这里是基于epoll+线程池的高并发服务器github源码,相对算是比较稳定的版本了,界面可能有点丑陋,功能都可以使用!也可扩展,读者可自行修改功能或者学习参考!
文件说明和框架介绍
- 说明一下里面文件的作用吧!
serverHttp文件存的是服务器端的资源文件!程序刚开始调用chdir函数将工作目录切换到该目录下!
epfd.h头文件 用类封装epoll句柄的初始化动作!
func.h 和 func.cpp 实现发送响应头,处理各种请求,字符编码问题,文件格式识别的函数声明头文件和实现文件!其中实现的功能辅助线程任务的完成!
task.h 线程池进行任务调度的功能类!
threadPool.h locker.h类,将线程池使用模板类封装起来,用的时候加上头文件即可!locker.h是操作互斥锁和环境变量的头文件,提供给线程程池使用!
- 实现结构
- 基于epoll i/o多路复用的Reactor模型
- 该项目是基于同步非阻塞I/O的实现,服务器和浏览器短的套接字都要初始化设置为非阻塞模式,使用epoll检测的事件为可读事件,读数据使用边缘触发模式.
注意事项总结
-
设置接收缓冲区
-
首先得定义接收缓冲区的大小,基于TCP是流协议的考虑,无论是发送还是接收数据,都应将定长数据包作为数据交互的载体.
-
关于地址复用
-
作为服务端,为套接字选项设置地址复用是比较重要的,因为要是假设服务器真的挂了我们必须使用
原端口和IP
重新与之前客户端建立连接,这个应该不难理解,所以使用地址复用选项极为重要! -
在套接字端设置如下:
int flag = 1 ;//注意这里一定设置为非0,否则无效. setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag) ) ;
-
-
关闭客户端套接字
- 我对于关闭客户端套接字描述符的处理方法是在将其加入到epoll之前设置延迟关闭描述符SO_LINGER选项,将struct linger中的两个属性设置为0,0(我在服务器端套接字描述符也设置了该选项),即就是在关闭了客户端套接字之前检查要是还有数据没完的话,尽量将其中的数据发完再关闭!
- 客户端和服务器每次的数据交互都需要建立一个新连接!每次处理完GET请求或者POST请求后,都要及时将浏览器套接字描述符从epoll树上去掉,再关掉浏览器套接字描述符.
-
服务器GET请求和POST请求的处理
- 我的服务端接收浏览器请求的方式是:当检测到有可读事件时,使用线程池分配子线程处理.在子线程中,使用长度为4096的缓冲区buf(为string对象) 来 recv浏览器的请求数据,当recv返回值等于4096的字节的话,使用使用
buf+=buf
将数据存起来,继续读数据… 当recv的返回值小于4096或者等于0时表示已经将请求数据读取完成. - 接下来我们的任务是分析buf中的内容
- 是GET请求的话,直接将GET请求的文件发给浏览器.
- 是POST请求的话,将用户的输入解析出来,并fork子进程,切换到提前设置好的逻辑处理进程并将用户的信息传到该进程中进行处理,将处理结果发送给浏览器.
- 我的服务端接收浏览器请求的方式是:当检测到有可读事件时,使用线程池分配子线程处理.在子线程中,使用长度为4096的缓冲区buf(为string对象) 来 recv浏览器的请求数据,当recv返回值等于4096的字节的话,使用使用
服务器功能比较简单,其他的难点倒是没什么了,就总结至此了!