2013-03-08 81 views
0

我有一個在Windows XP平臺(i7 2.1 Ghz處理器)上運行的應用程序。此應用程序是通過UDP在主節點和從節點之間進行基於主/從的通信。 主站發送請求,從站節點在其響應(突發模式)中發送每5毫秒的數據包,每個數據包包括標頭1300字節。Winsock函數的執行時間太長

回到主節點,主線程接收數據並將其寫入隊列,觸發並行線程從線程讀出。

問題: 讀取下一個數據包時,Winsock API的執行時間很長,所以數據正在從緩衝區中丟失。

執行時間:Recvfrom() - 200 - 400微秒。

Open_Sock() 
{ 
    socket(); 
    //Error check 

    connect(); 
    //Error Check 
} 

Receivethread() 
{ 
    sock again: 

    select(socket, read,write,excep,(0,0)); 
    //error check 

    rc = recvfrom(socket,buf,len,0,&s_addr,&cln_alen) 
    if(rc>0) { 
     enqueue(queue,buf); 
    } 
} 

我確信Winsock API不需要很長時間才能獲取下一個數據包。 但我找不到任何有關真實執行時間的信息。任何方向的幫助真的很感激。

+1

使用IOCP,排隊大量緩衝區,讓內核填滿他們的。稍後處理它們。 – 2013-03-08 15:41:27

+0

能夠爲每個發送緩衝區調用recvfrom至少12.5次似乎應該足夠充分(5ms/400us = 12.5)。你確定你正在處理的數據很快就完成了嗎?另外,我們發現Windows傾向於丟棄比我們認爲的更多的UDP數據包。我們將一個客戶端/服務器Windows應用程序移植到Linux上,並使用相同的硬件丟棄了零個數據包。 – 2013-03-08 18:28:23

+0

默認情況下,套接字以阻塞模式運行,所以'recvfrom()'將在退出之前等待數據到達。既然你使用'select()',那麼在你調用'recvfrom()'之前,套接字是否處於可讀狀態呢?知道套接字處於阻塞模式,除非你的線程在等待數據時需要做其他線程,否則你也可以放棄select()。 – 2013-03-08 20:21:27

回答

0

您可能遇到了發送/接收緩衝區大小和OS調度程序問題的組合。在Windows線程之間的平臺上下文切換是不是太頻繁,所以有兩個選擇,你可以使用:

  1. 服務器進程的增加優先

    這將減少時間您的服務器應用程序留在隊列。

  2. 增加接收緩衝區大小

    你需要做的兩端。您可以使用setsockopt的SO_RCVBUF選項:

    int size = 1 * 1024 * 1024; 
    setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (const char*)&size, sizeof(int)); 
    
+0

謝謝你的建議。有用...!!!然而,不是從套接字讀取垃圾的新的失敗。 – 2013-03-13 15:05:56

+0

@Pipa然後打開一張新票:)並且不要忘記提供更多信息。 – 2013-03-13 16:05:38

0

如果丟失數據包是個問題,請使用TCP。使用TCP,對於簡單的環回連接,我在不太現代的機器上實現了小於1毫秒的響應時間。這裏有一些重要的點:

  • 當等待流量時,使用WSAEventSelect()和WaitForMultipleObjects()。我不確定這是否與select()相比有很大的不同,但是如果您想通過額外的事件停止線程,它會使處理更輕鬆。
  • 在等待輸入之前分配一個緩衝區,這樣會減少延遲。
  • 嘗試不爲每個數據包創建一個線程,但已經有線程等待,即使用線程池。
  • 嘗試發送儘可能少的數據包,即嘗試將整個數據組合在內存中並通過一次調用發送。這可避免稍後彙編的多個數據包的網絡IO開銷。
  • 另請參閱Nagle算法,您可能需要關閉TCP。 Nagle算法結合延遲確認可嚴重影響您的延遲。
+0

我不能切換到TCP,因爲從站只能通過UDP進行通信。 而使用等待增加了延遲,我需要加速從緩衝區讀取,因爲奴隸處於突發模式。而且我無法控制從節點的觸發,因爲它是一個在ECU(從站)上運行的汽車應用。 – 2013-03-09 09:03:40