使用boost::asio::ip::tcp::socket::cancel()和socket::close()

4
如果我使用close而不是cancel,会出现一些问题。 close函数可以关闭套接字,任何未完成的异步操作都将通过返回boost::asio::error::operation_aborted错误来停止。
为什么我应该使用cancel而不是close呢?
我担心如果有一些异步操作正在执行,cancel可能无法取消它,对吗?
asio::ip::tcp::resolve::cancel一样,我尝试了很多次在调用async_resolve之后取消resolve_handler,但resolve_handler总是没有返回boost::asio::error::operation_aborted错误。
我认为resolve_handler正在被执行?
是吗?
2个回答

7

如果您想停止挂起的操作而不关闭套接字,则取消非常有用。

请注意,Boost文档建议使用close函数以获得更好的可移植性(来自文档页面):

... 要进行可移植的取消,请考虑使用以下替代方法之一:

  • 通过定义BOOST_ASIO_DISABLE_IOCP来禁用asio的I/O完成端口后端。
  • 使用close()函数同时取消未完成的操作并关闭套接字。

1
请注意,对于cancel()的备注还指出:“在运行Windows Vista、Windows Server 2008及更高版本时,始终使用CancelIoEx函数。该函数不具有上述描述的问题。” - Sam Miller
谢谢您和Sam Miller的帮助,我现在有点明白了,谢谢。 - xiao su

7
cancel 不会关闭套接字,因此如果您打算继续使用套接字对象,请使用 cancel。特别是,如果您的异步处理程序方法中引用了套接字的成员函数,则在确保当前正在执行的异步处理程序已完成之前,可能不希望关闭套接字。 cancel 并不能保证当前正在执行的异步处理程序,它只能保证(根据 boost 文档)在调用 socket::cancel() 时,在连接、发送和接收操作方面,“此函数会立即完成所有未完成的异步操作”,或在调用 resolver::cancel() 时,“此函数强制完成主机解析器上的任何待处理异步操作”。这个“完成”意味着 boost 将调用您的异步处理程序方法,它没有管辖权将任何取消逻辑注入到您的异步处理程序中(更不用说它一开始就不知道处理程序的实现)。
我建议在异步处理程序方法中添加自己的逻辑来处理套接字/解析器等被取消的情况。如果您正在调用 cancel 方法,则很可能有能力将此取消通知异步处理程序方法。

holtavolt是正确的,使用close()更具可移植性,但这完全取决于你想要做什么。 - devyndraen
谢谢你的帮助。是的,我创建了几个对象来处理HTTP请求,并将这些对象放入std :: deque中。当有一个任务到来时,从deque中pop_front一个对象进行处理,完成后将对象push_back到deque中。当连接期间出现错误时,我会关闭套接字,但在连接和读取时,我设置了20秒的超时时间。当连接超时时,我想取消回调函数handle_connect,在handle_connect_timeout或handle_read_timeout中,我不确定使用cancel还是close,但现在,我认为对我最好的选择是close。 - xiao su

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接