江存
基于Linux的2种HTTP服务器实现与对比分析
江存
(四川大学计算学院,成都 610000)
探讨Linux环境下的多线程并发编程的问题,介绍采用C语言实现基于动态线程池模式的简单服务器与基于epoll+多线程模式的简单服务器,采用Webbench进行压力测试,并对结果做出分析与思考。
线程池;epoll;并发编程;HTTP
HTTP协议是互联网中重要的协议,Web浏览器、服务器和相关的应用程序都是HTTP互通的,对其进行研究十分有必要。本文着重研究分析了HTTP服务器的设计与实现方式,一个设计架构良好的服务器需要高效稳定可扩展性,尽可能满足多的任务请求。本文着重设计实现了态线程池模式和epoll加多线程模式,并对其进行分析。
1.1 HTTP协议简介
http服务器是基于TCP协议的应用层协议,名为超文本传输协议。Web客户端与服务器端进行数据传输就是依靠HTTP协议实现的。它是全球因特网使用的公共语言。
通常,一个客户端与服务器建立连接之后,会发送一个请求个服务器,请求报文的格式一般为:请求起始行、请求首部字段和主体部分。服务器在将报文解析出来,在发送一个响应报文,和请求报文类似,也分为三个部分:响应起始行、响应首部、响应主体。
请求报文格式如下:
<method> <reque-uri> <version>
<headers>
<entity-body>
响应报文格式为:
<version> <status> <reason-pharse>
<headers>
<entity-body>
●方法(method)
客户希望服务器对资源进行的动作。如get,post等方法。
●请求 URL(request-URL)
所请求的资源地址。
●版本(version)
所使用的HTTP协议版本。
●状态码(status)
这三位数字描述了请求过程中所发生的情况。
●原因短语(reason-phrase)
数字状态码的可读版本,包含行终止序列的所有文本。
●首部(header)
可以有零个或者多个首部,每个首部包含一个名字,后面接一个逗号,然后是个可选空格,然后是一个值,最后是一个CRLF。
●实体的主体部分(entity-body)
包含任意数据组成的数据块。并不是所有的报文都包含实体的主体部分,有时报文以一个CRCL结束。
1.2 HTTP服务器架构分析与设计
(1)基于线程池的HTTP服务器
由于单个进程无法同时处理读个连接,并且无法发挥服务器多核心的优势,但是用多进程,每个进程分别处理不同的请求,又太耗费资源,所以采用多线程的模型来处理,与此同时,由于HTTP请求和响应很快,创建和销毁线程又非常的频繁,需要很大的系统资源开销,所以采用预先创建线程池来处理HTTP任务,既发挥了CPU多核心的优势又减少了不必要的系统开销。服务器工作原理如下:首先建立套接字描述符,接着绑定地址,在监听套接字看是否有连接接入,有接入就分配一个线程去处理任务。
其中线程池管理过程为:当主线程获取了一个连接后,将任务添加到线程池管理结构中的任务队列中,并检测是否需要增加线程,唤醒等待中的线程,唤醒的线程去任务队列中取下任务进行处理,处理完后继续队列任务。如此同时,单独创建一个检测线程,当满足条件后就会销毁一部分线程,以达到根据具体需求动态改变线程池大小的需求,如此往复。
(2)基于epoll加多线程的HTTP服务器架构
由于前面采用线程池模型,每个请求必须要一个线程去处理,处理完成后才会去做下一个任务,如果请求时保持型的长连接,那么很快线程池就被消耗完了,而其他的请求得不到满足。在这个问题基础上,改进了单独线程池模型的不足,采用epoll模型来,为了充分利用多核心的优势,采用了多线程加epoll模型,每个线程单独处理一个epoll对象,这样线程之间互不干扰,减少线程调度和切换的开销,同时提高了CPU的利用率。
2.1 线程池模型关键结构设计
(1)下面介绍一些必要的数据结构
●任务结点设计
(2)服务器处理步骤
图1
图2
2.2 epoll+多线程模式关键结构设计
(1)epoll主要结构如下
①连接信息结构
void add_epoll_event(int epfd,Conn*conn,int flags)函数负责向epoll对象中添加事件信息,epfd是epoll对象文件描述符,conn是连接请求信息,flags事件触发方式。
void mod_epoll_event(int epfd,Conn*conn,int flags)函数负责对epoll对象中的事件信息进行修改。
void del_epoll_event_close_fd(int epfd,Conn*conn)函数负责删除epoll对象中的事件,并且关闭套接字描述符fd。
其他创建和收集发生事件的连接直接调用系统函数epoll_create和epoll_wait函数。
(2)基于epoll的服务器处理流程图如下:
图3
笔者采用开源软件Webbench进行测试,主要采用GET方法请求,属于I/O型事件处理请求,两个模式服务器部署在同一个主机上进行测试,另一个主机每次模拟不同数量的客户端,每次测试时间30秒,测试10次,失败为止,表1是基于线程池的服务器的测试数据,表2是基于epoll+多线程的服务器的测试数据,可以看到,随着并发客户数越多,epoll效率几乎不受影响,同等条件下,当并发数超过4000时,线程池服务器就会出现请求失败的情况,而epoll服务器几乎不受影响。说明对于高并发和I/O型事件,epoll模式要由于一般的线程池模式。测试结果如下:
基于线程池服务器测试的截图和结果:
图4
图5
笔者研究了HTTP服务器原理以及实现,并且为了最大可能利用计算机资源和尽可能并发处理程序,经过比较最后选择基于线程池和epoll+线程模式两种方式进行对比测试分析,得出在不同情况下根据具体需求采用不同模型的必要性,当并发程度要求不高,二者性能将近,但是特别是在并发连接多I/O型事件请求任务下,epoll模式表现良好。一个好的服务器需要考虑很多方面,笔者才疏学浅只是在相对理想条件下进行测试,总之对此还需继续深入的研究与分析。
表1
表2
[1]W.Richard Stevens,Stephen A.Rago著.UNIX环境高级编程[M].戚正伟,张亚英,尤晋元译.北京:人民邮电出版社,2014.
[2]W.Richard Stevens,Bill Fenner,Andrew M.Ruoff著.UNIX网络编程[M].北京:人民邮电出版社,2015.
[3]David Gourley,Brian Totty,Marjorie Sayer,Sailu Reddy,Anshu Aggarwal著.HTTP权威指南[M].陈涓,赵振平译.北京:人民邮电出版社,2012.
[4]王远洋,周渊平,郭焕丽.Linux下基于Socket多线程并发通信的实现[J].微计算机信息,2009,25(5).
[5]催滨,万旺根,余小清,楼顺天.基于EPOLL机制的Linux网络游戏服务器实现方法[J].微计算机信息,2006,22(7).
[6]梁明刚,陈西曲.Linux下基于epoll+线程池高并发服务器实现研究[J].武汉轻工大学学报,2012,31(3).
Implementation and Comparison of Two Kinds of HTTP Server Based on Linux
JIANG Cun
(College of Computer Science,Sichuan University,Chengdu 610000)
Discusses the problem of multi-threaded concurrent programming in Linux environment,introduces the simple server based on dynamic thread pool mode and simple server based on epoll+multi-thread mode written in C language and Webbench is used for stress testing,fi⁃nally makes a summary of test.
Thread Pool;Epoll;Concurrent Programming;HTTP
1007-1423(2017)24-0058-05
10.3969/j.issn.1007-1423.2017.24.014
江存(1991-),男,湖北黄冈人,硕士研究生,研究方向为网络与信息安全
2017-04-27
2017-08-05