从 streambuf 使用 boost::asio::ip::tcp 将数据部分写入 TCP 套接字
Writing sections of data to TCP socket with boost::asio::ip::tcp from streambuf
投反对票的人请注意:这个问题不是关于asio的异步方面(尽管也许异步解决方案在这里可能有意义,这是我最后提出的一个问题)。这实际上只是关于将streambuf和ostreams与asio tcp套接字包装器一起使用。示例/教程未涵盖此特定方面(细分写入调用)。
我正在为一个插件环境编写一些(希望很简单)代码,该环境需要向外部服务器发送相当大的数据块(~2MB)以响应某些事件。数据需要相当迅速和完整地发送,但它很少,我并不过分关心原始性能。我正在使用谷歌的协议缓冲区来序列化数据。
截至目前,我有以下代码几乎可以工作:
#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::streambuf
和 std::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 保持在范围内。
- 通过套接字[TCP]传输数据 如何在C / C ++中打包多个整数并使用send() recv()传输数据
- WTSEnumerateProcesses与套接字和数据结构
- 在 1 个服务器 n 客户端套接字 C++ MFC 应用程序中更新数据的客户端
- C++ TCP 套接字通信 - 连接按预期工作,几秒钟后失败,没有收到新数据,read() 和 recv() 块
- 我们可以在套接字编程中将自定义数据作为辅助数据发送吗?
- TCP 服务器的异步读取使用 boost::asio 打印客户端套接字发送的数据
- 尝试将数据从C++发送到 Python 并使用套接字C++反转,C++ sendto() 和 python recvfr
- 不要从输入队列套接字读取数据
- 通过套接字 c++ 发送长度和数据
- 如何读取套接字编程(c ++)中的所有数据?
- 使用 Broadcast 发出的从节点服务器发送的数据不能被 C++ 套接字 IO 客户端读取
- 无法通过套接字发送或接收数据
- 连接UDP套接字,但仍然接收来自其他源的数据报
- boost::asio-async_read_some示例代码没有读取套接字中的所有数据
- 使用 epoll 边缘触发器的套接字上的数据过多
- 是否可以在数据报套接字中同时用于发送和接收
- 使用boost::asio将序列化数据写入套接字
- UDP 数据报套接字编程,服务器在 JAVA 中,客户端在 C++
- Unix数据报套接字仅适用于第一帧
- 如何立即写入数据到套接字,而不使用flush和waitFOrBytesWritten与QTCPSocket