臭名昭著的"ERROR_NETNAME_DELETED"错误可以被视为错误吗?
can the infamous `ERROR_NETNAME_DELETED' error be considered an error at all?
我正在使用完成端口在Windows NT中编写一个tcp服务器来利用异步I/O。我有一个 TcpSocket 类、一个 TcpServer 类和一些(虚函数)回调,用于在 I/O 操作完成时调用,例如 onRead() 用于完成读取。我还有 onOpen() 用于建立连接时和 onEof() 用于连接关闭时,依此类推。我总是对套接字有一个挂起的读取,所以如果套接字有效地获取数据(读取将以大小> 0 完成),它会调用 onRead(),相反,如果客户端从客户端关闭套接字(读取将以大小 == 0 完成),它调用 onEof(),并且服务器知道客户端何时使用 closesocket(server_socket) 关闭套接字;从它这边。
一切都很正常,但我注意到一件事:
当我调用 closesocket(client_socket); 在连接的服务器端端点而不是客户端时(无论是否设置 linger {true, 0}),挂起的读取将作为错误完成,也就是说,读取大小不仅为 == 0,而且 GetLastError() 返回错误:64 或 'ERROR_NETNAME_DELETED'。我在网上搜索了很多关于这个的信息,但没有发现任何有趣的东西。
然后我问自己:但这是一个真正的错误吗?我的意思是,这真的可以被认为是一个错误吗?
问题是在服务器端,当我关闭socket(client_socket)时将调用onError()回调;而不是onEof()。所以我想:
如果我在收到这个"ERROR_NETNAME_DELETED"错误"时调用 onEof() 而不是 onError() 怎么办?这会引入一些错误或未定义的行为吗?让我问这个问题的另一个重要点是:
当我收到带有"ERROR_NETNAME_DELETED"的读取完成时,我检查了重叠结构,特别是包含 NTSTATUS 错误代码的重叠>内部参数的基础驱动程序。如果我们看到 NTSTATUS 错误代码列表 [ http://www.tenox.tc/links/ntstatus.html ]我们可以清楚地看到,"ERROR_NETNAME_DELETED"是由NTSTATUS 0xC000013B生成的,这是一个错误,但它被称为"STATUS_LOCAL_DISCONNECT"。好吧,它看起来不像是错误的名称。它似乎更像是"ERROR_IO_PENDING",这是一个错误,但也是一种正确行为的状态。
那么检查重叠结构的内部参数,当==到'STATUS_LOCAL_DISCONNECT'时,执行对onEof()回调的调用呢?会把事情搞砸吗?
另外,我不得不说,从服务器端,如果我在调用之前调用 DisconnectEx()关闭插座(client_socket);我不会收到该错误。但是我不想调用 DisconnectEx() 呢?例如,当服务器关闭并且不想等待所有 DisconnectEx() 完成时,只想关闭所有连接的客户端。
如何处理错误条件完全取决于您。在您的情况下,此错误情况完全是预期的,您可以将其视为预期情况是完全安全的。
这种性质的另一个示例是,当您调用 API 函数但不知道要提供多大的缓冲区时。因此,您提供了一个缓冲区,您希望该缓冲区足够大。但是,如果 API 调用失败,则检查最后一个错误是否ERROR_INSUFFICIENT_BUFFER
。这是预期的错误条件。然后,您可以使用更大的缓冲区重试。
如何处理错误条件取决于您,但问题是代码中潜在问题的标志(从逻辑错误到未定义的行为)。
最重要的一点是,closesocket
后您不应该触摸 SOCKET 手柄。你在EOF上做什么?当我们检测到 EOF 时,站在我们这边closesocket
是合乎逻辑的,但这是您无法ERROR_NETNAME_DELETED
处理程序中执行的操作,因为closesocket
已经发生并且句柄无效。
想象一下,如果挂起的读取在closesocket
之前完成(有实际数据可用),并且您的应用程序在closesocket
之后立即检测到它,会发生什么也是有利可图的。您处理传入的数据并...是否使用相同的套接字句柄向客户端发送答案?您是否安排对该句柄的下一次读取?这一切都是错误的,没有ERROR_NETNAME_DELETED
告诉你。
如果在那个非常不幸的时刻(就在closesocket
之前)以 EOF 完成挂起的读取会发生什么?如果您的常规OnEof
回调被触发,并且该回调closesocket
,则再次出错。
如果closesocket
在一个线程中完成,而另一个线程等待 I/O 完成,则您描述的问题可能暗示更严重的问题。您确定另一个线程没有调用WSARecv
/ReadFile
而第一个线程正在调用closesocket
吗?这是未定义的行为,即使 winsock 让它看起来好像大部分时间都有效。
处理完成(或失败)读取不知道套接字句柄因已关闭而无用,则它就不正确。closesocket
之后,等待挂起的 I/O 完成很有用,因为如果不这样做OVERLAPPED
就无法重用结构;但是,处理这种完成是没有意义的,就好像它发生在正常操作期间一样,套接字仍然打开(错误/状态代码无关紧要)。
你调用了错误的方法。你应该调用WSAGetLastError()。Winsock API 调用后 GetLastError() 的结果毫无意义。
- 警告处理为错误这里有什么问题
- "error: no matching function for call to"构造函数错误
- boost::进程间消息队列引发错误
- C++,OpenCV,尝试显示图像时"OpenCV(4.3.0) Error: Assertion failed (size.width>0 && size.height>0)"此错误
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- QT在错误的班级中寻找空位
- vector.resize()中的分配错误
- 代码在main()中运行,但在函数中出现错误
- 释放错误后堆使用
- (C++)分析树以计算返回错误值的简单算术表达式
- Project Euler问题4的错误解决方案
- 我的字符计数代码计算错误.为什么
- 从"int*"强制转换为"unsigned int"会丢失精度错误
- 尝试导入pybind-opencv模块时出现libgtk错误
- CMake项目Boost库错误:Boost/config/compiler/gcc.hpp:165:10:致命错误:cs
- 在某些循环内使用vector.push_back时出现分段错误
- MSVC多行宏编译器错误
- 静态数据成员的问题-修复链接错误会导致编译器错误
- 为什么在运行时没有向我们提供有关分段错误的更多信息?
- 错误:未在此范围内声明'reverse'