C ++,UDP,sendto需要延迟才能工作

时间:2017-03-09 18:06:15

标签: c++ sockets udp delay sendto

我正在用C ++编写UDP中继服务器。但我有一个问题。

我有一个只调用recvfrom()的基本循环,检查数据包中的错误,然后读取数据包中的“目标”并在同一个套接字上使用sendto()发送数据包到目标客户端也在同一服务器上进行中继。

问题是如果我在sendto()之前没有添加延迟,几乎所有的数据包都会丢失(这个延迟取决于连接速度,因此我无法静态设置)。

m_iSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
bind(m_iSocket, (SOCKADDR*)&m_oSockAddress, sizeof(SOCKADDR_IN));
...
while(true) {
    recvfrom(m_iSocket, (char*)m_pRecvBuffer, m_nBufferSize, 0, (SOCKADDR*)&remoteAddr, &remoteAddrLen);
    ...
    sendto(m_iSocket, reinterpret_cast<char*>(rw.getData()), rw.getBufferSize(), 0, targets address , address size);
}

有什么想法吗?

2 个答案:

答案 0 :(得分:0)

  

有什么想法吗?

您的传出UDP数据包很可能会被丢弃,因为缓冲区在某处溢出。它最容易溢出的地方是你的socket的输出数据缓冲区;如果是这样,您可以通过调用setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, ...)来减少丢弃的数据包的数量,以使您的套接字的传出缓冲区大小更大(即大到足以发送保存您通过的所有数据包) sendto()一次调用。)

如果这还不足以解决问题,那么您接下来要做的就是实现自己的应用程序内缓冲;即不是只是立即调用sendto(),而是将数据包数据推送到FIFO数据结构的尾部,然后只在套接字select()作为准备写入时调用sendto()(当如果发生这种情况,请从FIFO的头部弹出下一个数据包,然后用它调用sendto()。这样,你总是只能以套接字缓冲区可以接受的速度发送数据,而不是假设套接字的缓冲区总是足够大,可以立即接受你抛出的所有东西。< / p>

(缓冲区可能溢出的另一个地方是接收应用程序套接字的接收缓冲区,在这种情况下,在接收应用程序上调用setsockopt(s, SOL_SOCKET, SO_RCVBUF, ...)套接字也可能有帮助)

答案 1 :(得分:0)

目标进程读取速度不够快,因此数据报被删除,因为它的套接字接收缓冲区已满。那么问题就出现了正确的缓解措施:

  1. (如果可以的话)加速接收器。
  2. 在循环中添加延迟。这只会将问题向下游移动到向您发送这些数据报的任何人。当套接字接收缓冲区已满时,将丢弃入站的数据报。
  3. 什么都不做。这不是你的问题;你的代码是正确的。
  4. 如果可能,我建议(1)和(3)。不要在网络代码中添加延迟。他们没有解决问题:他们只会改变它们。

    如果您可以访问所有相关的源代码,则应增加所有相关插槽发送和接收缓冲区的大小。