Boost.Asio 异步读写操作
参考资料:
asio异步读写操作及注意事项
目录
- 异步写操作
async_write_someasync_send- 基于
async_write_some的封装 - 基于
async_send的封装
- 异步读操作
async_read_someasync_receive- 基于
async_read_some的封装 - 基于
async_receive的封装
- 实际应用场景:实现一个简单的网络通信服务
- 服务端示例
- 客户端示例
1. 异步写操作
1.1 async_write_some
- 特点:
- 每次只尽可能多地发送数据,实际发送的字节数可能小于请求发送的总字节数。
- 应用层需通过回调函数检查已发送字节数,并循环调用直到数据完全发送。
- 适用场景:
- 更精细的控制发送过程,例如流式传输或对发送进度有特殊要求。
1.2 async_send
- 特点:
- 内部会循环调用
async_write_some,直到数据完全发送。 - 回调函数只在发送完成或发生错误时触发。
- 内部会循环调用
- 适用场景:
- 需要简化发送逻辑时使用。
1.3 基于 async_write_some 的封装
实现逻辑:
- 使用队列管理待发送数据,保证发送顺序。
- 在回调函数中检查发送进度,如果未发送完成则继续发送。
代码:
void Session::WriteToSocket(const std::string& buf) {
_send_queue.emplace(std::make_shared<MsgNode>(buf.c_str(), buf.length()));
if (_send_pending) return;
_send_pending = true;
auto front = _send_queue.front();
_socket->async_write_some(
asio::buffer(front->_msg, front->_total_len),
[this, front](const boost::system::error_code& ec, std::size_t bytes_transferred) {
this->HandleWrite(ec, bytes_transferred);
});
}
void Session::HandleWrite(const boost::system::error_code& ec, std::size_t bytes_transferred) {
if (ec) {
std::cerr << "Error during async write: " << ec.message() << std::endl;
return;
}
auto front = _send_queue.front();
front->_cur_len += bytes_transferred;
if (front->_cur_len < front->_total_len) {
_socket->async_write_some(
asio::buffer(front->_msg + front->_cur_len, front->_total_len - front->_cur_len),
[this, front](const boost::system::error_code& ec, std::size_t bytes_transferred) {
this->HandleWrite(ec, bytes_transferred);
});
} else {
_send_queue.pop();
if (_send_queue.empty()) {
_send_pending = false;
} else {
WriteToSocket(""); // 继续发送队列中的下一个消息
}
}
}
1.4 基于 async_send 的封装
实现逻辑:
- 使用队列管理数据,依次调用
async_send,简化发送逻辑。
代码:
void Session::WriteAllToSocket(const std::string& buf) {
_send_queue.emplace(std::make_shared<MsgNode>(buf.c_str(), buf.length()));
if (_send_pending) return;
_send_pending = true;
auto front = _send_queue.front();
_socket->async_send(
asio::buffer(front->_msg, front->_total_len),
[this, front](const boost::system::error_code& ec, std::size_t bytes_transferred) {
this->WriteAllCallBack(ec, bytes_transferred);
});
}
void Session::WriteAllCallBack(const boost::system::error_code& ec, std::size_t bytes_transferred) {
if (ec) {
std::cerr << "Error during async send: " << ec.message() << std::endl;
return;
}
_send_queue.pop();
if (_send_queue.empty()) {
_send_pending = false;
} else {
WriteAllToSocket(""); // 继续发送队列中的下一个消息
}
}
2. 异步读操作
2.1 async_read_some
- 特点:
- 每次只尽可能多地读取数据,实际读取的字节数可能小于请求的总字节数。
- 需要在回调函数中检查已读取字节数,并循环调用直到数据完全读取。
- 适用场景:
- 需要精细控制读取过程的场景。
2.2 async_receive
- 特点:
- 内部会循环调用
async_read_some,直到数据完全读取。 - 回调函数只在读取完成或发生错误时触发。
- 内部会循环调用
- 适用场景:
- 需要简化读取逻辑时使用。
2.3 基于 async_read_some 的封装
实现逻辑:
- 初始化接收缓冲区,调用
async_read_some开始接收数据。 - 在回调函数中检查读取进度,循环调用直到读取完成。
代码:
void Session::ReadFromSocket() {
if (_recv_pending) return;
_recv_node = std::make_shared<MsgNode>(RECVSIZE);
_socket->async_read_some(
asio::buffer(_recv_node->_msg, _recv_node->_total_len),
[this](const boost::system::error_code& ec, std::size_t bytes_transferred) {
this->ReadCallBack(ec, bytes_transferred);
});
_recv_pending = true;
}
void Session::ReadCallBack(const boost::system::error_code& ec, std::size_t bytes_transferred) {
if (ec) {
std::cerr << "Error during async read: " << ec.message() << std::endl;
return;
}
_recv_node->_cur_len += bytes_transferred;
if (_recv_node->_cur_len < _recv_node->_total_len) {
_socket->async_read_some(
asio::buffer(_recv_node->_msg + _recv_node->_cur_len, _recv_node->_total_len - _recv_node->_cur_len),
[this](const boost::system::error_code& ec, std::size_t bytes_transferred) {
this->ReadCallBack(ec, bytes_transferred);
});
} else {
// 数据读取完成
_recv_pending = false;
_recv_node = nullptr;
}
}
2.4 基于 async_receive 的封装
实现逻辑:
- 初始化接收缓冲区,调用
async_receive一次性读取数据。
代码:
void Session::ReadAllFromSocket() {
if (_recv_pending) return;
_recv_node = std::make_shared<MsgNode>(RECVSIZE);
_socket->async_receive(
asio::buffer(_recv_node->_msg, _recv_node->_total_len),
[this](const boost::system::error_code& ec, std::size_t bytes_transferred) {
this->ReadAllCallBack(ec, bytes_transferred);
});
_recv_pending = true;
}
void Session::ReadAllCallBack(const boost::system::error_code& ec, std::size_t bytes_transferred) {
if (ec) {
std::cerr << "Error during async receive: " << ec.message() << std::endl;
return;
}
_recv_node->_cur_len += bytes_transferred;
// 数据读取完成
_recv_pending = false;
_recv_node = nullptr;
}
3. 实际应用场景:网络通信服务
3.1 服务端示例
逻辑:
- 接收客户端连接。
- 使用封装的异步读写函数进行数据收发。
代码:
void StartServer(asio::io_context& io_context, short port) {
auto acceptor = std::make_shared<asio::ip::tcp::acceptor>(io_context, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port));
auto socket = std::make_shared<asio::ip::tcp::socket>(io_context);
acceptor->async_accept(*socket, [socket](const boost::system::error_code& ec) {
if (!ec) {
auto session = std::make_shared<Session>(socket);
session->ReadFromSocket(); // 开始接收数据
}
});
io_context.run();
}
3.2 客户端示例
逻辑:
- 连接服务端。
- 使用封装的异步读写函数与服务端通信。
代码:
void StartClient(asio::io_context& io_context, const std::string& host, short port) {
auto socket = std::make_shared<asio::ip::tcp::socket>(io_context);
asio::ip::tcp::resolver resolver(io_context);
asio::connect(*socket, resolver.resolve(host, std::to_string(port)));
auto session = std::make_shared<Session>(socket);
session->WriteToSocket("Hello, Server!");
session->ReadFromSocket(); // 等待服务端响应
io_context.run();
}


449

被折叠的 条评论
为什么被折叠?



