Consolexin's blog Consolexin's blog
首页
  • 算法基础

    • 图论
    • 字符串
    • 动态规划
    • 二分
    • 滑动窗口
    • 排序
  • Project

    • CppServer
  • 相关书籍

    • 现代C++编程
  • 书籍

    • SQL必知必会
    • MySQL必知必会
分类
标签
归档
GitHub (opens new window)

Consolexinhun

小学生
首页
  • 算法基础

    • 图论
    • 字符串
    • 动态规划
    • 二分
    • 滑动窗口
    • 排序
  • Project

    • CppServer
  • 相关书籍

    • 现代C++编程
  • 书籍

    • SQL必知必会
    • MySQL必知必会
分类
标签
归档
GitHub (opens new window)
  • README
  • day01-从一个最简单的socket开始
  • day02-不要放过任何一个错误
  • day03-高并发还得用epoll
  • day04-来看看我们的第一个类
  • day05-epoll高级用法-Channel登场
  • day06-服务器与事件驱动核心类登场
  • day07-为我们的服务器添加一个Acceptor
  • day08-一切皆是类,连TCP连接也不例外
  • day09-缓冲区-大作用
  • day10-加入线程池到服务器
  • day11-完善线程池,加入一个简单的测试程序
  • day12-将服务器改写为主从Reactor多线程模式
  • day13-支持业务逻辑自定义、完善Connection类
  • day14-重构核心库、使用智能指针
  • day15-重构Connection、修改生命周期
  • day16-使用CMake工程化
  • day17-使用EventLoopThreadPool、移交EventLoop
  • day18-HTTP有限状态转换机
  • day19-创建HTTP响应,实现HTTP服务器
  • day20-定时器的创建使用
  • day21-服务器主动关闭连接
  • day22-初步涉及日志库,定义自己的输出流LogStream
  • day23-定义前端日志库,实现同步输出
  • day24-异步日志库
  • day25-更有效的缓冲区
  • day26-监听写事件
  • day27-处理静态文件,实现POST请求
  • day28-文件服务器的简单实现,文件的展示和下载
  • day29-文件的上传
  • day30-WebBench的测试
  • CppServer
consolexinhun
2025-04-20

day08-一切皆是类,连TCP连接也不例外

# day08-一切皆是类,连TCP连接也不例外

在上一天,我们分离了用于接受连接的Acceptor类,并把新建连接的逻辑放在了Server类中。在上一天我们还提到了Acceptor类最主要的三个特点:

  • 类存在于事件驱动EventLoop类中,也就是Reactor模式的main-Reactor
  • 类中的socket fd就是服务器监听的socket fd,每一个Acceptor对应一个socket fd
  • 这个类也通过一个独有的Channel负责分发到epoll,该Channel的事件处理函数handleEvent()会调用Acceptor中的接受连接函数来新建一个TCP连接

对于TCP协议,三次握手新建连接后,这个连接将会一直存在,直到我们四次挥手断开连接。因此,我们也可以把TCP连接抽象成一个Connection类,这个类也有以下几个特点:

  • 类存在于事件驱动EventLoop类中,也就是Reactor模式的main-Reactor
  • 类中的socket fd就是客户端的socket fd,每一个Connection对应一个socket fd
  • 每一个类的实例通过一个独有的Channel负责分发到epoll,该Channel的事件处理函数handleEvent()会调用Connection中的事件处理函数来响应客户端请求

可以看到,Connection类和Acceptor类是平行关系、十分相似,他们都直接由Server管理,由一个Channel分发到epoll,通过回调函数处理相应事件。唯一的不同在于,Acceptor类的处理事件函数(也就是新建连接功能)被放到了Server类中,具体原因在上一天的教程中已经详细说明。而Connection类则没有必要这么做,处理事件的逻辑应该由Connection类本身来完成。

另外,一个高并发服务器一般只会有一个Acceptor用于接受连接(也可以有多个),但可能会同时拥有成千上万个TCP连接,也就是成千上万个Connection类的实例,我们需要把这些TCP连接都保存起来。现在我们可以改写服务器核心Server类,定义如下:

class Server {
private:
    EventLoop *loop;    //事件循环
    Acceptor *acceptor; //用于接受TCP连接
    std::map<int, Connection*> connections; //所有TCP连接
public:
    Server(EventLoop*);
    ~Server();

    void handleReadEvent(int);  //处理客户端请求
    void newConnection(Socket *sock);   //新建TCP连接
    void deleteConnection(Socket *sock);   //断开TCP连接
};
1
2
3
4
5
6
7
8
9
10
11
12
13

在接受连接后,服务器把该TCP连接保存在一个map中,键为该连接客户端的socket fd,值为指向该连接的指针。该连接客户端的socket fd通过一个Channel类分发到epoll,该Channel的事件处理回调函数handleEvent()绑定为Connection的业务处理函数,这样每当该连接的socket fd上发生事件,就会通过Channel调用具体连接类的业务处理函数,伪代码如下:

void Connection::echo(int sockfd){
    // 回显sockfd发来的数据
}
Connection::Connection(EventLoop *_loop, Socket *_sock) : loop(_loop), sock(_sock), channel(nullptr){
    channel = new Channel(loop, sock->getFd()); //该连接的Channel
    std::function<void()> cb = std::bind(&Connection::echo, this, sock->getFd()); 
    channel->setCallback(cb); //绑定回调函数
    channel->enableReading(); //打开读事件监听
}
1
2
3
4
5
6
7
8
9

对于断开TCP连接操作,也就是销毁一个Connection类的实例。由于Connection的生命周期由Server进行管理,所以也应该由Server来删除连接。如果在Connection业务中需要断开连接操作,也应该和之前一样使用回调函数来实现,在Server新建每一个连接时绑定删除该连接的回调函数:

Connection *conn = new Connection(loop, sock);
std::function<void(Socket*)> cb = std::bind(&Server::deleteConnection, this, std::placeholders::_1);
conn->setDeleteConnectionCallback(cb);  // 绑定删除连接的回调函数

void Server::deleteConnection(Socket * sock){
    // 删除连接
}
1
2
3
4
5
6
7

至此,今天的教程已经结束,我们将TCP连接抽象成一个类,服务器模型更加成型。测试方法和之前一样,使用make得到服务器和客户端程序并运行。

这个版本是一个比较重要的版本,服务器最核心的几个模块都已经抽象出来,Reactor事件驱动大体成型(除了线程池),各个类的生命周期也大体上合适了,一个完整的单线程服务器设计模式已经编码完成了,读者应该完全理解今天的服务器代码后再继续后面的学习。

完整源代码:https://github.com/yuesong-feng/30dayMakeCppServer/tree/main/code/day08 (opens new window)

编辑 (opens new window)
上次更新: 2025/05/21, 06:42:57
day07-为我们的服务器添加一个Acceptor
day09-缓冲区-大作用

← day07-为我们的服务器添加一个Acceptor day09-缓冲区-大作用→

最近更新
01
6-其他操作
05-20
02
4-联结
05-20
03
7-管理
05-20
更多文章>
Theme by Vdoing | Copyright © 2019-2025 Consolexinhun | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×