UDP连接后发送行为()

#include <stdio.h> #include <errno.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main() { struct sockaddr_in addr; int fd, cnt,ret; char ch = 'y',msg[] ="How are you"; if ((fd=socket(AF_INET,SOCK_DGRAM,0)) < 0) { printf("Error: socket"); exit(1); } printf("\nDone socket\n"); /* set up destination address */ memset(&addr,0,sizeof(addr)); addr.sin_family=AF_INET; addr.sin_addr.s_addr=inet_addr("128.88.143.113"); addr.sin_port=htons(9090); ret=connect(fd,(struct sockaddr *)&addr,sizeof(addr)); perror("Connect:"); while(ch == 'y'){ cnt = send(fd,msg,sizeof(msg),0); if(cnt < 0) perror("send:"); printf("\nNumber of bytes sent = %d , \n",cnt); printf("Continue (y/n)\n"); scanf(" %c",&ch); } return 0; } 

上面的代码被编译为在Linux机器上运行。

假设上述代码将数据发送到IP地址为128.88.143.113 。 没有UDP套接字绑定到端口9090128.88.143.113

while循环中, send()的第一个调用成功(数据包实际上出去了;使用trace检查),第二个send()失败, Connection refusedthird send()成功, third send()失败,依此类推。

我怀疑,在第一次send() ,堆栈收到一个ICMP错误信息(在Linux机器上的tcpdump看到)保存在套接字结构中。 第二个send()在看到这个错误后失败,实际上没有数据包被发送出去。 第二个send()也清除了套接字结构中的错误。 所以第三次send()成功,第四次失败等等。

问题:

  1. 这个假设是否正确?
  2. 应该是什么正确的行为? 有没有任何RFC标准定义这样的行为?
  3. 由于UDP不保持任何连接状态,不应该每个send()成功?

Solutions Collecting From Web of "UDP连接后发送行为()"

根据udp的linux手册页 :

所有致命错误将作为错误返回传递给用户,即使套接字未连接。 这包括从网络收到的异步错误。 对于在同一套接字上发送的较早数据包,您可能会遇到错误。 这种行为不同于许多其他BSD套接字实现,除非套接字连接,否则不会传递任何错误。 Linux的行为是由RFC 1122强制的。

RFC (4.1.3.3)特别指出:

UDP必须将从IP层收到的所有ICMP错误消息传递给应用层。 至少在概念上,这可以通过对ERROR_REPORT例程的上调来完成

你的假设是正确的。 Linux udp(7)手册页描述了这种情况:

所有致命错误将作为错误返回传递给用户,即使套接字未连接。 这包括从网络收到的异步错误。 对于在同一套接字上发送的较早数据包,您可能会遇到错误。
这种行为不同于许多其他BSD套接字实现,除非套接字连接,否则不会传递任何错误。 Linux的行为是由RFC 1122强制的。

当启用IP_RECVERR选项时,所有错误都将存储在套接字错误队列中,并且可以通过设置了MSG_ERRQUEUE标志的recvmsg(2)来接收。

比较使用sendto()而不是connect()send()的等效代码会很有趣。

如果您在每次发送之间留出一段时间,也就是说ICMP错误状态在套接字中保留一段时间,那么显示的代码是否会以相同的方式失败,或者如果您离开比如说一个小时?

我期望你的假设是正确的,网络堆栈正在努力变得聪明。 当connect()调用发出时,没有任何东西被发送,它只能存储给定的地址,使得套接字“逻辑上”连接,然后调用send()就可以工作。

从另一端开始,如果你连接一个UDP套接字,你可以在下一次发送时收集错误。 如果你不想要,不要连接!

我有同样的问题; 这是由于如果没有人正在监听和清空队列,udp消息队列被填满。