使用 Boost Asio 在 TCP 套接字上执行异步写入操作

Posted

技术标签:

【中文标题】使用 Boost Asio 在 TCP 套接字上执行异步写入操作【英文标题】:Performing asynchronous write operations over a TCP socket with Boost Asio 【发布时间】:2012-03-09 23:56:28 【问题描述】:

我正在借助 Boost Asio 用 C++ 编写客户端/服务器应用程序。我有一个工作的服务器,服务器工作流程是我很了解的。

我的客户端应用程序优雅地处理连接,如 Asio 示例所示,之后,它与服务器交换握手。然而,在那之后,用户应该能够在他们想要的时间和方式向服务器发送请求,这就是我理解范式的问题。

最初的工作流程是这样的:

OnConnected()  SendHandshake() 
SendHandshake()  async.write_some(handshake...), async_read_some(&OnRead) 
OnRead()  ReadServerHandshake() *** 

用户会使用 Write(msg) 发送消息:

Write (msg)  async_write_some(msg,&OnWrite), async_Read_some(&OnRead) 
OnWrite()  

编辑:为了更清楚地表述问题,这里是场景:

初始握手完成后,Client 仅用于向服务器发送请求,并在服务器上得到回复。因此,例如,用户发送写入。客户端等待读取操作完成,读取回复并对其进行处理。下一个用户写入只会在 5 分钟之后出现。 io_service 是否会同时停止工作,因为在上一次回复读取和下一次写入之间没有未完成的异步操作?

【问题讨论】:

【参考方案1】:

在信息说明中,您可以向其提供 io_service::work 以阻止 io_service 停止工作。这将确保 io_service::run 在工作对象被销毁之前永远不会返回。 要控制工作对象的生命周期,您可以使用shared_ptr 指针并在工作完成后将其重置,或者您可以使用boost::optional,如here 所述。

当然,您仍然需要处理服务器关闭 TCP 连接或连接因任何原因而终止的情况。要处理这种情况,一种解决方案是在连接到服务器的套接字上有一个出色的async_read。当/如果连接出现问题时,应该使用error_code 调用读取处理程序。如果您在连接上有未完成的读取,则不需要使用工作对象。

【讨论】:

【参考方案2】:

如果希望 IO 服务完成一次读取,则必须启动一次读取。如果您想在客户端发送数据的任何时候读取数据,您必须始终有一个异步读取操作挂起。否则,图书馆怎么知道如何处理这些数据?

【讨论】:

我知道,如果我期待来自服务器的答复,我需要有一个未完成的异步读取。我在 Write 方法中这样做。但是如果我完成了写-读周期,并且用户想要再次写入之前需要一些时间,那么io_service是否会因为没有工作而终止? 但它确实有工作要做,它正在(并且仍然会)尝试完成未完成的异步读取请求。发出异步请求是您告诉 io_service 做某事的方式之一。 我的意思是读完之后。所以我做 async_read -> 一旦完成,就会调用 OnRead 处理程序,并且在其中我不调用任何其他异步操作。在启动下一次写入之前,我在套接字上没有未完成的读取或写入。 io_service 会停止工作吗? 当您在 OnRead 处理程序中时,读取尚未完成。异步操作的一部分正在运行指定的处理程序,直到它完成,操作才完成。 (而且您通常还会异步监听正在进行的新连接。)

以上是关于使用 Boost Asio 在 TCP 套接字上执行异步写入操作的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Boost.ASIO 中分配已连接的本机套接字类型 (TCP)

C++ Boost.Asio - tcp 套接字异步写入

使用 Boost Asio 在 TCP 套接字上执行异步写入操作

使用 boost::asio::ip::tcp::socket 作为 shared_ptr

如何将 boost::asio::tcp::io_stream 附加到我的 io_service?

使用Boost asio实现同步的TCP/IP通信