UDP套接口编程

常用的UDP实现的程序:DNS域名系统,NFS网络文件系统,SNMP简单网络管理协议

ssize_t recvfrom(int sockfd,void *buff,size_t nbytes,int flags,struct sockaddr * from,socklen_t *addrlen);

ssize_t sendto(int sockfd,void *buff,size_t nbytes,int flags,struct sockaddr * to,socklen_t addrlen);
sockfd:描述字
buff:缓冲区指针
nbytes 读写字节数
 
 UDP服务器端
int main(int argc,char ** argv){

int sockfd;

struct sockaddr_in servaddr,cliaddr;

sockfd = Socket(AF_INET,SOCK_DGRAM,0);

bzero(&servaddr,sizeof(servaddr));

servaddr.sin_family = AF_INET;

servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

servaddr.sin_port = htons(SERV_PORT);

Bind(sockfd,(SA *)&servaddr,sizeof(servaddr));

dg_echo(sockfd,(SA *)&cliaddr,sizeof(cliaddr));

}

 

void dg_echo(int sockfd,SA *pcliaddr,socklen_t clilen){

int n;

socklen_t len;

char mesg[MAXLINE];

for(;;){

    len = clilen;

    n = Recvfrom(sockfd,mesg,MAXLINE,0,pcliaddr,&len); //读一个到达的数据包

    Sendto(sockfd,mesg,n,0,pcliaddr,len); //发送回给客户机

}

}
SOCK_DGRAM:UDP套接口
 
1 函数不能终止
2 服务器是迭代服务器,没有fork调用,单一服务器进程处理所有客户。
 
 
UDP客户机程序:
int main(int argc,char ** argv){

int sockfd;

struct sockaddr_t servaddr;

if(argc != 2)

    err_quit("usage:udpcli<IPaddress>");

bzero(&servaddr,sizeof(servaddr));

servaddr.sin_family = AF_INET;

servaddr.sin_port = htons(SERV_PORT);

inet_pton(AF_INET,argv[1],&servaddr,sin_addr); //装填套接字

sockfd = Socket(AF_INET,SOCK_DGRAM,0);

dg_cli(stdin,sockfd,(SA *)&servaddr,sizeof(servaddr));

exit(0);

}

void dg_cli(FILE *fp,int sockfd,const SA *pservaddr,socklen_t servlen){

int n;

char sendline[MAXLINE],recvline[MAXLINE+1];

while(Fgets(sendline,MAXLINE,fp) != NULL){ //从标准输入读一行

    Sendto(sockfd,sendline,strlen(sendline),0,pservaddr,servlen); //使用sendto发送给服务器

    n = Recvfrom(sockfd,recvline,MAXLINE,0,NULL,NULL); //使用recvfrom接收服务器回射,NULL无视目标主机

    recvline[n] = 0; 

    Fputs(recvline,stdout); //fputs输出回射行到标准输出

}

}

 

改进的dg_cli
void dg_cli(FILE *fp,int sockfd,const SA * pservaddr,socklen_t servlen){

int n;

char sendline[MAXLINE],recvline[MAXLINE+1];

socklen_t len;

struct sockaddr *preply_addr;

preply_addr = Malloc(servlen);

while(Fgets(sendline,MAXLINE,fp)!= NULL ){

    Sendto(sockfd,sendline,strlen(sendline),0,pservaddr,servlen);

    len = servlen;

    n = Recvfrom(sockfd,recvline,MAXLINE,0,preply_addr,&len);

    if(len != servlen || memcpy(pservaddr,preply_addr,len) != 0){

        printf("reply from %s (ignored)\n");

                    Sock_ntop(preply_addr,len);

        continue;

    }

    recvline[n] = 0;

    Fputs(recvline,stdout);

}

}

 

解决办法:
1 给定由recvfrom返回的IP,在DNS中查找服务器验证
2 服务器配置每个IP地址创建套接口,捆绑IP地址此套接口,
 
 
仅在进程已将UDP套接口连接到确切的对方后,这些一步错误才返回给进程。
 
已连接的UDP套接口上调用connect达到下面两个目的:
1 指定IP地址和端口号
2 断开套接口
 
使用connect连接后再调用read write
void dg_cli(FILE *fp,int sockfd,const SA * pservaddr,socklen_t servlen){

    int n;

    char sendline[MAXLINE],recvline[MAXLINE+1];

    Connect(sockfd,(SA *)pservaddr,servlen);

    while(Fgets(sendline,MAXLINE,fp)!= NULL){

        Write(sockfd,sendline,strlen(sendline));

        n=Read(sockfd,recvline,MAXLINE);

        recvline[n] = 0;

        Fputs(recvline,stdout);

    }

}

 

对发送的UDP进行统计:
static void recvfrom_int(int);

static int count;

void dg_echo(int sockfd,SA *pcliaddr,socklen_t clilen){

    socklen_t len;

    char mesg[MAXLINE];

    Signal(SIGINT,recvfrom_int);

    for(;;){

        len = clilen;

        Recvfrom(sockfd,mesg,MAXLINE,0,pcliaddr,&len);

 

        count++;

    }

}

static void recvfrom_int(int signo){

    printf("\nreceived %d datagrams\n",count);

    exit(0);

}

 

 
UDP与TCP的服务器复用:
int main(int argc,char ** argv){

int listenfd,connfd,updfd,nready,maxfdp1;

char mesg[MAXLINE];

pid_t childpid;

fd_set rset;

ssize_t n;

socklen_t len;

const int on = 1;

struct sockaddr_in cliaddr,servaddr;

void sig_child(int);

 

listenfd = Socket(AF_INET,SOCKSTREAM,0);

bzero(&servaddr,sizeof(servaddr));

servaddr.sin_family=AF_INET;

servaddr.sin_addr.s_add=htonl(INADDR_ANY);

servaddr.sin_port=htons(SERV_PORT);

Setsockopt(listenfd,SOL_SOCKET,SO_RESSEADDR,&on,sizeof(on));

Bind(listenfd,(SA *)&servaddr,sizeof(servaddr));

Listen(listenfd,LISTENQ);

 

updfd=Socket(AF_INET,SOCK_DGRAM,0);

bzero(&servaddr,sizeof(servaddr));

servaddr.sin_family=AF_INET;

servaddr.sin_addr.s_addr=htonl(INADDR_ANY);

servaddr.sin_port=htons(SERV_PORT);

Bind(udpfd,(SA *)&servaddr,sizeof(servaddr));

 

Signal(SIGCHLD,sig_chld);

FD_ZERO(&rset);

maxfdp1=max(listenfd,udpfd)+1;

for(;;){

    FD_SET(listenfd,&rset);

    FD_SET(udpfd,&rset);

    if((nready=select(maxfdp1,&rset,NULL,NULL,NULL,NULL))<0){

        if(errno==EINTR)

            continue;

        else

            err_sys("select error");

    }

    if(FD_ISSET(listenfd,&rset)){

        len = sizeof(cliaddr);

        connfd=Accept(listenfd,(SA *)&cliaddr,&len);

        if((childpid=Fork())==0){

            Close(listenfd);

            str_echo(connfd);

            exit(0);

        }

        Close(connfd);

    }

    if(FD_ISSET(udpfd,&rset)){

        len=sizeof(cliaddr);

        n=Recvfrom(udpfd,mesg,MAXLINE,0,(SA *)&cliaddr,&len);

        Sendto(udpfd,mesg,n,0,(SA *)&cliaddr,len);

    }

}

}

 

你可能感兴趣的:(UDP)