AcceptEx() 同步完成?
AcceptEx() synchronous completion?
我正在使用 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);
}
我对 "Accept completed synchronously" 其他情况感到困惑。我已经多次尝试让这个代码路径被命中(通过在我发出 AcceptEx
之前暂停代码,连接,然后恢复代码),但是每当我尝试调用总是失败并显示 ERROR_IO_PENDING
然后我收到通知包。此外,我已阅读 this MS knowledgebase article(我可能误解了)其中指出
Additionally, if a Winsock2 I/O call returns SUCCESS or IO_PENDING, it
is guaranteed that a completion packet will be queued to the IOCP when
the I/O completes
但是,我认为这不适用于 AcceptEx()
,因为参数 lpdwBytesReceived
的 AcceptEx()
状态的 dox
This parameter is set only if the operation completes synchronously.
所以它似乎 可以 同步完成...谁能告诉我 如何 AcceptEx()
可以同步完成(即如何在我的服务器中复制它?)
Additionally, if a Winsock2 I/O call returns SUCCESS
or ERROR_IO_PENDING
, it
is guaranteed that a completion packet will be queued to the IOCP when
the I/O completes
这适用于 any I/O 如果完成端口与文件相关联的请求。但是从 windows vista 开始,这也取决于从 notification mode 设置的文件句柄。
但需要先从本机视图开始查看。
默认情况下,如果 FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
未设置,存在 3 种情况 returned NTSTATUS status
:
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
和 return ERROR_IO_PENDING
(但存在例外情况,例如 ReadDirectoryChangesW
)。否则万一 NT_ERROR(status)
api return 失败并设置错误代码。否则 return 成功。可见 NT_WARNING(status)
的情况视为成功,但在这种情况下,如果 I/O 管理器出错,则不会完成。如果参数不正确,I/O 通常 return 来自 NT_ERROR(status)
范围的错误。只有我知道的情况(对于异步 api)- STATUS_DATATYPE_MISALIGNMENT
可以被 return 编辑以防错误对齐的缓冲区,当 I/O 管理器对缓冲区对齐有特殊的了解时。在 NtNotifyChangeDirectoryFile
(ReadDirectoryChangesW
用于 win32)或 NtQueryDirectoryFile
(没有对应的 win32 api)。所以只有我知道什么时候不会完成的情况,当 win32 return 成功时 - 使用未对齐的 lpBuffer 调用 ReadDirectoryChangesW
(它必须是 DWORD-aligned ) - 在这种情况下 I/O 管理器只是 return STATUS_DATATYPE_MISALIGNMENT
但 win32 层将其解释为成功代码并且 return 为真。但在这种情况下不会完成。然而,这种情况很少见,您可能需要为此使用错误的对齐结构。所以一般来说是的:
默认情况下如果I/O调用returns SUCCESS
或ERROR_IO_PENDING
将排队一个完成条目到端口。 (我尝试描述的特殊例外情况)
如果我们在文件对象上设置 FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
(注意这是每个文件对象而不是每个文件句柄 - 文档不完全在这里)一切都会变得更加简单和高效 - 完成条目将排队到端口- 当且仅当 I/O 请求 return STATUS_PENDING
时。 ERROR_IO_PENDING
从 win32 视图(除了 ReadDirectoryChangesW
( 可能是其他 api ?),其中 win32 层只是丢失了 return 代码信息)
However, I am thinking this doesn't apply to AcceptEx()
你错了。这,我怎么说,适用于任何 io 请求。 "This parameter is set only if the operation completes synchronously." - 那又怎样?
如果查看代码片段,可以清楚地看到代码假设 - 如果 AcceptEx
同步完成并且没有发生错误 - 将没有 io 完成。或 SetFileCompletionNotificationModes(m_listeningSocket, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)
调用或代码错误 - 在这种情况下将是 io 完成而不需要 m_iocp.PostStatus
- 这是致命错误。但是我怀疑代码使用了 FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
- 所以它错了。但从未出现错误,因为 AcceptEx
的驱动程序端实现(下划线 ioctl)从不 return STATUS_SUCCESS
:它检查参数 - 如果错误 - 只是 return 一些错误,否则总是 return STATUS_PENDING
。结果,对于异步套接字 AcceptEx
永远不会 return true 并且代码永远不会跳转到错误的其他情况。但无论如何代码是错误的。我也认为设计不是最好的 - 如果我们确定不会完成 - 最好直接调用完成例程 returned 错误代码而不是 Release()
(这将在完成例程中完成)或 PostStatus
- 为什么 post?! - 直接打电话。
how AcceptEx()
can complete synchronously
非常简单 - 如果 m_listeningSocket
是 同步 文件对象的句柄。但是在这种情况下,您不能将 IOCP 绑定到文件(它只能在异步文件对象的情况下绑定)。
关于lpdwBytesReceived
参数-系统复制IO_STATUS_BLOCK
的Information
成员或者如果想要OVERLAPPED.InternalHigh
,以防操作完成即可。如果未决 returned - 此数据根本没有准备好且未填充。你得到了由 io 完成 return 的实际字节数
我正在使用 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);
}
我对 "Accept completed synchronously" 其他情况感到困惑。我已经多次尝试让这个代码路径被命中(通过在我发出 AcceptEx
之前暂停代码,连接,然后恢复代码),但是每当我尝试调用总是失败并显示 ERROR_IO_PENDING
然后我收到通知包。此外,我已阅读 this MS knowledgebase article(我可能误解了)其中指出
Additionally, if a Winsock2 I/O call returns SUCCESS or IO_PENDING, it is guaranteed that a completion packet will be queued to the IOCP when the I/O completes
但是,我认为这不适用于 AcceptEx()
,因为参数 lpdwBytesReceived
AcceptEx()
状态的 dox
This parameter is set only if the operation completes synchronously.
所以它似乎 可以 同步完成...谁能告诉我 如何 AcceptEx()
可以同步完成(即如何在我的服务器中复制它?)
Additionally, if a Winsock2 I/O call returns
SUCCESS
orERROR_IO_PENDING
, it is guaranteed that a completion packet will be queued to the IOCP when the I/O completes
这适用于 any I/O 如果完成端口与文件相关联的请求。但是从 windows vista 开始,这也取决于从 notification mode 设置的文件句柄。
但需要先从本机视图开始查看。
默认情况下,如果 FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
未设置,存在 3 种情况 returned NTSTATUS status
:
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
和 return ERROR_IO_PENDING
(但存在例外情况,例如 ReadDirectoryChangesW
)。否则万一 NT_ERROR(status)
api return 失败并设置错误代码。否则 return 成功。可见 NT_WARNING(status)
的情况视为成功,但在这种情况下,如果 I/O 管理器出错,则不会完成。如果参数不正确,I/O 通常 return 来自 NT_ERROR(status)
范围的错误。只有我知道的情况(对于异步 api)- STATUS_DATATYPE_MISALIGNMENT
可以被 return 编辑以防错误对齐的缓冲区,当 I/O 管理器对缓冲区对齐有特殊的了解时。在 NtNotifyChangeDirectoryFile
(ReadDirectoryChangesW
用于 win32)或 NtQueryDirectoryFile
(没有对应的 win32 api)。所以只有我知道什么时候不会完成的情况,当 win32 return 成功时 - 使用未对齐的 lpBuffer 调用 ReadDirectoryChangesW
(它必须是 DWORD-aligned ) - 在这种情况下 I/O 管理器只是 return STATUS_DATATYPE_MISALIGNMENT
但 win32 层将其解释为成功代码并且 return 为真。但在这种情况下不会完成。然而,这种情况很少见,您可能需要为此使用错误的对齐结构。所以一般来说是的:
默认情况下如果I/O调用returns SUCCESS
或ERROR_IO_PENDING
将排队一个完成条目到端口。 (我尝试描述的特殊例外情况)
如果我们在文件对象上设置 FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
(注意这是每个文件对象而不是每个文件句柄 - 文档不完全在这里)一切都会变得更加简单和高效 - 完成条目将排队到端口- 当且仅当 I/O 请求 return STATUS_PENDING
时。 ERROR_IO_PENDING
从 win32 视图(除了 ReadDirectoryChangesW
( 可能是其他 api ?),其中 win32 层只是丢失了 return 代码信息)
However, I am thinking this doesn't apply to
AcceptEx()
你错了。这,我怎么说,适用于任何 io 请求。 "This parameter is set only if the operation completes synchronously." - 那又怎样?
如果查看代码片段,可以清楚地看到代码假设 - 如果 AcceptEx
同步完成并且没有发生错误 - 将没有 io 完成。或 SetFileCompletionNotificationModes(m_listeningSocket, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)
调用或代码错误 - 在这种情况下将是 io 完成而不需要 m_iocp.PostStatus
- 这是致命错误。但是我怀疑代码使用了 FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
- 所以它错了。但从未出现错误,因为 AcceptEx
的驱动程序端实现(下划线 ioctl)从不 return STATUS_SUCCESS
:它检查参数 - 如果错误 - 只是 return 一些错误,否则总是 return STATUS_PENDING
。结果,对于异步套接字 AcceptEx
永远不会 return true 并且代码永远不会跳转到错误的其他情况。但无论如何代码是错误的。我也认为设计不是最好的 - 如果我们确定不会完成 - 最好直接调用完成例程 returned 错误代码而不是 Release()
(这将在完成例程中完成)或 PostStatus
- 为什么 post?! - 直接打电话。
how
AcceptEx()
can complete synchronously
非常简单 - 如果 m_listeningSocket
是 同步 文件对象的句柄。但是在这种情况下,您不能将 IOCP 绑定到文件(它只能在异步文件对象的情况下绑定)。
关于lpdwBytesReceived
参数-系统复制IO_STATUS_BLOCK
的Information
成员或者如果想要OVERLAPPED.InternalHigh
,以防操作完成即可。如果未决 returned - 此数据根本没有准备好且未填充。你得到了由 io 完成 return 的实际字节数