C++Boost.Asio错误在async_receive和async_send处理程序中

C++ Boost.Asio errors in async_receive and async_send handlers

本文关键字:async send 处理 程序 receive Asio C++Boost 错误      更新时间:2023-10-16
  1. 当error_code不为0时,连接是否正式"死"?

  2. 当error_code不为0时,读取处理程序的bytesReceived参数是否可能为0以外的任何值?如果可能的话,应该处理这些字节还是不处理?

简而言之,一个不成功的error_code并不保证连接是死的,对于非组合操作,例如async_receive()bytes_transferred在成功时将是0或更多,如果发生错误,则始终是0


一个不成功的error_code并不能正式表示该连接已正式失效。例如,TCP连接在以下情况下仍然存在:

  • 通过cancel()取消的未完成的basic_stream_socket::async_receive()操作将导致调用处理程序时出现boost::asio::error::operation_aborted错误
  • 全双工连接中只有一部分是shutdown()。例如,如果套接字的接收端关闭,那么数据仍然可以通过套接字通过连接发送

对于非组合操作,当发生错误时,bytes_transferred将为0。然而,0并不表示发生了错误。例如,bytes_transferred可以是0,而error_code可以在使用反应器式操作或提供空缓冲区时指示成功。StreamSocketService的async_receive()async_send()文档说明:

如果操作成功完成,则会调用[handler]并传输字节数。否则使用0调用它。

另一方面,组合操作,例如boost::asio::async_read(),可以使用非成功的error_code和非零的bytes_transferred来调用。例如,如果async_read()操作被启动并设置为在完成之前读取1024字节,则它可以多次调用async_read_some()。如果接收到256个字节,然后连接关闭,则async_read()处理程序将具有非零的error_code,并且bytes_transferred将指示缓冲器的256个字节是有效的。


以下是一个完整的示例,演示了即使某些操作失败,连接仍能保持:

#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
void noop() {}
void print_status(
const boost::system::error_code& error,
std::size_t bytes_transferred)
{
std::cout << "error = (" << error << ") " << error.message() << "; "
"bytes_transferred = " << bytes_transferred
<< std::endl;
}
void run_io_service(std::string message, boost::asio::io_service& io_service)
{
std::cout << message << ": ";
io_service.run();
io_service.reset();
}
int main()
{
using boost::asio::ip::tcp;
// Create all I/O objects.
boost::asio::io_service io_service;
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), 0));
tcp::socket socket1(io_service);
tcp::socket socket2(io_service);
// Connect the sockets.
acceptor.async_accept(socket1, boost::bind(&noop));
socket2.async_connect(acceptor.local_endpoint(), boost::bind(&noop));
io_service.run();
io_service.reset();
const char data[] = "hellon";
char buffer[128];
// Create an async receive operation and cancel it.
socket1.async_receive(boost::asio::buffer(buffer), &print_status);
socket1.cancel();
run_io_service("async_receive1", io_service);
// Create an async write operation.
socket1.async_send(boost::asio::buffer(data), &print_status);
run_io_service("async_send1", io_service);
// Shutdown the receive side of the socket then create an async
// receive operation.
socket1.shutdown(tcp::socket::shutdown_receive);
socket1.async_receive(boost::asio::buffer(buffer), &print_status);
run_io_service("async_receive2", io_service);
// Create an async write operation.
socket1.async_send(boost::asio::buffer(data), &print_status);
run_io_service("async_send2", io_service);
}

输出:

async_receive1: error = (system:125) Operation canceled; bytes_transferred = 0
async_send1: error = (system:0) Success; bytes_transferred = 7
async_receive2: error = (asio.misc:2) End of file; bytes_transferred = 0
async_send2: error = (system:0) Success; bytes_transferred = 7