AcceptEx
直到被告知退出为止,此时它将试图取消最后的启动接受。注:要澄清,如果第一个参数隐含转换为
TASSERT
(如果不转换为布尔值),则
TASSERTF
&false
宏中止该过程
我这样做的代码看起来像 // Cancel the last initiated accept (if it's still in progress)
if (!::CancelIoEx((HANDLE)g_unpipeListenSocket, &overlapped)) {
const DWORD error(::GetLastError());
// This should _never_ fail
TASSERTF(ERROR_NOT_FOUND == error, "CancelIoEx() failed: %s", Win32ErrorToString(error).c_str());
}
else {
// The accept was still in progress, wait until it's complete
DWORD unused;
TASSERTF(
::GetOverlappedResult((HANDLE)g_unpipeListenSocket, &overlapped, &unused, TRUE),
"GetOverlappedResult() failed: %s",
Win32ErrorToString(::GetLastError()).c_str());
}
sock_close(acceptingSocket);
sock_close(g_unpipeListenSocket);
所以发生了什么是成功,但随后呼唤
CancelIoEx
只是永远悬而未决。我的理解是,仅关闭插座并允许
GetOverlappedResult
被划分(因为它在线程的堆栈上即将返回)将使门打开以获得无用的无用,因为这不足以取消取消正在进行的I/O操作(或至少不足以等待取消生效)
任何一次,只有一次接受操作;这是我用来启动它们并处理其相关完成的代码:
overlapped
i我在线程开头时一次调用一次,然后每次我完成以前的接受的完成。如果我的错误处理代码是问题:
g_unpipeListenSocket
看起来这个问题是我正在使用
static void
BeginAccept(SOCKET& io_acceptingSocket, OVERLAPPED& in_overlapped, AcceptExBuff& in_acceptExBuff) noexcept {
memset(&in_overlapped, 0, sizeof(in_overlapped));
if (INVALID_SOCKET == io_acceptingSocket) {
io_acceptingSocket = sockit(g_unpipeInAddr.inx_family, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == io_acceptingSocket) {
char errorString[MAX_SOCK_ERROR_LEN];
sock_error_string(getSockErr(), errorString);
// TODO: Don't abort (exit thread & notify waiters somehow so they can start it again next time?)
TABORT("sockit() failed: %s", errorString);
}
}
DWORD bytesReceived;
TASSERTF(!AcceptEx(
g_unpipeListenSocket,
io_acceptingSocket,
&in_acceptExBuff,
0,
sizeof(in_acceptExBuff) / 2,
sizeof(in_acceptExBuff) / 2,
&bytesReceived,
&in_overlapped),
"AcceptEx() completed synchronously?");
const DWORD error(::WSAGetLastError());
// TODO: Don't abort (exit thread & notify waiters somehow so they can start it again next time?)
TASSERTF(
ERROR_IO_PENDING == error,
"AcceptEx() failed synchronously: (%u) %s",
error,
Win32ErrorToString(error).c_str());
}
static void
HandleAccept(
SOCKET& io_acceptingSocket,
OVERLAPPED& in_overlapped,
AcceptExBuff& in_acceptExBuff) noexcept {
TASSERT(io_acceptingSocket != INVALID_SOCKET);
const SOCKET connectedSocket(io_acceptingSocket);
io_acceptingSocket = INVALID_SOCKET;
// Begin the next accept...
BeginAccept(io_acceptingSocket, in_overlapped, in_acceptExBuff);
// Finish setting up accepted socket.
// TODO: Don't abort (exit thread & notify waiters somehow so they can start it again next time?)
TASSERTF(
!::setsockopt(connectedSocket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (PCHAR)&g_unpipeListenSocket, sizeof(SOCKET)),
"setsockopt(SO_UPDATE_ACCEPT_CONTEXT) failed:");
// Consume the connected socket
}
而不是BeginAccept
;当我切换到后者时(并将事件设置为我使用的
HandleAccept
结构的句柄,因为记录了通过
GetQueuedCompletionStatus
),事情开始工作了。我当前的线程清理时的当前代码看起来像
if (!::GetQueuedCompletionStatus(
g_unpipeListenThreadIOCP,
&numBytes,
&completionKey,
&overlappedPtr,
INFINITE))
{
const DWORD error(::GetLastError());
TASSERTF(
(&overlapped == overlappedPtr) && (ACCEPT_THREAD_ACCEPT_COMPLETION_KEY == completionKey),
"&overlapped=%p overlappedPtr=%p completionKey=%" FSIZE "u GetLastError()='%s'",
&overlapped,
overlappedPtr,
completionKey,
Win32ErrorToString(error).c_str());
SIMBA_TRACE(
"Retrieved completion status about error on accept operation: %s",
Win32ErrorToString(error).c_str());
// Start another accept (Should we consider this a fatal error?)
BeginAccept(acceptingSocket, overlapped, acceptExBuff);
continue;
}