【S1mpleServer】适合新手的C++Web项目----多线程网络库(支持Http解析)

目录

  • 前言
  • 项目简介
  • 系统框架
  • 运行结果
  • 测试结果

前言

闭关多日,仔细阅读了muduo的源码,有一点开窍的感觉,仿照着牛客上天线宝宝大佬的服务器写了一个C++11的网络库,并在上面跑了一个数独求解的HTTP服务器。
这篇博客记录一下这个项目的构建过程,也对这段时间的学习做一个总结。
github链接:https://github.com/Supredan/S1mpleServer
测试页:数独求解(跑在我买的服务器上,一旦我用服务器干别的事情就会宕机哈 -_-!)

项目简介

C++的服务器当然是要往高并发的方向上走,网上已经有很多开源的高性能网络库,如Libevent、muduo、handy、oatpp还有重量级选手Boost的ASIO、ACE等等。对于新手来说,前几个都是很好的学习对象,我先大体看了看Libevent,但是由于它用的是c,而我还是想锻炼一下C++的能力,所以重点看的其实是muduo。陈硕大佬的水平当然不用怀疑,赶快拜读了《Linux多线程服务端编程:使用muduo C++网络库》,只是我这个菜鸡看到满天飞的boost整个人都不好了。

当然现在最新版的muduo2.0已经用上了c++11,但是还是有一些boost残留在其中,而且muduo考虑到了方方面面,导致在书中写的5000行以内的网络库现在貌似已经不止5000行了。

所以我参考muduo和牛客网上的天线宝宝大佬的程序写了一版简化版的muduo,我尽量将其写成muduo那样的库,然而目前的第一版还没有做到如此分离,这是之后优化的目标之一。

本项目的特性:

  • C++11编写的Web服务器库,利用非阻塞IO和IO复用技术,实现了one loop per thread + thread pool模型的并发连接
  • 使用timerfd处理定时事件,存储的数据结构采用时间堆
  • 使用eventfd进行线程唤醒,能够跨线程的调用回调函数
  • 使用双缓冲技术实现异步日志系统
  • 实现了长连接和管线化

虽然这个项目针对muduo进行了代码的简化,但是muduo库的优良特性都继承了下来,下面来看一下设计的思路。

系统框架

先贴一张muduo的框架图,可以看到即使最核心的模块也有如下7.8个,更不提没画上去的日志类、线程池、定时器等等,让我这个萌新当时看得好苦。。。

跑偏了,话说回muduo它的核心思想就是一个主线程负责分发,多个工作线程负责处理业务,而且每个线程都运行一个循环,并不是处理完就结束工作。我们利用muduo的核心思想,实现了一个简单的服务器,即使没有看过muduo,也不影响这篇博客的阅读,下面就让我们开始吧!
【S1mpleServer】适合新手的C++Web项目----多线程网络库(支持Http解析)_第1张图片
往下说之前默认读者至少看过UNP,有过基本echo服务器的编写经验,如果没有希望你先照着UNP熟悉一下基础API再来看,在这等你。

本项目主要有以下几个类:
对外可见的:

  • EventLoop:事件循环,也即大家熟知的Reactor,负责事件的分发,每个拥有一个Epoll和至少一个Channel。
  • Server:主服务器类,封装一个服务器的各种参数。

内部实现:

  • Channel:负责响应和接收IO事件,可以想象为socket的包装,它含有socket的回调函数,在各个类间传递数据。
  • Epoll:epoll的包装类
  • EventLoopThreadPoll:线程池的最上层封装
  • Logging:日志的最上层封装类
  • Timer:时间类
  • HttpData:http数据处理类

记住上面几个类就够读代码了,当然还有一些细节的实现类。
我们来看一下项目具体跑起来的样子:

    EventLoop mainLoop;
    Server SudokuServer(&mainLoop, threadNum, port);
    SudokuServer.start();
    mainLoop.loop();

4句话就能运行这个服务器,下图是此时服务器的状态。
【S1mpleServer】适合新手的C++Web项目----多线程网络库(支持Http解析)_第2张图片
首先创建了一个mainloop的实例,正如其名它是主循环,默认有一个channel类包含一个wakeupfd,一个Epoll类用来注册epoll事件。
然后创建了一个SudokuServer的实例,它和主循环相对应,同时默认有一个acceptchannel负责listenfd的新建连接,还有一个线程池负责分发事件。
之后运行start函数让各个模块初始化,最后运行主循环。

当一个新连接到来,状态如下图所示:【S1mpleServer】适合新手的C++Web项目----多线程网络库(支持Http解析)_第3张图片
我之前写过一篇tinyhttpd的文章,如果你读过那个源码就会发现这个工作线程其实就是将其分布到了不同的类中,各司其职。

subloop是工作线程的循环,httpdata充当了各个类的数据处理中心,connfd如果你熟悉UNP的各个例子,就会知道它是新连接的socket,数据从connfd送往httpdata类解析,回调函数通过channel最终再调用httpdata中的readhandle处理。

这里要注意subloop同样拥有一个epoll,connfd是注册到它的上面。

运行结果

来看看一个简单的运行效果吧!使用最原始的html的丑陋首页和交互性极差的输入方式,哈哈!
前端的内容都不是重点(为自己找一个借口),可以看到数独计算的功能已经实现了,http请求得以解析。
【S1mpleServer】适合新手的C++Web项目----多线程网络库(支持Http解析)_第4张图片【S1mpleServer】适合新手的C++Web项目----多线程网络库(支持Http解析)_第5张图片

测试结果

使用webbench进行的本地测试,下图是在开启4线程,1000个连接,使用keep-Alive方式的结果,全部请求都成功,吞吐量在38MB/s。
【S1mpleServer】适合新手的C++Web项目----多线程网络库(支持Http解析)_第6张图片

你可能感兴趣的:(Web)