第二十二篇:基于UDP的一对回射客户/服务器程序
前言
之前曾经学习过一对回射客户/服务器程序的例子,不过那个是基于TCP协议的。本文将讲解另一对回射客户/服务器程序,该程序基于UDP协议。
由于使用的协议不同,因此编写出的程序也有本质上的区别,应将它们对比来进行理解。
通信框架
服务器端
1 #include "unp.h" 2 3 int 4 main(int argc, char **argv) 5 { 6 int sockfd; 7 struct sockaddr_in servaddr, cliaddr; 8 9 // 创建UDP套接字 10 sockfd = Socket(AF_INET, SOCK_DGRAM, 0); 11 12 bzero(&servaddr, sizeof(servaddr)); 13 servaddr.sin_family = AF_INET; 14 servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 15 servaddr.sin_port = htons(SERV_PORT); 16 17 Bind(sockfd, (SA *) &servaddr, sizeof(servaddr)); 18 19 dg_echo(sockfd, (SA *) &cliaddr, sizeof(cliaddr)); 20 }
1 #include "unp.h" 2 3 void 4 dg_echo(int sockfd, SA *pcliaddr, socklen_t clilen) 5 { 6 int n; 7 socklen_t len; 8 char mesg[MAXLINE]; 9 10 for ( ; ; ) { 11 len = clilen; 12 // 接收数据 13 n = Recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len); 14 15 // 回射数据 16 Sendto(sockfd, mesg, n, 0, pcliaddr, len); 17 } 18 }
客户端
1 #include "unp.h" 2 3 int 4 main(int argc, char **argv) 5 { 6 int sockfd; 7 struct sockaddr_in servaddr; 8 9 if (argc != 2) 10 err_quit("usage: udpcli <IPaddress>"); 11 12 bzero(&servaddr, sizeof(servaddr)); 13 servaddr.sin_family = AF_INET; 14 servaddr.sin_port = htons(SERV_PORT); 15 Inet_pton(AF_INET, argv[1], &servaddr.sin_addr); 16 17 // 创建UDP套接字 18 sockfd = Socket(AF_INET, SOCK_DGRAM, 0); 19 20 dg_cli(stdin, sockfd, (SA *) &servaddr, sizeof(servaddr)); 21 22 exit(0); 23 }
1 #include "unp.h" 2 3 void 4 dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen) 5 { 6 int n; 7 char sendline[MAXLINE], recvline[MAXLINE + 1]; 8 socklen_t len; 9 struct sockaddr *preply_addr; 10 11 preply_addr = Malloc(servlen); 12 13 while (Fgets(sendline, MAXLINE, fp) != NULL) { 14 15 // 往服务器发送数据 16 Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen); 17 18 len = servlen; 19 n = Recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr, &len); 20 // 不接收非指定服务器的数据 21 if (len != servlen || memcmp(pservaddr, preply_addr, len) != 0) { 22 printf("reply from %s (ignored)\n", 23 Sock_ntop(preply_addr, len)); 24 continue; 25 } 26 27 // 将回射结果打印给用户 28 recvline[n] = 0; /* null terminate */ 29 Fputs(recvline, stdout); 30 } 31 }
小结
1. UDP的机制比起TCP来说,简单多了。但也因此缺少了重传机制,验证相应是否来自对端等等可靠性相关的性质。
2. 只有被 connect 后的UDP套接字才能收到异常信息。