我有一个服务器应用程序,它使用异步i / o处理网络客户端。接受客户端连接,然后将其添加到描述符集,该描述符集可以使用poll / epoll / select / etc进行监视。我正在使用apr_pollset_poll()apache APR库调用来检查可以读取或写入的描述符。这在内部使用epoll / poll / select / etc,具体取决于平台。
问题是,其中一个套接字描述符被破坏,apr_pollset_poll返回errno 10038,即WSAENOTSOCK:尝试对非套接字的操作进行操作。不幸的是,这导致我的应用程序完全停止工作,而不仅仅是能够踢出特定的客户端连接。 如果我可以以某种方式忽略或从描述符集中删除此套接字,那么它可以继续运行并正确读/写其他套接字。我知道我应该找到导致套接字损坏的根本原因,但我需要一个故障安全的解决方法。
一旦将描述符添加到pollset中,然后由OS /内核处理这些描述符,我认为无法检索它们以便能够迭代。在我自己的列表中维护这些也可能会进一步产生其他问题,因为在socket关闭时我需要以某种方式清理它们,这会自动发生在内核内的pollset中。
有什么建议吗?
答案 0 :(得分:2)
这听起来很可怕,但是当它发生时是紧急情况。因此,我建议您浏览工作pollset中的所有描述符,并尝试对该描述符执行操作,如果描述符是伪造的,将触发该错误。例如,您可以创建一个新的临时pollset并尝试非阻塞零超时轮询操作,看看是否可以得到错误。
如果您的pollset中有超过十几个描述符,您可以考虑使用二进制搜索而不是一次一个方法。您可以将一半描述符放入临时轮询集中,然后执行操作。如果它失败了,你知道你在尝试的集合中有一个伪造的描述符;分成两半再试一次;如果它没有失败,你可以假定伪造的描述符在另一个集合中,你可以验证另一半失败或假设它将并将剩余部分分成两部分并再试一次。继续前进,直到你隔离了一个失败的描述符。显然,如果你有几个伪造的描述符而不是一个,你可能需要重复几次。
如果隔离了一个描述符,您可以决定需要做什么以及如何处理。如果/当问题再次出现时,您可以重复隔离过程。显然,除非您首先发现问题,否则不会尝试此操作。但是当事情出错时,你需要隔离问题,这将(应该)实现。
答案 1 :(得分:0)
事实证明我正在对另一个线程中轮询的套接字描述符执行close(),并且基于select()的pollset实现不喜欢这样。 另一方面,当select检测到无效套接字时,可以修改apr库代码以返回描述符,或者甚至可以自动删除它。