Windows网络编程---IOCP编程优雅退出处理

发布于:2025-04-02 ⋅ 阅读:(13) ⋅ 点赞:(0)

在 IOCP 网络编程中,ERROR_OPERATION_ABORTEDERROR_NETNAME_DELETED 是常见的错误代码,它们表示 I/O 操作被取消或套接字连接关闭的不同情况。对于这两个错误,你可以调用 CancelIoExclosesocket,但有一些细节需要注意,避免重复调用而引起问题。

1. ERROR_OPERATION_ABORTED 错误

  • 解释:当你使用 CancelIoEx 取消一个正在进行的 I/O 操作时,该操作会返回 ERROR_OPERATION_ABORTED,表示该 I/O 操作被中止。这个错误表示操作被主动取消,通常发生在调用 CancelIoEx 之后。

  • 是否可以调用 CancelIoExclosesocket

    • 在遇到 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 表示远程主机的连接被强制关闭,通常是因为网络断开、对方主动关闭连接或网络故障。这个错误意味着套接字连接已经不再有效。

  • 是否可以调用 CancelIoExclosesocket

    • 在遇到 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 是用来确保释放资源,不会导致重复错误。

总结:

  1. ERROR_OPERATION_ABORTED:通常是在 I/O 操作被取消时返回的,调用 CancelIoEx 是有效的,尤其是在你没有显式取消操作的情况下。closesocket 可以在任何时候安全调用。

  2. ERROR_NETNAME_DELETED:表示连接已被对方关闭或断开。你可以调用 CancelIoExclosesocket,它们是安全的,不会导致重复错误。

关键注意点:
  • 调用 CancelIoEx:在遇到 ERROR_OPERATION_ABORTEDERROR_NETNAME_DELETED 时,如果你未显式取消 I/O 操作,可以调用 CancelIoEx 来确保取消所有挂起的 I/O 操作,避免继续等待无效的操作。

  • 调用 closesocketclosesocket 负责关闭套接字并释放资源。它是线程安全的,可以在 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;
}

结论:

  • CancelIoExclosesocket 在遇到 ERROR_OPERATION_ABORTEDERROR_NETNAME_DELETED 错误时是安全的,你可以根据需要调用它们来取消 I/O 操作和关闭套接字。

  • 不会因重复调用而引起错误,但需要确保在适当的时机调用它们,避免不必要的操作。