UDP缓冲区溢出没有填充接收缓冲区?

时间:2013-05-08 11:16:04

标签: c sockets network-programming udp distributed

如果我寄1000“Hello World!” UDP消息(12字节+ 28 IP / UDP开销),我观察到在接收端我只有缓冲区658(总是相同的数字,658 * 40 = 26320字节)。我这样做,通过在服务器上休眠时发送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;
}

2 个答案:

答案 0 :(得分:4)

进行反向计算的信息更丰富 - 你的缓冲区是42080,它在开始丢弃之前缓冲658个数据包。现在42080/658 = 63.95,所以看起来它将每个数据包计为64字节并且如果到目前为止缓冲的数据包的总大小等于或高于限制,则丢弃数据包。由于它会缓冲整个数据包,因此实际上最终会缓冲超过限制。

为什么64字节而不是40字节?也许它包括一些排队开销,或者它可能会将对齐的一些2的幂的倍数或者两者的某种组合四舍五入。

答案 1 :(得分:1)

我没有完整的答案,但我在我的Linux机箱上测试了这个,这就是我观察到的。

当我发送一个&#34; Hello World!\ n&#34;终止&#39; 0&#39;。我明白了:

客户端:

$./sendto
sent 14 bytes

Socket&#34; Recv-Q&#34;有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

顺便提一下213504/768 = 278.通过快速实验,我无法弄清楚要调整的设置,以增加缓冲量。另外,我不知道为什么收到的数据包在这个队列中占用了这么多空间。可能有很多元数据?就像你在osX上一样,丢弃的数据包出现在netstat -su。

编辑:使用ss -ulm进行额外观察,打印&#34;套接字内存使用情况&#34;更详细:

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

缓冲的213504字节比rb值高512个字节。可能不是巧合,但需要阅读内核源代码才能找到答案。

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

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

有点矫枉过正,但我​​用这些(免责声明)随机调整缓冲区值可能会严重搞乱你的网络和内核):

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