为何我的UDP接收代码无法获取数据包?请求技术排查
问题分析
我编写了一段UDP接收代码,需要从IP为192.168.10.2的源端接收1000个大小为4094的数据包。通过Wireshark确认数据包已经到达我的主机(192.168.10.1),数据包的源端口为1234、目的端口为4321,但代码在recvfrom处挂起。请问以下代码片段是否存在使用错误?
int sockfd; char buffer[4094]; struct sockaddr_in servaddr, cliaddr; FILE* f = fopen("output.bin", "wb"); if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){ perror("error creating socket"); exit(EXIT_FAILURE); } memset(&servaddr, 0, sizeof(servaddr)); memset(&cliaddr, 0, sizeof(cliaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(4321); servaddr.sin_addr.s_addr = inet_addr("192.168.10.2"); bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)); int n; socklen_t len; for (int i=0; i<1000; i++){ len = sizeof(cliaddr); n = recvfrom(sockfd, (char *)buffer, 4094, MSG_WAITALL, (struct sockaddr *) &cliaddr, &len); if (n>0){ if (n<4094){ buffer[n] = '\0'; } fwrite(buffer, 1, n, f); } } fclose(f); close(sockfd);
错误点分析
Bind地址错误:你在
bind时将socket绑定到了源端IP(192.168.10.2),但你的主机IP是192.168.10.1。这会导致socket仅监听发送到192.168.10.2地址的数据包,到达你主机192.168.10.1的数据包会被直接忽略。正确做法是绑定到INADDR_ANY(允许接收发送到主机任何IP的数据包),或者明确绑定到你的主机IP:servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // 或者 servaddr.sin_addr.s_addr = inet_addr("192.168.10.1");MSG_WAITALL选项误用:
MSG_WAITALL是为TCP设计的选项,用于确保接收指定长度的流式数据。但UDP是基于数据包的协议,每个recvfrom调用只能接收一个完整的UDP数据包,使用MSG_WAITALL没有实际意义,反而可能引发异常行为,建议移除该选项:n = recvfrom(sockfd, (char *)buffer, 4094, 0, (struct sockaddr *) &cliaddr, &len);缺失错误处理:代码未处理
recvfrom返回-1的错误情况(比如socket异常),可能导致程序无限挂起或异常退出,建议添加错误处理逻辑,例如:n = recvfrom(sockfd, (char *)buffer, 4094, 0, (struct sockaddr *) &cliaddr, &len); if (n == -1) { perror("recvfrom failed"); fclose(f); close(sockfd); exit(EXIT_FAILURE); }
内容的提问来源于stack exchange,提问作者grumio
相关产品推荐
相关产品推荐

