我开发了一个 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/