C++ boost asio async_read()似乎跳过了一些空值

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。(事实上,它将读取四(长度标题),然后读取三(正

我对一个简单的boost-asio-TCP对话有点疯狂

我有一个服务器和一个客户端。我使用长度前缀消息。客户端发送“一”,服务器响应“二”。这就是我所看到的:

客户端发送,服务器接收,
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);
        });
}