在 IOCP 网络编程中,ERROR_OPERATION_ABORTED
和 ERROR_NETNAME_DELETED
是常见的错误代码,它们表示 I/O 操作被取消或套接字连接关闭的不同情况。对于这两个错误,你可以调用 CancelIoEx
和 closesocket
,但有一些细节需要注意,避免重复调用而引起问题。
1. ERROR_OPERATION_ABORTED
错误
解释:当你使用
CancelIoEx
取消一个正在进行的 I/O 操作时,该操作会返回ERROR_OPERATION_ABORTED
,表示该 I/O 操作被中止。这个错误表示操作被主动取消,通常发生在调用CancelIoEx
之后。是否可以调用
CancelIoEx
和closesocket
:在遇到
ERROR_OPERATION_ABORTED
错误时,通常意味着该 I/O 操作已经被取消。如果你的应用程序没有在之前调用CancelIoEx
来取消该操作,你可以再次调用CancelIoEx
来确保取消所有相关 I/O 操作。closesocket
是用于关闭套接字的操作,当你确认连接已经关闭,且没有其他操作需要继续时,可以安全地调用closesocket
来释放资源。
是否会重复调用导致错误:
如果在调用
CancelIoEx
后再次接收到ERROR_OPERATION_ABORTED
错误,并不代表你需要再次调用CancelIoEx
,因为已经取消了该操作。closesocket
可以在任何时候调用,只要套接字不再需要。当你关闭套接字后,closesocket
会释放资源,不会引起重复关闭的问题。
2. ERROR_NETNAME_DELETED
错误
解释:
ERROR_NETNAME_DELETED
表示远程主机的连接被强制关闭,通常是因为网络断开、对方主动关闭连接或网络故障。这个错误意味着套接字连接已经不再有效。是否可以调用
CancelIoEx
和closesocket
:在遇到
ERROR_NETNAME_DELETED
错误时,套接字已经断开连接,你可以调用CancelIoEx
来取消所有未完成的 I/O 操作(尽管此时 I/O 操作可能已经没有意义)。closesocket
可以在接收到ERROR_NETNAME_DELETED
后调用,因为套接字已经失效并且需要释放资源。
是否会重复调用导致错误:
CancelIoEx
在收到ERROR_NETNAME_DELETED
错误时可以安全调用,但通常它会取消掉所有挂起的 I/O 操作。如果没有挂起的 I/O 操作,它不会有任何影响。closesocket
也可以安全调用。尽管你可能已经在 IOCP 中收到套接字关闭的通知(比如通过ERROR_NETNAME_DELETED
),但调用closesocket
是用来确保释放资源,不会导致重复错误。
总结:
ERROR_OPERATION_ABORTED
:通常是在 I/O 操作被取消时返回的,调用CancelIoEx
是有效的,尤其是在你没有显式取消操作的情况下。closesocket
可以在任何时候安全调用。ERROR_NETNAME_DELETED
:表示连接已被对方关闭或断开。你可以调用CancelIoEx
和closesocket
,它们是安全的,不会导致重复错误。
关键注意点:
调用
CancelIoEx
:在遇到ERROR_OPERATION_ABORTED
或ERROR_NETNAME_DELETED
时,如果你未显式取消 I/O 操作,可以调用CancelIoEx
来确保取消所有挂起的 I/O 操作,避免继续等待无效的操作。调用
closesocket
:closesocket
负责关闭套接字并释放资源。它是线程安全的,可以在 IOCP 工作线程中调用,只要套接字不再需要,它不会引起重复关闭错误。
示例代码(在 IOCP 工作线程中处理这两种错误):
DWORD WINAPI IoCompletionPortWorker(LPVOID lpParam)
{
HANDLE iocp = (HANDLE)lpParam;
DWORD bytesTransferred;
ULONG_PTR completionKey;
LPOVERLAPPED overlapped;
while (true)
{
BOOL result = GetQueuedCompletionStatus(iocp, &bytesTransferred, &completionKey, &overlapped, INFINITE);
if (result)
{
// 正常的 I/O 操作
std::cout << "I/O operation completed." << std::endl;
}
else
{
DWORD dwError = GetLastError();
if (dwError == ERROR_OPERATION_ABORTED)
{
// I/O 操作被取消
std::cout << "I/O operation was cancelled (ERROR_OPERATION_ABORTED)." << std::endl;
// 可以再次调用 CancelIoEx(如果有未取消的操作)
CancelIoEx((HANDLE)completionKey, NULL);
}
else if (dwError == ERROR_NETNAME_DELETED)
{
// 远程主机关闭连接
std::cout << "Socket was closed by peer (ERROR_NETNAME_DELETED)." << std::endl;
// 取消 I/O 操作并关闭套接字
CancelIoEx((HANDLE)completionKey, NULL);
closesocket((SOCKET)completionKey); // 关闭套接字
}
// 清理完成,退出循环
break;
}
}
return 0;
}
结论:
CancelIoEx
和closesocket
在遇到ERROR_OPERATION_ABORTED
和ERROR_NETNAME_DELETED
错误时是安全的,你可以根据需要调用它们来取消 I/O 操作和关闭套接字。不会因重复调用而引起错误,但需要确保在适当的时机调用它们,避免不必要的操作。