我的协议非常简单:我发送了一个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_
的递归更新中某处 - 某些数据丢失,被覆盖?
答案 0 :(得分:2)
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
会被调用。