2013-05-08 195 views
1

如果我发送1000个“Hello World!” UDP消息(12字节+ 28 IP/UDP开销),我观察到在接收端我只缓冲658(总是相同的数字,658 * 40 = 26320字节)。我这样做,通过在服务器上睡眠时发送UDP消息(创建套接字之后)。没有填充接收缓冲区的UDP缓冲区溢出?

奇怪的是服务器上的SO_RCVBUF选项是42080字节。所以,我想知道为什么我不能缓冲1000条消息。你知道剩下的15760字节花在哪里吗?

下面的服务器代码(其中包含distrib.h的插座和信号处理功能,基本的错误处理包装):

#include "distrib.h" 

static int count; 
static void sigint_handler(int s) { 
    printf("\n%d UDP messages received\n",count); 
    exit(0); 
} 

int main(int argc, char **argv) 
{ 
    struct addrinfo* serverinfo; 
    struct addrinfo hints; 
    struct sockaddr_storage sender; 
    socklen_t len; 
    int listenfd,n; 
    char buf[MAXLINE+1]; 

    if (argc != 2) { 
    log_error("usage: %s <port>\n", argv[0]); 
    exit(1); 
    } 

    Signal(SIGINT,sigint_handler); 

    bzero(&hints,sizeof(hints)); 
    hints.ai_family = AF_INET;  
    hints.ai_socktype = SOCK_DGRAM; 
    hints.ai_protocol = IPPROTO_UDP; 
    Getaddrinfo("127.0.0.1", argv[1], &hints, &serverinfo); 

    listenfd = Socket(serverinfo->ai_family, serverinfo->ai_socktype, 
      serverinfo->ai_protocol); 
    Bind(listenfd, serverinfo->ai_addr,serverinfo->ai_addrlen); 
    freeaddrinfo(serverinfo); 

    count =0; 
    sleep(20); 
    while(true) { 
    bzero(buf,sizeof(buf)); 
    len = sizeof(sender); 
    n = Recvfrom(listenfd, buf, MAXLINE, 0, (struct sockaddr*)&sender,&len); 
    buf[n]='\0'; 
    count++; 

    } 

    close(listenfd); 

    return 0; 
} 
+0

MAXLINE的价值是什么? – thuovila 2013-05-08 11:34:30

+0

你确定所有邮件都已发送吗?服务器和客户端程序都在同一台计算机/网络上吗? – 2013-05-08 11:47:03

+0

如果你在Linux上,你是否检查_netstat -su_ [ref](http://stackoverflow.com/questions/10899937/udp-packet-drops-by-linux-kernel) – thuovila 2013-05-08 11:47:52

回答

4

这更多的信息做反向计算 - 你的缓冲区是42080,它在开始丢弃之前缓冲了658个数据包。现在42080/658 = 63.95,因此它看起来像是将每个数据包计为64个字节,并且如果目前缓冲的数据包的总大小等于或超过限制,则丢弃数据包。由于它缓冲了整个数据包,实际上它的缓冲区稍稍超过限制。

为什么64字节而不是40?也许它包含了一些排队开销,或者它可能是以2的倍数来对齐,或者也可能是两者的某种组合。

1

我没有一个完整的答案,但我测试了这个在我的Linux框和这是我观察到的。

当我发送一个“Hello World!\ n”结尾为'0'。我得到:

客户:

$./sendto 
sent 14 bytes 

插座 “的Recv-Q” 已经768个字节(似乎有可能它以字节为单位,没有检查SS源):

$ ss -ul|grep 55555 
UNCONN  768 0    127.0.0.1:55555     *:*  

当我送1000个包我得到:

$ ./sendto 
sent 14000 bytes 

的Recv-Q:

$ ss -ul|grep 55555 
UNCONN  213504 0    127.0.0.1:55555     *:*  

您的服务器(后CTRL-C):

$ ./recvfrom 55555 
^C 
278 UDP messages received 

顺便七百六十八分之二十一万三千五百零四= 278.快速实验的我想不出什么设置调整,以增加缓冲量。另外,我不知道为什么接收到的数据包在这个队列中占用这么多空间。许多元数据可能?在你的osX上,丢弃的数据包在netstat -su中显示。

编辑:

UNCONN  213504 0    127.0.0.1:55555     *:*  
skmem:(r213504,rb212992,t0,tb212992,f3584,w0,o0,bl0) 

缓冲的213504个字节是上面的RB值512个字节:与SS -ulm,打印 “插座存储器使用” 更详细的附加观察。可能不是巧合,但需要阅读内核源代码才能找到答案。

你是否检查过一个UDP数据报在osX上占用多少?

编辑2: 这仍然不是在OSX一个合适的答案,但在Linux上我发现,增加分配给内核内存接收缓冲区让我来缓冲发送的所有1000个数据包。

大材小用了一点,但我用这些(免责声明)随机调整的缓冲值可能会严重弄乱你的网络和内核):

net.core.rmem_max=1048568 
net.core.rmem_default=1048568