2011-10-31 35 views
1

我能夠通過套接字編程成功地發送一個靜態類,對於少量數據工作正常,但在生產環境中,它凍結了一段時間,又一次開始發送數據,我無法弄清楚什麼問題是什麼?你能幫忙嗎?代碼如下。在Windows中的套接字編程發送數據凍結了一段時間,並延遲了一段時間?

  DWORD BytesCount; 
    WSABUF Buffer[1]; 
    DWORD Flag = 0; 

    Buffer[0].len = SendLength; 
    Buffer[0].buf = SendData; 
    if (WSASend(*socket, Buffer, 1, &BytesCount, Flag, NULL, NULL) != SOCKET_ERROR) 
    { 
     if (BytesCount != SendLength) 
      Result = -2; 
     else 
     { 
      if (ReturnAnswer) 
      { 
       int Res = 0, recBufStart; 
       DWORD RecvCount = 0, AllRecv = 0; 

       Buffer[0].len = ReceiveLength; 
       Buffer[0].buf = ReceiveData; 
       recBufStart = 0; 
       saAction = saReceive; 

       // We need to Receive until we get all the data. When WSARecv call might only return zero bytes 
       bool Stop = true; // true as we dont need to recieve anything from the server. 
       while (!Stop) 
       { 
        Res = WSARecv(*socket, &Buffer[recBufStart], (recBufStart == 0 ? 1 : 0), &RecvCount, &Flag, NULL, NULL); 
        if (Res == SOCKET_ERROR) 
         Stop = true; 
        else 
        { 
         AllRecv = AllRecv + RecvCount; 
         if (AllRecv == ReceiveLength || RecvCount == 0) 
          Stop = true; // Stop 
         else 
         { 
          Buffer[0].buf = &ReceiveData[AllRecv]; 
          Buffer[0].len = ReceiveLength - (AllRecv); 
          recBufStart = 0; 
         } 
        } 
       } 

       if (Res == SOCKET_ERROR) 
        Result = WSAGetLastError();     
      } 
     } 
    } 
    else 
     Result = WSAGetLastError();  
+0

「WSASend」還是「WSARecv」凍結了? –

+0

我正在使用WSASend,至於時間我沒有收到任何東西,你可以看到布爾值設置爲true。 – Ershad

回答

1

我不知道是否這可能是問題,但從WSASend Microsoft文檔有以下幾點:

當發出阻塞Winsock調用,如WSASend與lpOverlapped參數集爲NULL,Winsock可能需要等待網絡事件才能完成通話。

此外,您的接收代碼似乎相當複雜。在什麼情況下,recBufStart將不是0?我也不會使用變量「停止」。只需發出break語句即可退出while循環。

編輯:更仔細地看一下你的接收代碼,你在while(!Stop)之前設置Stop爲true,即while(Stop == false)。所以它不會去WSARecv。這是故意的嗎?如果是這樣,微軟的解釋和下面的答案似乎表明你的問題,即你不斷髮送和Winsock必須等待,才能發送更多的數據。

+0

好的,故意我現在沒有收到任何數據,問題你說的話似乎是正確的,那麼爲避免這種情況需要做些什麼呢?我在創建套接字時使用select,並在超時錯誤之間進入。 – Ershad

+0

我還沒有看到只發送數據而沒有收到的代碼。我認爲您需要從發送給您的對等點獲得某些回報,並且此時您可能會獲得解除WSASend的網絡事件。只是爲了測試簡單地做一個WSASend後跟一個WSARecv。使用Berkeley套接字接口而不是Microsoft接口可能更容易,以避免所有這些重疊的I/O內容,即發送而不是WSASend,套接字,而不是WSASocket和recv,而不是WSARecv。 – rushman

0

您正在使用WSASend並且WSARecv處於阻塞模式(最後兩個參數爲NULL)。這意味着,只要填充了TCP/IP堆棧緩衝區,下一次對WSASend的調用就會阻塞,直到緩衝區中再次出現空間(即數據已發出)。

您最好使用異步調用和I/O completion ports

+0

我正在使用這個並且超時,這是否會導致問題。代碼如下。如果(選擇(0,NULL,&ConnectSockets,NULL,&超時)== SOCKET_ERROR) \t { \t \t LogToEventLog(EVENTLOG_WARNING_TYPE,EVENTID_WINSOCK_ERROR,_T( 「主服務器連接失敗 - 與誤差%ld的一個選擇呼叫」),WSAGetLastError( )); \t \t Close(SocketPrimary,TRUE); \t \t return false; \t} \t其他 \t { \t \t如果(ConnectSockets.fd_count == 0) \t \t { \t \t \t LogToEventLog(EVENTLOG_WARNING_TYPE,EVENTID_WINSOCK_ERROR,_T( 「主服務器連接失敗 - 已逾時連接...」 )); \t \t \t Close(SocketPrimary,TRUE); \t \t \t return false; \t \t} \t} – Ershad

0

如果應用程序發送的數據塊大於套接字的發送緩衝區大小,TCP堆棧可能會阻塞應用程序。

嘗試增加您的套接字的SO_SNDBUF選項。如果你想避免阻塞,它的值應大於bigest SendLength的值。 使用setsockopt()功能來改變SO_SNDBUF的值。