2017-03-09 23 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)。不要將延遲添加到網絡代碼中。他們不解決問題:他們只是改變他們。

如果您有權訪問所有相關源代碼,則應該增加所有有關的套接字發送和接收緩衝區的大小。

相關問題