我正在使用IO完成端口和AcceptEx()
,同时了解服务器,并正在研究Len Holgate的免费服务器框架来执行此操作。他有以下代码:
// Basically calls AcceptEx() via a previously obtained function pointer
if (!CMSWinSock::AcceptEx(
m_listeningSocket,
pSocket->m_socket,
reinterpret_cast<void*>(const_cast<BYTE*>(pBuffer->GetBuffer())),
bufferSize,
sizeOfAddress,
sizeOfAddress,
&bytesReceived,
pBuffer))
{
const DWORD lastError = ::WSAGetLastError();
if (ERROR_IO_PENDING != lastError)
{
Output(_T("CSocketServerEx::Accept() - AcceptEx: ") + GetLastErrorMessage(lastError));
pSocket->Release();
pBuffer->Release();
}
}
else
{
// Accept completed synchronously. We need to marshal the data recieved over to the
// worker thread ourselves...
m_iocp.PostStatus((ULONG_PTR)m_listeningSocket, bytesReceived, pBuffer);
}
我很担心&#34;接受同步完成&#34;其他情况。我已多次尝试使这个代码路径被命中(通过在发出AcceptEx
之前暂停代码,连接,然后恢复代码),但每当我尝试调用总是失败时ERROR_IO_PENDING
我收到通知包此外,我读过this MS knowledgebase article(我可能误解了)哪些陈述
此外,如果Winsock2 I / O调用返回SUCCESS或IO_PENDING,则为 保证完成数据包将在以后排队到IOCP I / O完成
但是,我认为这并不适用于AcceptEx()
,因为参数AcceptEx()
的{{1}}状态dox
仅当操作同步完成时才设置此参数。
所以似乎可以同步完成...有人可以告诉我如何 lpdwBytesReceived
可以同步完成(例如我如何在我的服务器中复制它?)
答案 0 :(得分:1)
此外,如果Winsock2 I / O调用返回
SUCCESS
或ERROR_IO_PENDING
,则为 保证完成数据包将在以后排队到IOCP I / O完成
如果完成端口与文件关联,则适用于任何 I / O请求。但是从windows vista开始,这也取决于notification mode设置的文件句柄。
但首先需要从原生视角开始。
默认情况下,如果未设置FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
,则返回NTSTATUS status
存在3个案例:
NT_SUCCESS(status)
或status >= 0
- 将完成NT_ERROR(status)
或status >= 0xc0000000
- 将无法完成NT_WARNING(status) or status < 0xc0000000
- 不清楚 - 如果是这样的话
来自I / O经理的错误(比如 - STATUS_DATATYPE_MISALIGNMENT
- 会
没有完成)。如果这个错误来自司机(比如说
STATUS_NO_MORE_FILES
- 将完成)。 win32层通常单独检查STATUS_PENDING
并在这种情况下返回ERROR_IO_PENDING
(但存在和例外,如ReadDirectoryChangesW
)。否则,如果NT_ERROR(status)
api返回失败并设置错误代码。否则返回成功。可见情况NT_WARNING(status)
被视为成功,但在这种情况下,如果来自I / O管理器的错误,将无法完成。如果参数不正确,I / O通常会从NT_ERROR(status)
范围返回错误。只有我知道的情况(对于异步api) - 当错误的对齐缓冲区,当I / O管理器具有关于缓冲区对齐的特殊知识时,可以返回STATUS_DATATYPE_MISALIGNMENT
。在NtNotifyChangeDirectoryFile
(win ReadDirectoryChangesW
)或NtQueryDirectoryFile
(无对应的win32 api)。所以只有我知道什么时候才能完成的情况,当win32返回成功时 - 用未对齐的 lpBuffer 调用ReadDirectoryChangesW
(它必须是DWORD对齐的) - 在这种情况下I / O管理器只是返回STATUS_DATATYPE_MISALIGNMENT
但win32层将此解释为成功代码并返回true。但在这种情况下将无法完成。但这种情况很少发生,您可能需要使用错误的对齐结构。总的来说是的:
默认情况下,如果I / O调用返回SUCCESS
或ERROR_IO_PENDING
,则会将完成条目排入端口。 (有特殊例外情况,我尝试描述)
如果我们在文件对象上设置FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
(注意这是每个文件对象但不是每个文件句柄 - 文档不完全在这里)都变得更加简单和高效 - 完成条目将排队到端口 - 当并且仅当I / O请求返回STATUS_PENDING
时。来自win32视图的ERROR_IO_PENDING
(除了ReadDirectoryChangesW
(可能是其他api?),其中win32层只是丢失了返回代码信息)
你搞错了。这个,我怎么说,适用于任何io请求。 &#34;仅当操作同步完成时才设置此参数。&#34; - 等等什么?但是,我认为这并不适用于
AcceptEx()
如果查看代码片段,清除可见代码假设 - 如果AcceptEx
完成同步且没有错误发生 - 将不会完成。或SetFileCompletionNotificationModes(m_listeningSocket, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)
被叫或代码错误 - 在这种情况下将完成io并且不需要m_iocp.PostStatus
- 这将是致命的错误。但我怀疑代码使用FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
- 所以它错了。但是错误从未引发过,因为AcceptEx
(强调ioctl)的驱动程序端实现永远不会返回STATUS_SUCCESS
:它检查参数 - 如果错误 - 只返回一些错误,否则总是返回STATUS_PENDING
。因此,对于异步套接字AcceptEx
永远不会返回true,代码永远不会跳转到错误的其他情况。但无论如何代码是错误的。我认为设计不是最好的 - 如果我们确定不会完成 - 更好的只是直接调用完成例程而返回错误代码而不是Release()
(这将在完成例程中完成)或PostStatus
- for什么帖子?! - 直接打电话。
AcceptEx()
如何同步完成
非常简单 - 如果m_listeningSocket
处理同步文件对象。但是在这种情况下,您无法将IOCP绑定到文件(它只能在异步文件对象的情况下绑定)。
关于lpdwBytesReceived
参数 - IO_STATUS_BLOCK
的系统副本Information
成员或者如果想要OVERLAPPED.InternalHigh
,以防操作刚刚完成。如果挂起返回 - 这些数据根本没有准备好,也没有填写。你有完成后io返回的实际字节数