如何使用 WSASend() 和 IOCP 模拟阻塞 send()?

How to simulate a blocking send() using WSASend() and IOCP?

编辑: 这个问题不是必需的,因为 WSASend() 函数本质上可以在阻塞模式下使用,即使套接字具有重叠属性并且与完成端口相关联。要在阻塞模式下使用它:调用 WSASend().

时不要提供重叠结构或完成例程

我想确保当我发送数据时,该函数仅在数据已放入发送缓冲区后才会 return。所以这就是我想出的(伪代码):

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);
        }
    }
}

你为什么要这样做?

您认为它实现了什么?

来自 MSDN documentation 对于 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.

因此,只要不提供完成例程或 OVERLAPPED 结构,调用就会变成 "non overlapped" 调用。这就是您想要的,一个阻塞调用,直到数据被复制到网络堆栈的发送缓冲区中...

此外,我希望有问题的代码没有使用 IOCP,因为如果使用 IOCP,它会严重崩溃,也许现在不会,但最终会崩溃。你有一个竞争条件。如果您正在使用 IOCP,那么 OVERLAPPED 结构必须存在,直到完成发生并由调用 GetQueuedCompletionStatus() 的线程处理。您可以通过这种方式使用重叠 I/O,只是不要将套接字与 IOCP 相关联。您等待事件发出信号这一事实并不意味着您在 GetQueuedCompletionStatus() 上阻塞的线程之一将检索完成并处理它并完成接触您在其上创建的 OVERLAPPED 结构调用等待事件完成之前的堆栈和该函数 returns。