WSARecv() 和 lpNumberOfBytesRecvd 参数

WSARecv() and the lpNumberOfBytesRecvd parameter

WSARecv()documentationlpNumberOfBytesRecvd 参数说明如下:

A pointer to the number, in bytes, of data received by this call if the receive operation completes immediately.

Use NULL for this parameter if the lpOverlapped parameter is not NULL to avoid potentially erroneous results. This parameter can be NULL only if the lpOverlapped parameter is not NULL.

我正在使用IOCP所以lpOverlapped不能NULL,同时WSARecv()可以立即完成。因此,如果 WSARecv() 立即完成,如果 lpNumberOfBytesRecvdNULL,我怎么知道读取了多少字节?!或者文档只是意味着我可以将 NULL 用于 lpNumberOfBytesRecvd 但我不必这样做?

文档只是说明了在这些参数上使用 NULL 的一些规则,它 不是 说明您 必须 在任何情况下都使用 NULL。您始终可以根据需要使这些参数正确指向有效变量。

当一个重叠的 WSARecv()IO_PENDINGSUCCESS 完成时,一个完成数据包将排队到 IOCP,请参阅 this MSDN article for details

对于 Vista 或更高版本,您可以通过为套接字调用 SetFileCompletionNotificationModes() 并传递 FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 来更改此设置(请注意,您可以在文档中将文件读作套接字,文件句柄的概念直接翻译到插座)。

如果您确实启用完成端口跳过,那么当 WSARecv() return 立即与数据一起发送时(即 SUCCESS return 而不是 IO_PENDING return) 然后你必须直接在 WSARecv() 调用站点处理它,因为你不会得到完成数据包。

请注意,启用 "skip completion port" 处理对于减少上下文切换非常有用,但您现在需要以两种方式处理完成,要么直接(当WSARecv() returns SUCCESS) 或在您的正常完成处理程序中(当 WSARecv() return 出现错误且错误为 IO_PENDING 时)。而之前两个结果都生成了一个完成数据包。

所以,回答你的问题...

除非您启用了 "skip completion port" 处理,否则没有理由在 WSARecv() 的调用站点使用 lpNumberOfBytesRecvd 的值,因为即使调用 returns SUCCESS 因为数据已经可用,你仍然会得到一个排队到 IOCP 的完成,你必须以通常的方式处理它。

当且仅当您启用了 "skip completion port" 处理时,您才应该处理 return 通过调用 WSARecv() 编辑的数据 returns SUCCESS在你得到 SUCCESS 结果的时候。