Winsocks发送和接收

时间:2009-09-02 03:39:26

标签: c++ winsock

我在Windows套接字中使用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
            // ......
            // ......
        }
    }
}

我的想法是,我会设置一个布尔标志来确定接收已完成(消息将以其长度为前缀),然后开始处理该数据。但是发送()呢?你能告诉我可能性吗?

**编辑:**请参阅FD_READ事件部分

2 个答案:

答案 0 :(得分:0)

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

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

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

您无法确定对等方已收到多少数据,除非它通知您(mIRC DDC会这样做)。

不确定它让你的疑惑变得清晰,希望它有所帮助:)

答案 1 :(得分:0)

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

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

我将阅读Microsoft网站上recvsend的函数说明,以获取有关返回值和标志的更多信息。