通过UDP套接字发送缓冲区时,延迟有时会增加

gek*_*kod 3 c linux network-programming

我开发了MPEG-ts Streamer.它从文件中读取数据包,并以正确的速度将它们发送到接收器.

现在一切正常,除了我经常有一些滞后.我在我的代码中搜索了每个可能的错误.我已经优化了我的程序性能.

现在我保留一个日志,其中包含sendto()发送数据包所需的时间,我还记录了数据包发送时间和发送时间之间的差异.

我注意到,每次数据包比平均时间晚很多时sendto(),发送前一个数据包所花费的时间也远远高于正常数据包.

这表明我sendto()每次以某种方式发送数据包时都会导致这些滞后.我正在使用UDP套接字.

我可能在插座上做错了吗?套接字缓冲区是否可能已满并且实际上需要更长时间才能发送数据包?或者我错过了什么?有没有办法在发送之前加速套接字或使其不完全填充缓冲区?

由于这是用于流式传输视频,因此我非常依赖于性能,主要用于HD,因为数据包的数量要高得多,因此滞后更常发生.

Set*_*ble 6

sendto()阻止只有两个原因:

  • 您的传出UDP缓冲区已满,需要等待空间释放
  • CPU调度程序决定暂时执行其他操作,就像任何系统调用一样.

检查传出缓冲区的大小:

int buff_size;
int len = sizeof(buff_size);

err = getsockopt(s,SOL_SOCKET,SO_SNDBUF,(char*)&size,&len);
Run Code Online (Sandbox Code Playgroud)

一些Linux系统默认为荒谬的小发送缓冲区(只有几千字节),因此您可能需要将其设置为更大的值.

如果缓冲区较大并且sendto()无论如何都会暂时阻塞(确切地说多长时间?)那么这可能只是开展业务的成本.即使在局域网上,当然在广域网上,延迟也会发生很大变化.

更新

要增加UDP缓冲区大小的系统限制:

sysctl -w net.core.wmem_max=1048576
sysctl -w net.core.rmem_max=1048576
Run Code Online (Sandbox Code Playgroud)

您可以通过添加以下行来使其永久化/etc/sysctl.conf:

net.core.wmem_max=1048576
net.core.rmem_max=1048576
Run Code Online (Sandbox Code Playgroud)

要在您的应用程序中利用此功能,您需要使用setsockopt():

int len, trysize, gotsize;
len = sizeof(int);
trysize = 1048576+32768;
do {
   trysize -= 32768;
   setsockopt(s,SOL_SOCKET,SO_SNDBUF,(char*)&trysize,len);
   err = getsockopt(s,SOL_SOCKET,SO_SNDBUF,(char*)&gotsize,&len);
   if (err < 0) { perror("getsockopt"); break; }
} while (gotsize < trysize);
printf("Size set to %d\n",gotsize);
Run Code Online (Sandbox Code Playgroud)

重复同样的事情SO_RCVBUF.循环非常重要,因为许多系统默默地强制执行最大值,该最大值小于您设置的最大值sysctl,当setsockopt()失败时,它会保持先前的值不变.所以你必须尝试许多不同的值,直到你得到一个坚持.同样重要的是不进行测试,(gotsize == trysize)因为在某些系统上,设置的结果实际上与您请求的结果不同.