1.核心流程
1.1.服务端视角
1.1.1.服务启动
流程
- 准备主EventLoop对象
- 准备一个支持业务处理的BussinessServer,含TcpServer成员。TcpServer初始化。
- TcpServer启动
- 创建监听描述符
- 注册可读监控
- 设置新连接事件回调,设置收包回调
- TcpServer配置的线程数大于0时,依次启动关联的工作线程,运行线程的事件循环。
- 提供一个线程运行EventLoop的事件循环
此时,服务侧可以接收外部连接请求,主事件循环和内部工作线程启动运行。
1.1.2.被动连接建立
流程
分成可读事件处理和异步任务执行两阶段
监听套接字可读事件处理
- 监听套接字可读事件处理,accept取出套接字
- 回调到TcpServer层,回调处理中:
- 分配EventLoop(EventLoop和线程绑定,也即将套接字分配到了某个线程)
- 产生基础连接对象,注册基础对象到TcpServer下被动连接对象集合。
- 设置基础连接的连接事件回调,消息回调,关闭回调
- 向关联EventLoop投递异步任务
异步任务执行
- 注册可读事件监控
- 引发连接事件回调
- 业务层连接事件回调处理
1.1.3.被动连接数据接收&业务包处理
流程
- epoll_wait产生套接字可读事件
- 可读事件处理
- 若读到有效数据,引发一次收包回调
- 业务层收包回调中需处理完整包识别,构成一个完整包时完整包业务处理,接收缓存更新
- 若读到0,引发工作线程内连接关闭
- 若读到有效数据,引发一次收包回调
评价
- 业务层单个收包回调需要处理的事情过多,易用性不佳
- 完整包识别
- 完整包的业务处理
- 接收缓存更新
- 一次收到多个包时,多个包的拆分
- 接收缓存底层基于std::vector,需要以来拷贝转移/拷贝扩容等方式在空间不足时,容纳接收数据,效率不高。
- 可读事件中,提供一块临时缓存,读到临时缓存的内容需拷贝到接收缓存效率不高
1.1.4.被动连接数据发送处理
流程
分为任务投递和异步任务执行两个阶段
异步发送任务投递
- 连接状态检测,若检测通过,则继续。
- 投递异步发送任务
异步发送任务处理
- 若积压数据为0,直接写入套接字发送缓存
- 若存在剩余数据,剩余数据拷贝到积压缓存
- 若积压缓存不为0且尚未注册可写监控,注册可写监控
- 若写入错误,工作线程内关闭连接
评价
- 发送过程产生多次拷贝转移效率不佳
- 异步投递时,产生一次数据拷贝
- 异步发送中剩余数据存储到积压缓存产生一次数据拷贝
- 积压缓存底层基于std::vector,需要基于拷贝转移/拷贝扩容在空间不足时接纳新数据,效率不佳
- 同一工作线程所有关联套接字的异步任务投递,共用一个线程级任务队列,锁竞争不佳
1.1.5.连接关闭
流程
连接关闭可以细分为三种类型:
- 工作线程下,网络库内部关闭
- 工作线程下,业务回调关闭
- 非工作线程下,业务侧关闭
网络库内部关闭
- 设置状态为关闭
- 取消事件监控
- 引发关闭回调
- 业务层连接关闭回调
- 引发内部关闭回调
- 从服务对象被动连接映射中移除此被动连接
- 从复用器对象移除关联Channel
业务回调关闭
关闭处理
- 若为连接状态,设置状态为关闭中
- 投递异步关闭任务
异步关闭任务
- 处理流程为网络库内部关闭流程
非工作线程下,业务侧关闭
关闭处理
- 设置状态为关闭中
- 投递异步关闭任务
异步关闭任务
- 处理流程为网络库内部关闭流程
1.2.服务视角下评价
并发安全
- 被动连接建立,数据接收,收包回调,数据发送,连接关闭均放在单个工作线程,串行化执行。并发安全。
资源管理评价
- TcpServer/主EventLoop生命期由业务侧管控
- 基础连接对象:
- 生命开始:监听套接字可读事件处理中,TcpServer回调中产生,记录到服务对象连接映射。
- 生命结束:连接关闭中执行了从服务对象映射中移除连接+业务层不再持有任何此连接智能指针。
- 内部功能工作线程
- 生命开始:TcpServer执行start
- 生命结束:TcpServer执行stop后析构
性能评价
- 接收过程及接收缓存性能不佳
- 发送过程及发送缓存性能不佳
- 任务投递共有线程级任务对象,锁竞争较大