2017-03-09 271 views
0

我正在用C++编程UDP中继服务器。但我有一个问题。C++,UDP,sendto需要延时才能工作

我有一个基本的循环,只是调用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); 
} 

任何想法?

+1

失去了如何?你使用数据包嗅探器来观看UDP流量吗?你不应该需要任何延迟。请提供一个[最小化,完整和可验证的示例](/ help/mcve),以演示问题的实际应用。 –

回答

0

任何想法?

由于缓冲区在某处溢出,很可能您的传出UDP数据包被丢弃。它最有可能溢出的地方在你的套接字自己的传出数据缓冲区中;如果是这样,通过调用setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, ...)可以使您的套接字的传出缓冲区大小更大(即,可以一次发送通过sendto()调用传递的所有数据包)来减少丢弃数据包的数量, 。

如果这还不足以解决问题,那么您可以做的下一件事是实现您自己的应用程序内缓冲;即,不是只是立即调用sendto(),而是将分组数据推送到FIFO数据结构的尾部,然后在套接字select()的准备好写入时才调用sendto()弹出FIFO头部的下一个数据包,并用此命令调用sendto())。这样你总是只能以socket的缓冲区可以接受的速度发送数据,而不是假设套接字的缓冲区总是足够大,以便立即接受你投入的所有内容。

(其中一个缓冲区可能溢出其他地方是在接收应用程序的套接字的接收缓冲区,在这种情况下,接收应用程序的插座上setsockopt(s, SOL_SOCKET, SO_RCVBUF, ...)通话也可能有助于)

+0

select()并设置发送缓冲区更大的问题<3感谢很多 –

0

目标进程不读取速度足够快,因此数据报因为其套接字接收缓冲区已满而被丢弃。接下来的问题是什么正确的缓解是:

  1. (如果可以的话)加快接收器。
  2. 在您的循环中添加延迟。这只会将问题向下游移动到向您发送这些数据报的人员。当您的套接字接收器缓冲区已满时,入站到您的数据报将被丢弃。
  3. 什么都不做。这不是你的问题;你的代码是正确的。

我推荐(1)如果可能的话,和(3)。不要将延迟添加到网络代码中。他们不解决问题:他们只是改变他们。

如果您有权访问所有相关源代码,则应该增加所有有关的套接字发送和接收缓冲区的大小。

相关问题