0

我在 Windows Sockets 中使用 WSAEventSelect I/O 模型,现在我想知道我怎么知道我的发送和接收操作已经发送和接收了所有数据?

在我知道之后,我应该如何设计一种方式才能完全发送数据?任何示例将不胜感激。

这是代码(我正在学习的书中的示例代码):

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 事件部分

4

2 回答 2

0

除非您正在处理的协议(应用程序层)为您提供有关您将要接收多少数据的任何信息,否则确定是否没有更多数据要接收的唯一方法是当对等方断开连接时。如果服务器只是停止发送,您无法确定它是结束还是只是忙。当它结束时它就结束了。您也无法确定服务器是因为结束还是因为连接中断而断开连接。

这就是为什么大多数协议会在发送之前通知对等方它将发送多少字节,或者通过在数据末尾放置边界。

关于发送,您必须了解您正在使用的缓冲区。当你 时send(),它会进入一个缓冲区(默认为 64KB)。send()返回放置在缓冲区中的字节数,如果它小于您尝试发送的字节数,您必须管理它以便在下次收到 FD_WRITE 事件时重试。

您无法确定对等方已经收到了多少数据,除非它让您了解情况(mIRC DDC 会这样做)。

不确定它是否消除了您的疑虑,希望对您有所帮助:)

于 2009-09-02T04:07:04.593 回答
0

在做recv的时候,需要保存返回状态来判断是否接收到数据。recv 返回接收到的字节数,我将使用标志 MSG_WAITALL 而不是零作为第四个参数来接收所有消息(基于缓冲区大小)。如果状态 recv 返回是否定的,则存在某种性质的错误,例如连接从另一端关闭或存在其他问题。

至于发送,您应该将返回值保存为状态,但在这种情况下,没有一个标志可以在返回之前发送所有数据。您必须确定发送量并根据该值调整缓冲区和发送大小。与 recv 一样,负值表示发生了错误。

我会阅读 Microsoft 网站上有关recv的函数描述,并发送有关返回值和标志的更多信息。

于 2009-09-02T04:16:08.770 回答