让我们假设一个客户端拥有两个不同的大对象(就字节大小而言)并对其进行序列化,然后发送序列化的对象
使用boost::asio
通过TCP / IP网络连接到服务器。
boost::asio::write
将二进制数据(const char*
)发送到服务器。 read_some
而不是boost::asio::ip::tcp::iostream
来提高效率。我在服务器端构建了以下recv
函数。第二个参数std::stringstream &is
在函数末尾保存了一个较大的接收数据(> 65536字节)。 当客户端调用两个顺序的
boost::asio::write
以便分别发送两个不同的二进制对象时,服务器端也依次调用两个相应的recv
。但是,第一个
recv
函数吸收所有两个传入的大数据,而第二个调用则什么也没收到;-(。我不知道为什么会这样以及如何解决。
由于两个不同的对象中的每个对象都有其自己的(反)序列化功能,因此我想分别发送每个数据。实际上,由于必须通过网络发送20多个对象(而不仅仅是2个)。
void recv (
boost::asio::ip::tcp::socket &socket,
std::stringstream &is) {
boost::array<char, 65536> buf;
for (;;) {
boost::system::error_code error;
size_t len = socket.read_some(boost::asio::buffer(buf), error);
std::cout << " read "<< len << " bytes" << std::endl; // called multiple times for debugging!
if (error == boost::asio::error::eof)
break;
else if (error)
throw boost::system::system_error(error); // Some other error.
std::stringstream buf_ss;
buf_ss.write(buf.data(), len);
is << buf_ss.str();
}
}
客户端主文件:
int main () {
... // some 2 different big objects are constructed.
std::stringstream ss1, ss2;
... // serializing bigObj1 -> ss1 and bigObj2-> ss2, where each object is serialized into a string. This is due to the dependency of our using some external library
const char * big_obj_bin1 = reinterpret_cast<const char*>(ss1.str().c_str());
const char * big_obj_bin2 = reinterpret_cast<const char*>(ss2.str().c_str());
boost::system::error_code ignored_error;
boost::asio::write(socket, boost::asio::buffer(big_obj_bin1, ss1.str().size()), ignored_error);
boost::asio::write(socket, boost::asio::buffer(big_obj_bin2, ss2.str().size()), ignored_error);
... // do something
return 0;
}
服务器主文件:
int main () {
... // socket is generated. (communication established)
std::stringstream ss1, ss2;
recv(socket,ss1); // this guy absorbs all of incoming data
recv(socket,ss2); // this guy receives 0 bytes ;-(
... // deserialization to two bib objects
return 0;
}
最佳答案
recv(socket,ss1); // this guy absorbs all of incoming data
当然,它吸收了一切。您明确地用编码的
recv
进行无限循环,直到eof
为止。这是流的结尾,这意味着“无论何时在远程端关闭套接字”。因此,协议(protocol)中缺少的基本要素是框架。解决该问题的最常见方法是:
'\0'
。但是,对于二进制数据,很难(很难)找到有效载荷中自然不会出现的定界符。当然,如果您知道有效负载的其他特征,则可以使用它。例如。如果您的有效负载已压缩,则您将不会定期找到512个相同字节的块(它们将被压缩)。另外,您可以采取消除歧义的方式对二进制数据进行编码。
yEnc
,Base122
等。想起(请参阅Binary Data in JSON String. Something better than Base64以获取灵感)。 笔记:
不管那个
boost::asio::[async_]read
和boost::asio::streambuf
一起使用。 const char * big_obj_bin1 = reinterpret_cast<const char*>(ss1.str().c_str());
const char * big_obj_bin2 = reinterpret_cast<const char*>(ss2.str().c_str());
str()
returns a temporary copy of the buffer-不仅浪费,而且意味着const char*
在初始化后即成为悬挂。 关于c++ - 我们如何依次从boost::asio::tcp::ip::read_some调用中接收多个数据?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48998084/