C++ boost asio async_read()似乎跳过了一些空值
我对一个简单的boost-asio-TCP对话有点疯狂 我有一个服务器和一个客户端。我使用长度前缀消息。客户端发送“一”,服务器响应“二”。这就是我所看到的: 客户端发送,服务器接收,C++ boost asio async_read()似乎跳过了一些空值,c++,c++14,boost-asio,C++,C++14,Boost Asio,我对一个简单的boost-asio-TCP对话有点疯狂 我有一个服务器和一个客户端。我使用长度前缀消息。客户端发送“一”,服务器响应“二”。这就是我所看到的: 客户端发送,服务器接收,00036F6E65(==0x0003one) 服务器通过发送00 00 03 74 77 6F(==0x0003-two)进行响应 现在这里是非常奇怪的地方(代码如下)。如果客户端读取四个字节,我希望它得到0003。如果读数为7,我希望看到00000374776f。(事实上,它将读取四(长度标题),然后读取三(正
00036F6E65
(==0x0003one)
服务器通过发送00 00 03 74 77 6F
(==0x0003-two)进行响应
现在这里是非常奇怪的地方(代码如下)。如果客户端读取四个字节,我希望它得到0003
。如果读数为7,我希望看到00000374776f
。(事实上,它将读取四(长度标题),然后读取三(正文)
但我实际上看到的是,如果我一次读七个,我确实看到了00000374776f
,如果我只要求四个,我看到了74776f03
。这对我来说毫无意义
下面是我用来接收它的代码(减去一些打印语句等):
const int kTcpHeaderSize=4;
const int kTcpMessageSize=2048;
std::阵列接收\u缓冲区\u;
void TcpConnection::ReceiveHeader(){
boost::asio::异步读取(
套接字,boost::asio::buffer(接收缓冲区,kTcpHeaderSize),
[this](boost::system::error\u code error\u code,
标准::尺寸(接收长度){
如果(错误代码){
LOG_WARNING从我在代码中看到的情况来看,它应该根据以下条件工作:
异步操作将继续,直到满足以下条件之一:
- 提供的缓冲区已满。也就是说,传输的字节等于缓冲区大小之和
- 发生了一个错误
但是,请参见底部的备注:
此重载相当于调用:
boost::asio::async\u read(
s、 缓冲器,
boost::asio::transfer_all(),
处理器);
看来情况可能是唯一被检查的
尝试使用该条件,如果它确实有效,请报告一个问题。sergiopm建议使用transfer\u all
,这是很好的,我很确定它有帮助。另一个问题涉及异步发送/接收函数中的缓冲区寿命。显然,我对某些东西的寿命和使用时间感到有点困惑我需要他们活着,所以我不时地覆盖一些东西。这可能比转移更重要,但我仍然很高兴@sergiopm能帮助我走上正轨
我的目的只是拥有一个简单的tcp客户机或服务器,我可以声明它,给它一个回调,然后继续我的工作,知道我只能关注那些回调
我很确定这样的东西一定存在(成千上万次)。如果你认为有比asio更好的库来完成这项任务(也就是说,我需要的代码要少得多),请在下面对我和后面的人发表评论。原则上的限制是,由于多种语言和服务,我们需要拥有wire协议。否则,我们会陷入诸如“库X是否有语言Y的模块?”之类的问题
另一方面,我感兴趣的是,我发现的每个示例基本上都使用长度前缀编码,而不是包的开始/结束编码。长度前缀确实很容易实现,但是,除非我完全弄错了,否则会遇到重新同步的麻烦:如果流被中断(“我将向您发送100个字节,这是前50个字节,但我死了”)我不清楚是否存在无法正确重新同步的情况
无论如何,我在这一过程中学到了很多,我推荐这个练习。你应该提供ReceiveBody
的主体,以及receive\u buffer\u
的定义。关于receive\u buffer\u
的好观点,完成了。但是错误发生在调用ReceiveBody()
之前(长度不正确,以十亿计)。当前输出74 77 6F 03
表明标头被读取为00 00 03
,因此消息正文的长度为3
,然后正文被读取到缓冲区的开头,因此前三项被覆盖,您得到的74 77 6F 03
03是以前读取操作的旧值。但这只是我的怀疑。M发送方代码中可能有错误。这是一个很好的假设,但我想知道为什么,当我读取七个字节时,我看到了正确的数据,而如果我读取四个字节,它就不正确了。(ReadHeader()
给出了一个愚蠢的长度。)不过,我会进一步看,谢谢。记住,ReceiveBody(uint32\t body\u length)
正在使用数十亿个参数进行调用。很难想象该函数的内容会涉及到其参数的计算。
const int kTcpHeaderSize = 4;
const int kTcpMessageSize = 2048;
std::array<char, kTcpMessageSize + kTcpHeaderSize> receive_buffer_;
void TcpConnection::ReceiveHeader() {
boost::asio::async_read(
socket_, boost::asio::buffer(receive_buffer_, kTcpHeaderSize),
[this](boost::system::error_code error_code,
std::size_t received_length) {
if (error_code) {
LOG_WARNING << "Header read error: " << error_code;
socket_.close(); // TODO: Recover better.
return;
}
if (received_length != kTcpHeaderSize) {
LOG_ERROR << "Header length " << received_length
<< " != " << kTcpHeaderSize;
socket_.close(); // TODO: Recover better.
return;
}
uint32_t read_length_network;
memcpy(&read_length_network, receive_buffer_.data(),
kTcpHeaderSize);
uint32_t read_length = ntohl(read_length_network);
// Error: read_length is in the billions.
ReceiveBody(read_length);
});
}