Boost.Asio 同步读写操作详解
Boost.Asio 是一个高效的 C++ 网络和底层 I/O 库,提供了多种 API 用于同步和异步数据传输。本文将详细介绍同步操作及其具体实现,包括 write_some、send、write、read_some、receive、read 和 read_until 等。
1. 同步写:write_some
功能: 将指定数量的字节写入到套接字。如果发送缓冲区已满,则只写入一部分数据并返回已写字节数。
特点:
- 需要循环调用才能确保全部数据写完。
- 每次写入的数据量由缓冲区的容量决定。
代码示例:
void write_to_socket(asio::ip::tcp::socket& sock) {
std::string buf = "Hello World!";
std::size_t total_bytes_written = 0;
while (total_bytes_written != buf.length()) {
total_bytes_written += sock.write_some(
asio::buffer(buf.c_str() + total_bytes_written,
buf.length() - total_bytes_written));
}
}
实际例子:
用于发送较大数据时,比如将日志分块写入到远程服务器。
2. 同步写:send
功能: 一次性发送缓冲区中的数据。如果缓冲区已满,则会阻塞,直到发送缓冲区有空闲。
特点:
- 操作简单。
- 自动处理缓冲区已满的情况。
代码示例:
int send_data_by_send() {
asio::ip::tcp::socket sock(ios, ep.protocol());
sock.connect(ep);
std::string buf = "Hello World!";
int send_length = sock.send(asio::buffer(buf.c_str(), buf.length()));
if (send_length <= 0) {
std::cout << "send failed" << std::endl;
return 0;
}
return 0;
}
实际例子:
实时数据传输场景,如发送传感器数据到服务器。
3. 同步写:write
功能: 类似于 send,将整个缓冲区内容发送到对端,阻塞直到数据发送完成。
特点:
write是更高层的封装。- 可与
asio::write配合用于流式操作。
代码示例:
int send_data_by_write() {
asio::ip::tcp::socket sock(ios, ep.protocol());
sock.connect(ep);
std::string buf = "Hello World!";
int send_length = asio::write(sock, asio::buffer(buf.c_str(), buf.length()));
if (send_length <= 0) {
std::cout << "send failed" << std::endl;
return 0;
}
return 0;
}
实际例子:
批量文件数据发送,例如将完整文件发送到云端。
4. 同步读:read_some
功能: 读取指定数量的字节。如果读取缓冲区为空,则会阻塞。
特点:
- 返回读取的实际字节数。
- 通常需要循环调用,直到读取到完整数据。
代码示例:
std::string read_from_socket(asio::ip::tcp::socket& sock) {
const unsigned char MESSAGE_SIZE = 7;
char buf[MESSAGE_SIZE];
std::size_t total_bytes_read = 0;
while (total_bytes_read != MESSAGE_SIZE) {
total_bytes_read += sock.read_some(
asio::buffer(buf + total_bytes_read,
MESSAGE_SIZE - total_bytes_read));
}
return std::string(buf, total_bytes_read);
}
实际例子:
读取固定长度的命令响应,如从数据库或设备返回的状态码。
5. 同步读:receive
功能: 一次性同步接收缓冲区中的数据。如果缓冲区为空,则会阻塞。
特点:
- 操作简单。
- 阻塞直到数据被完全接收或缓冲区满。
代码示例:
int read_data_by_receive() {
asio::ip::tcp::socket sock(ios, ep.protocol());
sock.connect(ep);
char buffer_receive[BUFF_SIZE];
int receive_length = sock.receive(asio::buffer(buffer_receive, BUFF_SIZE));
if (receive_length <= 0) {
std::cout << "receive failed" << std::endl;
}
return 0;
}
实际例子:
适用于接收固定格式的数据包,例如 IoT 设备发送的心跳包。
6. 同步读:read
功能: 类似于 receive,但提供更高级的封装,可以自动处理缓冲区管理。
特点:
- 一次性读取到缓冲区满或数据读取完成。
- 适合处理较大的数据块。
代码示例:
int read_data_by_read() {
asio::ip::tcp::socket sock(ios, ep.protocol());
sock.connect(ep);
char buffer_receive[BUFF_SIZE];
int receive_length = asio::read(sock, asio::buffer(buffer_receive, BUFF_SIZE));
if (receive_length <= 0) {
std::cout << "receive failed" << std::endl;
}
return 0;
}
实际例子:
传输大型文件或图片数据时的分块接收。
7. 同步读:read_until
功能: 一直读取数据,直到遇到特定字符(如换行符 \n)。
特点:
- 适合处理基于分隔符的数据流。
- 自动管理缓冲区,并返回分隔符前的数据。
代码示例:
std::string read_data_by_until(asio::ip::tcp::socket& sock) {
asio::streambuf buf;
asio::read_until(sock, buf, '\n');
std::string message;
std::istream input_stream(&buf);
std::getline(input_stream, message);
return message;
}
实际例子:
适用于实时聊天应用的消息接收,或日志服务器按行读取客户端日志。
总结
- 写操作:
write_some: 低级别,需要循环调用。send和write: 高级别,一次性发送。
- 读操作:
read_some: 低级别,需要循环调用。receive和read: 高级别,一次性读取。read_until: 按分隔符读取数据流。
Boost.Asio 提供了丰富的同步 API,可以根据具体需求灵活选择使用,适用于各种网络应用场景。


3411

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



