2009-09-02 120 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