2009-09-02 125 views
0

我在Windows套接字中使用WSAEventSelect I/O模型,現在我想知道如何知道我的發送和接收操作已發送和接收所有數據?Winsocks發送和接收

我知道之後,我應該如何設計一種方式,使其完全發送數據?任何例子將非常感激。

這裏是代碼(從書我是從學習樣本代碼):

SOCKET SocketArray [WSA_MAXIMUM_WAIT_EVENTS]; 
WSAEVENT EventArray [WSA_MAXIMUM_WAIT_EVENTS], 
NewEvent; 
SOCKADDR_IN InternetAddr; 
SOCKET Accept, Listen; 
DWORD EventTotal = 0; 
DWORD Index, i; 
WSANETWORKEVENTS NetworkEvents; 


// Set up socket for listening etc... 
// .... 

NewEvent = WSACreateEvent(); 

WSAEventSelect(Listen, NewEvent, 
       FD_ACCEPT │ FD_CLOSE); 

listen(Listen, 5); 

SocketArray[EventTotal] = Listen; 
EventArray[EventTotal] = NewEvent; 
EventTotal++; 

while(TRUE) 
{ 
    // Wait for network events on all sockets 
    Index = WSAWaitForMultipleEvents(EventTotal, 
     EventArray, FALSE, WSA_INFINITE, FALSE); 
    Index = Index - WSA_WAIT_EVENT_0; 

    // Iterate through all events to see if more than one is signaled 
    for(i=Index; i < EventTotal ;i++ 
    { 
     Index = WSAWaitForMultipleEvents(1, &EventArray[i], TRUE, 1000, 
      FALSE); 
     if ((Index == WSA_WAIT_FAILED) ││ (Index == WSA_WAIT_TIMEOUT)) 
      continue; 
     else 
     { 
      Index = i; 
      WSAEnumNetworkEvents(
       SocketArray[Index], 
       EventArray[Index], 
       &NetworkEvents); 

      // Check for FD_ACCEPT messages  
      if (NetworkEvents.lNetworkEvents & FD_ACCEPT) 
      { 
       if (NetworkEvents.iErrorCode[FD_ACCEPT_BIT] != 0) 
       { 
        printf("FD_ACCEPT failed with error %d\n", 
         NetworkEvents.iErrorCode[FD_ACCEPT_BIT]); 
        break; 
       } 

       // Accept a new connection, and add it to the 
       // socket and event lists 
       Accept = accept(
        SocketArray[Index], 
        NULL, NULL); 

       NewEvent = WSACreateEvent(); 

       WSAEventSelect(Accept, NewEvent, 
        FD_READ │ FD_CLOSE); 

       EventArray[EventTotal] = NewEvent; 
       SocketArray[EventTotal] = Accept; 
       EventTotal++; 
       printf("Socket %d connected\n", Accept); 
      } 

      // Process FD_READ notification 
      if (NetworkEvents.lNetworkEvents & FD_READ) 
      { 
       if (NetworkEvents.iErrorCode[FD_READ_BIT] != 0) 
       { 
        printf("FD_READ failed with error %d\n", 
         NetworkEvents.iErrorCode[FD_READ_BIT]); 
        break; 
       } 

       // Read data from the socket 
       recv(SocketArray[Index - WSA_WAIT_EVENT_0], 
        buffer, sizeof(buffer), 0); 

       // here I do some processing on the data received 
       DoSomething(buffer); 

       // now I want to send data 
       send(SocketArray[Index - WSA_WAIT_EVENT_0], 
         buffer, sizeof(buffer), 0); 
       // how can I be assured that the data is sent completely 

      } 

      // FD_CLOSE handling here 
      // ...... 
      // ...... 
     } 
    } 
} 

我的想法,我會設置一個布爾標誌來確定接收已完成(該消息將有其長度前綴),然後開始處理該數據。但是send()?你能告訴我可能性嗎?

**編輯:**見FD_READ事件部分

回答

0

除非你正在處理協議(應用層)爲您提供有關你有多少數據要回任何信息,只有這樣才能確定是否當對方斷開連接時,沒有什麼可以收到的。如果服務器停止發送,則無法確定其結束還是其正忙。它結束時結束。您也無法確定服務器是否因其結束而斷開連接,或者因爲連接中斷。

這就是爲什麼大多數協議都會通知對等方在發送它之前要發送多少字節,或者通過在數據末尾放置一個邊界。

關於發送,您必須知道您使用的緩衝區。當你send(),它進入一個緩衝區(默認爲64KB)。 send()返回放置在緩衝區中的字節數,如果小於您嘗試發送的字節數,則必須管理它,以便在下次收到FD_WRITE事件時再次嘗試。

除非通知對方已經收到了多少數據,否則無法確定對方已收到多少數據(mIRC DDC會這樣做)。

不知道它clearfyed你的疑惑,希望它幫助:)

+0

問題是我沒有等待FD_WRITE事件,因爲我必須發送足夠的數據,以便內部緩衝區已滿並且它再次發送FD_WRITE事件。我正在做的是異步發送,但是我需要知道數據已成功發送。我怎麼做? – akif 2009-09-02 04:17:07

+0

其簡單,你等待FD_WRITE :) – Havenard 2009-09-02 04:43:50

+0

,因爲我發送短消息(1,2字節)我不會得到另一個FD_WRITE事件,除非內部緩衝區已滿。 – akif 2009-09-02 05:21:01

0

當你正在做的recv,您需要保存返回狀態,以確定是否接收到的數據。 recv返回接收到的字節數,並且我將使用MSG_WAITALL標誌而不是零作爲第四個參數來接收所有消息(基於緩衝區大小)。如果狀態recv返回爲負值,則會出現某種性質的錯誤,例如連接距離另一端較近或出現其他問題。

至於發送,你應該保存返回值,因爲它也是狀態,但在這種情況下,沒有一個標誌可以在返回之前發送所有數據。您將必須確定發送量並根據該值調整緩衝區和發送大小。與recv一樣,負值表示發生錯誤。

有關返回值和標誌的更多信息,我會在微軟網站上閱讀recvsend的函數描述。

+0

MSG_WAITALL用於SOCK_DGRAM(UDP和RAW)。 SOCK_STREAM(TCP)將掛起。 – Havenard 2009-09-02 04:47:01