请注意那些不赞成投票的人:这个问题与 asio 的异步方面无关(尽管在这里异步解决方案可能有意义,这是我最后提出的一个问题)。这实际上只是将 streambuf 和 ostreams 与 asio tcp 套接字包装器一起使用。示例/教程不涵盖此特定方面(细分写入调用)。
我正在为插件环境编写一些(希望是简单的)代码,该插件环境需要将相当大的数据块(~2MB)发送到外部服务器以响应某些事件。数据需要相当迅速、完整地发送,但这种情况很少见,我并不太担心原始性能。我正在使用 Google 的协议缓冲区来序列化数据。
截至目前,我有以下几乎可以工作的代码:
#include <boost/asio.hpp>
// connect to the server:
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
tcp::resolver::query query(server_address, server_port);
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::socket socket(io_service);
boost::asio::connect(socket, endpoint_iterator);
// float_array consists of ~500,000 floats in a ProtoBuf message:
//
// message FloatArray {
// repeated float data = 1 [packed=true];
// }
// send the serialized float_array to the server:
boost::asio::streambuf b;
std::ostream os(&b);
float_array.SerializeToOstream(&os);
boost::asio::write(socket, b);
// the TCP connection *must* now close to signal the server
问题是我正在工作的环境(多线程)认为该write()
操作花费了太长时间(它阻塞),并终止了线程。由于不允许我创建自己的线程,因此我需要将 write() 操作拆分为多个单独的写入。
我关心的是如何做到这一点。我知道我可以使用它来发送确切的字节数:
boost::asio::write(socket, b, boost::asio::transfer_exactly(65536));
但要正确地做到这一点,我需要确切地知道 ostream 中还有多少字节。我注意到b.size()
相应地减少了,所以我可以使用它。然而,为了拆分我的写作,我需要在调用这个函数之间存储一些状态。
我有一个选择是在调用我的写作函数之间存储streambuf b和ostream os,但我想知道是否有更好的方法来做到这一点。据我所知,部分序列化 ProtoBuf 输出是不可能的,所以我认为我只需要调用float_array.SerializeToOstream()
. 那么问题是是否有一种适当的方法可以直接查询 ostream 以获取可用字节数,或者可能使用其他一些机制(boost::asio::buffer
也许?)。
我很高兴自己查看 boost::asio 文档,我只是在寻找有关如何进行的一些指导,因为有很多文档需要处理,我不确定难题的哪些部分是相关的。
一个想法 - 是否可以使用 boost::asio 沿着这些线路创建某种单线程异步“发送器”来为我处理这种状态?例如,我是否可以调用某种非阻塞write()
函数,然后使用某种回调(或经常访问的函数)来检查是否完成,然后关闭 TCP 连接?