UNIX网络编程:UDP回射服务器程序(初级版本)及漏洞分析
客户端程序: #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #define SERV_PORT 3333 #define MAXLINE 1024 #define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); } while(0) typedef struct sockaddr SA; 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); n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL); recvline[n] = 0; /* null terminate */ fputs(recvline, stdout); } } int main(int argc, char **argv) { int sockfd; struct sockaddr_in servaddr; if (argc != 2) ERR_EXIT("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); } 1.数据报的丢失 我们的UDP客户/服务器例子是不可靠的。如果一个客户数据报丢失(譬如说,被客户主机与服务器主机之间的某个路由器丢失),客户将永远阻塞于dg_cli函数中的recvfrom调用,等待一个永远不会达到的服务器应答。类似的,如果客户数据报到达服务器,但是服务器的应答丢失了,客户也将永远阻塞于recvfrom调用。防止这样永远阻塞的一般方法是给客户的recvfrom调用设置一个超时。 仅仅给recvfrom调用设置超时并不是完整的解决办法。举例来说,如果确实超时了,我们将无从判定超时原因是我们的数据报没有到达服务器,还是服务器的应答没有回到客户。所以我们可以增加UDP客户/服务器程序的可靠性。(后面会有讲解) 2.服务器进程未运行 我们下一个要检查的情形是在不启动服务器的前提下启动客户。如果我们这么做后在客户上键入一行文本,那么什么也不发生。客户永远阻塞于它的recvfrom调用,等待一个永远不出现的服务器应答。 经过抓包分析,服务器主机响应的是一个“port unreachable”(端口不可达)ICMP消息。不过这个ICMP错误不返回给客户进程。我们称这个ICMP错误为异步错误。该错误由sendto引起,但是sendto本身却成功返回。我们知道从UDP输出操作成功返回仅仅表示在输出队列中具有存放所形成IP数据报的空间。该ICMP错误直到后来才返回,这就是称其为异步的原因。 一个基本规则是:对于一个UDP套接字,由它引发的异步错误却并不返回给它,除非它已连接。仅在进程已将其UDP套接字连接到恰恰一个对端后,这些异步错误才返回给进程。 注:只要SO_BSDCOMPAT 套接字选项没有开启,linux甚至对未连接的套接字也返回大多数ICMP(目的地不可达)错误。 查看本栏目更多精彩内容:http://www.bianceng.cn/OS/unix/ (编辑:云计算网_泰州站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |