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

标签 c linux network-programming

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

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

现在我记录了 sendto() 函数发送数据包的时间,我还记录了数据包应该发送的时间和实际发送时间之间的差异。

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

这表明是 sendto() 导致每次发送数据包以某种方式花费更长的时间时出现这些延迟。我正在使用 UDP 套接字。

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

因为这是为了流式传输视频,所以我非常依赖于性能,主要是高清,因为数据包的数量要多得多,延迟发生得更频繁。

最佳答案

sendto() 阻塞的原因只有两个:

  • 您的传出 UDP 缓冲区已满,需要等待空间释放
  • CPU 调度程序只是决定暂时做其他事情,就像它可以处理任何系统调用一样。

检查传出缓冲区的大小:

int buff_size;
int len = sizeof(buff_size);

err = getsockopt(s,SOL_SOCKET,SO_SNDBUF,(char*)&size,&len);

某些 linux 系统默认发送缓冲区小得离谱(只有几千字节),因此您可能需要将其设置为更大的值。

如果缓冲区更大并且 sendto() 无论如何都会短暂阻塞(到底多长时间?)那么这可能只是做生意的成本。即使在 LAN 上,当然在 WAN 上,延迟也会有很大差异。

更新

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

sysctl -w net.core.wmem_max=1048576
sysctl -w net.core.rmem_max=1048576

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

net.core.wmem_max=1048576
net.core.rmem_max=1048576

要在您的应用程序中利用这一点,您需要使用 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);

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

关于c - 通过 UDP 套接字发送缓冲区时,延迟有时会增加,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9409306/

相关文章:

c++ - 使用 TCP 套接字设置目标端口

c - 在同一进程中多次加载共享库的地址空间

java - 无法从 Java 中的 COM 端口读取串行数据

C 忽略一些行,然后打印其余行

linux - 过滤两个多列的大文件

linux - 编译curl后的路径问题

python - 使用 basemap 在世界地图上绘制网络/图形(python)

c - 如何在C中接收多个UDP数据包?

无法使用for循环在C中打印数组

c - C 库最初如何读取语言环境文件