【问题标题】:Large body sent via boost::asio::tcp::ip通过 boost::asio::tcp::ip 发送的大正文
【发布时间】:2013-03-17 08:01:01
【问题描述】:

我的协议很简单:我发送了一个size_t 指示正文的大小,然后是正文本身。

代码基于official Boost examples,这里是:

class tcp_conn : 
        public std::enable_shared_from_this<tcp_conn>, 
        private boost::noncopyable 
    {
    public:
        tcp_conn(ba::io_service& io_service);
        void start();
        void stop();

        tcp::socket& socket();

    private:
        void handle_read_header(const error_code& e, std::size_t bytes_transferred);
        void handle_read(const error_code& e, std::size_t bytes_transferred);

        ba::streambuf::mutable_buffers_type buffer_wrapper_;
        ba::streambuf buffer_;
        std::size_t buffer_size_;
        tcp::socket socket_;

};

而实现是:

void tcp_conn::start() {
    socket_.async_read_some(
        ba::buffer(&buffer_size_, sizeof(buffer_size_)),
        boost::bind(
          &tcp_conn::handle_read_header,
          this,
          ba::placeholders::error,
          ba::placeholders::bytes_transferred
          )
        );
}

void tcp_conn::handle_read_header(const boost::system::error_code& e, std::size_t bytes_transferred){
    if(!e) {
        buffer_wrapper_ =  buffer_.prepare(buffer_size_);

        socket_.async_read_some(
            ba::buffer(buffer_wrapper_),
            boost::bind(
              &tcp_conn::handle_read,
              this,
              ba::placeholders::error,
              ba::placeholders::bytes_transferred
              )
            ); 

    } else {
        //stop connection
    }
}


void tcp_conn::handle_read(const boost::system::error_code& e, std::size_t bytes_transferred)   {
    if (!e ) {
        buffer_.commit(bytes_transferred);

        if(buffer_.size() == buffer_size_) {
            std::cout << "WHOLE BODY TRANSFERED NOW" << std::endl;
            //has all data in buffer, handle it.
        }
        else {
            std::cout << "NOT WHOLE BODY TRANSFERED, still got "<< (buffer_size_ - bytes_transferred) << " to go" << std::endl;
            socket_.async_read_some(
                ba::buffer(buffer_wrapper_),
                boost::bind(
                  &tcp_conn::handle_read,
                  this,
                  ba::placeholders::error,
                  ba::placeholders::bytes_transferred
                  )
                ); 
        }


    }
    else {
        //handle error
    }   
}

这不太行。我猜我的错误是在 buffer_wrapper_ 的递归更新中的某个地方——有些数据会丢失、被覆盖?

【问题讨论】:

    标签: c++ networking boost tcp boost-asio


    【解决方案1】:

    buffer_.commit() 使prepare() 的结果无效,如文档所示:"The returned object is invalidated by any basic_streambuf member function that modifies the input sequence or output sequence."

    实际上,不用手动准备缓冲区并链接async_read_some(),您可以使用适当的无辅助函数与streambuf 和完成条件:

    asio::async_read(
       socket_,
       buffer_, 
       asio::transfer_exactly(buffer_size_),
       boost::bind(&tcp_conn::handle_read, this, _1, _2)
    );
    

    这样handle_read 会在您获取整个消息正文或发生错误时被调用。

    【讨论】:

    • 嘿,谢谢。我只是让它与复杂的手动缓冲区更新一起工作。你的答案几乎是完美的,但你能否为上述代码提供所有命名空间前缀(_1、_2、transfer_exactly 等在哪里定义?)
    • @Queequeg transfer_exactlyasio 命名空间中,_1, _2 绑定占位符在全局命名空间中(您可以继续使用 asio 占位符,如您的问题所示)。
    • 非常感谢,现在干净多了!而且它确实有效 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-17
    • 1970-01-01
    • 2018-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多