2010-12-09 40 views
8
#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机器上运行。连接后的UDP发送行为()

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

while循环,以send()第一个呼叫成功(文实际熄灭在电线上;它使用trace选中)和第二send()失败Connection refusedthird send()成功,第四次失败等。

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

问题:

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

通过别名界面发送时,我在arch linux机器上看到了类似的行为。这解决了吗? – 2011-12-20 10:10:56

回答

1

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

2

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

如果您在每次发送之间留出一段时间(即,ICMP错误状态在套接字中保留一段时间,或者如果在第二个时间段内仍然失败,则显示的代码是否以相同方式失败if你离开了,比如说,一个小时?

我认为你的假设是正确的,网络堆栈试图变得聪明。有没有其他的一点,当它可以返回'连接被拒绝',因为当发出connect()调用时不发送任何内容,它只是存储给定的地址,以便套接字'逻辑'连接,然后send()的调用就可以工作。

5

按照linux man page for udp

所有致命错误,将被传递给用户 作为即使不连接 插座一个错误的回报。这包括 网络收到的异步错误。您可能会在 相同的套接字上发送一个 较早的数据包时发生错误。此行为与许多其他BSD套接字 实现不同 不同,除非套接字已连接,否则它们不会传递任何 错误。 Linux的行为由RFC 1122强制执行。

具体的RFC(4.1.3.3)规定:

UDP必须传递给应用程序层中的所有ICMP错误,它从IP层接收 消息。从概念上讲 至少,这可以与上调,对 ERROR_REPORT常规

3

你的假设是正确的完成。 Linux的UDP(7)手册页描述了这样的情况:

所有致命错误,将被传递 给用户一个错误返回即使 时未连接插座。这包括从网络接收的异步错误 。您可能在 上收到了在同一个套接字上发送的早期数据包 的错误。
此行为不同于许多其他 BSD套接字实现不 传递任何错误,除非插座连接 。 Linux的行为是由RFC 1122授权的 。

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

0

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