How to simulate a blocking send() using WSASend()

2019-09-03 16:47发布

问题:

Edit: This question is not necessary, as the WSASend() function can inherently be used in a blocking mode, even if the socket has the overlapped attribute and is associated with a completion port. To use it in a blocking mode: just don't supply an overlapped structure or a completion routine when calling WSASend().


I want to make sure that when I send data, the function will only return when this data has been placed in the send buffer. So this is what I come up with (pseudo code):

void WSASend_Block(char *arr, int length)
{
    OVERLAPPED overlapped;
    overlapped.hEvent = someEvent;
    int result = WSASend(arr, length, &overlapped);

    while(true)
    {
        if (result == 0) // IO operation has been scheduled
        {
            wait(overlapped.hEvent, INFINITE); // block until data is placed into send buffer
            break;
        }
        else
        {
            result = WSASend(arr, length, &overlapped);
        }
    }
}

回答1:

Why would you want to do this?

What do you think it achieves?

From the MSDN documentation for WSASend

For sockets with the overlapped attribute, WSASend uses overlapped I/O unless both the lpOverlapped and lpCompletionRoutine parameters are NULL. In that case, the socket is treated as a non-overlapped socket.

So, simply don't supply a completion routine OR an OVERLAPPED structure and the call will become a "non overlapped" call. Which is what you want, a call which blocks until the data is copied into the network stack's send buffer...

Also, I hope the code in question is NOT using an IOCP as it will crash horribly if it is, maybe not now, but eventually. You have a race condition. If you're using IOCP then the OVERLAPPED structure MUST exist until after the completion occurs and is processed by a thread calling GetQueuedCompletionStatus(). You could use overlapped I/O this way, just do NOT associate the socket with an IOCP. The fact that you wait for the event to be signalled does not mean that one of your threads blocking on GetQueuedCompletionStatus() will have retrieved the completion and dealt with it and finished touching the OVERLAPPED structure that you have created on the stack before the call waiting on the event completes and that function returns.