请注意那些不赞成投票的人:这个问题不是关于asio的异步方面的(尽管也许异步解决方案在这里很有意义,这是我最后提出的一个问题)。实际上,这实际上与在asio tcp套接字包装程序中使用streambuf和ostreams有关。示例/教程未涵盖此特定方面(细分写调用)。

我正在为插件环境编写一些代码(希望很简单),该代码需要响应某些事件而将相当大的数据块(约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连接吗?

最佳答案

尽管我无法找到一种查询ostream的方法来直接确定流中“等待”的数据量,但我能够完全避免使用ostream并将数据序列化为char*数组。然后,可以使用boost::asio::write()函数以类似于旧式C套接字方法的方式发送此消息:

...
tcp::socket socket(io_service);
char * buffer = new char[size];  // or a smart-ptr
float_array.SerializeToArray(static_cast<void*>(buffer, size));
void * p = static_cast<void*>(buffer);
int bytes_sent = boost::asio::write(socket, boost::asio::buffer(p, bytes_to_send);


或者,如果首选使用boost::asio::streambufstd::ostream,则似乎在使用ostream写入某些数据之后可以查询streambuf(使用.size()):

boost::asio::streambuf b;
std::ostream os(&b);
float_array.SerializeToOstream(&os);

// send a chunk of a particular size
int bytes_to_send = std::min(chunk_size, b.size());
cout << b.size() << endl;  // shows amount of remaining data
boost::asio::write(socket, b, boost::asio::transfer_exactly(bytes_to_send));
cout << b.size() << endl;  // shows a reduction in amount of remaining data


因此,如果多次调用(对于每个块),则ostream,streambuf和io_service必须保留在范围内。

关于c++ - 从streambuf使用boost::asio::ip::tcp将数据段写入TCP套接字,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19614696/

10-11 23:07
查看更多