Skip to content

betterpig/WebServer

Repository files navigation

微型web服务器程序(more C++ version)

C++ & HTML

单线程IO复用+多线程业务处理:

  • 主线程负责接受连接和读写,工作线程负责解析处理请求(proactor)->读写并发数为1,即使业务处理很快,入口(读)和出口(写)只有一个,是瓶颈
  • 或者主线程只负责接受连接,工作线程负责读写和解析处理请求(reactor)->读写并发数为n(工作线程个数),每个工作线程都是出入口,比proactor好一点

使用方法

环境

  • Ubuntu 18.04
  • MySQL 5.7.31

修改程序

  • 将main.cc中数据库连接池初始化参数修改为你自己的数据库用户名、用户密码和数据库名称

    connpool->init("localhost",0,"root","123","db",5);

  • 将http_conn.cc文件中的html文件所在的根目录改成你系统中该root文件夹所在路径

    const char* doc_root="/home/sing/code/fight/my_web_server/root";

编译

在Makefile所在文件夹运行命令行

make

运行

在程序所在文件夹运行命令行,其中ip改成你电脑的IP,端口改成任意不冲突端口即可(不用加[])

./server [your ip] [port]

服务器架构

半同步半反应堆式:主线程负责接受新连接和网络数据读写,工作线程只负责解析和处理客户请求

使用到的技术

  • 定时器(基于升序链表)
  • 日志(基于阻塞队列)
  • 线程池
  • 线程间通信:信号量、互斥锁、条件变量
  • 数据库和连接池
  • I/O复用(epoll)
  • 统一事件源(socketpair管道)

主要逻辑

主线程 epoll监听所有事件

  • 监听描述符可读->初始化该连接描述符对应的客户对象,添加该连接的定时器
  • 异常事件->关闭连接
  • 信号管道可读
  • 终止信号->将终止服务器标志设为true
  • SIGALRM信号->将timeout标志设为true,所有就绪事件处理完毕后将调用定时器的Tick函数,清理到期的定时器
  • 连接描述符可读->
    1. 主线程读取客户数据,放在客户对象中
    2. 将客户对象指针放入请求队列中
    3. 调整定时器
  • 连接描述符可写->将客户对象中写缓冲区的数据发送给客户端

工作线程

  1. 阻塞等待请求到来
  2. 从请求队列中取出客户对象指针,对其中的读缓冲区内容进行解析和处理
  3. 将响应写入客户对象的写缓冲区中,使epoll改为监听该连接描述符上的可写事件

改进

  1. 定时器容器整合:在原有基于升序链表的定时器容器类的基础上,加上了时间堆和时间轮。利用简单工厂模式,实现了三种定时器容器在使用方法上的统一。现在,只需要给定类型,就可以生成相应的定时器容器,完成定时器的添加、删除、调整和Tick。
  2. 增加了session功能,通过unordered_map存储会话信息,包括过期时间、是否验证通过等,实现了客户连接在登录后一段时间内不需要重复登录的功能; 增加了注销登录按钮,使用户通过同一个浏览器可以登录不同账户。
  3. 主线程与工作线程、其他线程与日志线程,都统一通过阻塞队列进行通信。将原本的线程detach属性去掉,改为由主线程进行回收。当需要结束程序时,主线程会在析构函数将stop标志位置为true,并调用条件变量的NotifyAll函数唤醒阻塞线程,它们将检测到结束标志并安全退出。
  4. 通过宏和条件编译增加了reator模式,即把网络I/O工作交给工作线程,主线程只负责接受连接,在请求到来时往任务队列中加入任务。

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published