`io_context.stop()` 与 `socket.close()`
Posted
技术标签:
【中文标题】`io_context.stop()` 与 `socket.close()`【英文标题】:`io_context.stop()` vs `socket.close()` 【发布时间】:2021-11-12 18:28:32 【问题描述】:要关闭一个 Tcp 客户端,应该使用哪个,io_context.stop()
或 socket.close()
?做出这样的选择应该考虑哪些方面?
据我所知,io_context
是线程安全的,而 socket
不是。
所以,我可以在任何线程中调用io_context.stop()
,它可能与调用io_context.run()
的线程不同。
但是对于socket.close()
,如果在不同的线程中调用socket
对象(例如,所述线程调用aiso::async_read(socket, ...)
),我需要调用io_context.post([=]()socket.stop())
。
【问题讨论】:
【参考方案1】:要关闭一个Tcp客户端,应该使用io_context.stop()还是socket.close()?
显然socket.cancel()
和或socket.shutdown()
:)
在只有一个 IO 对象(您的套接字)的情况下,停止整个 iexecution 上下文似乎是等效的。但是,一旦您打开了多个套接字或使用了计时器和信号集,就很明显为什么这是用佳能射击苍蝇了。
另请注意,io_context::stop
具有清除任何未完成工作的副作用(至少,如果没有reset()
,则无法恢复),这使其更像是一种钝器。
相反,使用socket::cancel()
取消任何 IO 操作对其进行。他们将以error::operation_aborted
结尾,以便您检测情况。如果您控制对象上的所有异步启动,这就足够了。如果您想阻止“其他”方成功启动新的 IO 操作,您可以 shutdown
套接字代替。您可以关闭套接字的写入端、读取端或两者。
shutdown 通常优于close()
的原因可能非常微妙。一方面,关闭一侧可以让您仍然可以处理/通知另一侧以正常关闭。另一方面,当本机套接字句柄(也)存储在某处时,可以防止非常常见的竞争条件:关闭套接字使本机句柄有资格重复使用,并且不知道更改的客户端可以后来的类型继续使用该句柄,不知道它现在属于其他人。我在生产代码中看到过这样的问题,在高负载下,RPC 调用会突然被写入数据库服务器。
简而言之,最好将套接字句柄与socket
实例的生命周期联系起来,并且更喜欢使用cancel()
或shutdown()
。
如果在不同的线程中调用套接字对象(例如,所述线程调用 aiso::async_read(socket, ...)),我需要调用 io_context.post(=socket.stop())。
是的,线程安全是您的责任。不,当多个线程运行执行上下文时,post(io_context, ...)
甚至还不够。在这种情况下,您需要更多同步,例如post(strand_, ...)
。见Why do I need strand per connection when using boost::asio?
【讨论】:
感谢您的详细解释。根据document,它表示“调用 cancel() 将始终失败......当在 Windows XP 和早期版本的 Windows 上运行时......对于便携式取消,请考虑使用以下替代方案之一:使用close()
函数同时取消未完成的操作并关闭套接字。”因此,该文件似乎建议调用stop()
而不是cancel()
。如果我错过了什么,请告诉我。
是的,您选择性地引用了该页面。它取决于平台和驱动程序。有多种解决方法,您会知道平台何时不支持取消。如果您只是为所有这些 Windows 版本使用各种驱动程序,那么也许您不想依赖取消(或选择退出 IOCP)。由于关闭和关闭操作仍然可用,因此答案并没有太大变化。此外,在琐碎的场景中 io_context::stop 会很好。以上是关于`io_context.stop()` 与 `socket.close()`的主要内容,如果未能解决你的问题,请参考以下文章
SO_REUSEADDR与SO_REUSEPORT平台差异性与测试