网络编程与应用实践

13k 词

同步与异步模式简介

同步

  • 同步模式下,程序会等待某个操作完成后再继续执行后续代码
  • 典型场景:阻塞式 socket 通信,read/write 操作会阻塞线程直到数据收发完成
  • 优点:编程简单,逻辑清晰,易于理解和调试
  • 缺点:效率低,无法充分利用多核资源,容易造成线程阻塞,难以支撑高并发
void session(socket_ptr sock){
  for (;;) {
    char data[MAX_LENGTH];
    size_t length = sock->read_some(boost::asio::buffer(data, MAX_LENGTH), error);
    // ...处理数据...
    boost::asio::write(*sock, boost::asio::buffer(data, length));
  }
}

异步

  • 异步模式下,操作会立即返回,实际的读写操作在后台进行,完成后通过回调函数通知主程序
  • 典型场景:事件驱动的高性能服务器,利用回调机制处理 I/O
  • 优点:高并发、资源利用率高、适合大规模网络服务
  • 缺点:编程复杂,回调嵌套多,生命周期管理难度大
void Session::Start() {
  _socket.async_read_some(boost::asio::buffer(_data, max_length),
    std::bind(&Session::handle_read, this, ...));
}

Boost.Asio 网络库使用

核心组件

  • io_context:所有异步操作的核心,事件循环。
  • socket:封装 TCP/UDP 套接字。
  • acceptor:服务器端用于监听和接受连接。
  • buffer:数据缓冲区。
  • error_code:错误处理。

同步模式下的典型流程

  1. 创建 io_context
  2. 创建 acceptor 并绑定端口
  3. 循环接受连接,创建 socket
  4. 阻塞读写数据

异步模式下的典型流程

  1. 创建 io_context
  2. 创建 acceptor,异步接受连接
  3. 每个连接创建 Session 对象,异步读写
  4. 通过回调函数处理数据和连接生命周期

开发注意点:

  1. ​ 异步模式下常用 std::shared_ptrenable_shared_from_this 管理 Session 对象生命周期,防止回调时对象被提前销毁。
  2. ​ TCP 是流协议,消息边界不固定,需自定义协议头解决粘包问题,一般用tlv协议,或者应用层http来拆包,下面的例子直接用2字节表示后面数据的大小

一个asio异步echo服务器示例

这里代码写的有点耦合了,Session类应该另起一个源文件,清楚一点。

此外,这里的async_read_some函数调用时不限制长度,造成了切包时的复杂处理,可以用async_read函数来指定长度,较为方便直观,这个api封装了async_read_some,免去手动划分长度。

改进:增加IOservice多线程处理消息请求,并且把逻辑层和网络接收层解耦

graph TD
A[服务端启动入口]
B[主 io_context]
D[Server acceptor 监听端口]
E[AsioIOServicePool 线程池]
F[GetIOService 轮询分配]
G[Session socket]
H[LogicSystem 业务队列]
I[JsonClient 客户端]

A --> B
A --> E
E --> D
I --> D
D --> F
F --> G
G --> H
H --> G