# Epoll高并发服务器 **Repository Path**: JiangRRRen/EpollHighConcurrencyServer ## Basic Information - **Project Name**: Epoll高并发服务器 - **Description**: 基于epoll机制的高并发服务器,开发用于传感器网络交互数据,也可用作其他用途 - **Primary Language**: C - **License**: AFL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 5 - **Forks**: 3 - **Created**: 2019-07-29 - **Last Updated**: 2023-10-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Epoll高并发服务器 ## 项目简介 基于Linux下的Epoll机制,设计的一种适用于高并发场景下的服务器。该服务器目前用于电力系统传感器网络交换数据,经过修改后可适用于其他场景。 ## 功能特性 - 利用Epoll机制提高监视文件描述符限制,避免Select中大量复制的句柄数据结构,产生巨大开销。监听时不需要遍历所有文件描述符,提高程序执行效率 - 设计了Free,Poll,RW三个链表,用于管理服务器内存开支,能有效避免服务器上内存的频繁开辟和浪费 ## 环境依赖 本项目是基于Centos7环境下开发,使用MySQL数据库5.6版本 ## 部署步骤 项目源码分为服务器部分和客户端测试部分。 使用时需要先打开MyServer.h头文件修改所连数据库的信息,如果有必要还需要修改所有结构体,以适应数据库。 如果做测试用,可以使用本人的测试数据库,里面包含了电力系统监控的一些测试数据。 配属完毕后,使用Makefile生成可执行文件,之后在Linux系统下执行即可。下图为服务器成功启动后的结果: ![]( http://pub694cho.bkt.clouddn.com/20190729095314.png) 服务器启动后可以使用本人提供的测试程序client2进行测试,客户端测试程序启动后,客户端显示如下,成功获取数据库存储的最新一条传感器数据,并打印出房间ID。 ![]( http://pub694cho.bkt.clouddn.com/20190729095652.png) 服务器界面如图: ![]( http://pub694cho.bkt.clouddn.com/20190729095755.png) MySQL数据库,查到了数据 ![]( http://pub694cho.bkt.clouddn.com/20190729103546.png) ## 原理结构描述 ![]( http://pub694cho.bkt.clouddn.com/20190729100110.png) Server程序导图如上图所示,其核心作用原理是3类线程+3条链表。3类线程完成不同的工作,3条链表用于管理内存和进程间通信。 ### 3条链表 服务器用采用了3条链表来管理内存和进程间通信。 - Free链表 在主线程中开辟空间,作为内存管理的基本要素,链表中的节点表示空余内存,可供后面的操作取用。 - Poll链表 与客户端建立连接后,从Free链表中取一个节点,向其添加信息,作为一个**令牌**,将这个令牌放入Poll链表,起到进程间通信的作用。 - RW链表 从Poll链表取出令牌放入RW链表,读出命令要求,进行操作,操作完后放回Poll链表或者清空回收到Free链表。 ### 3类线程 整个服务器的线程分为三种:主线程(1条),交互子线程(1条),读写子线程(4条) - 主线程的主要工作分为两部分:初始化信息(包括内存,socket,子线程等等)和监听客户连接。 - 交互子线程负责客户端和服务器的沟通(主线程监听到客户端的请求后建立连接,交互子线程负责维护管理这个连接),与客户端的读写操作都在交互子线程中完成。 - 读写子线程负责数据库的读写,使用阻塞的方式,不断去查询RW链表中是否有待处理的令牌,如果有就处理,如果没有就一直询问。 ### 工作流程 工作流程分为两种:有数据返回和无数据返回 假设现在主线程已初始化完毕。 主线程:客户端1向服务器发送链接请求-->触发ListenEpoll->客户端接收并创建socket句柄-->主线程从Free链表取一个令牌将客户端链接信息写入,然后放入poll链表-->向ClientEpoll注册一个事件 交互子线程:客户端1连接完毕后发送请求-->触发ClientEpoll-->交互子线程从poll链表取出令牌,读取连接管道信息-->根据socket信息从客户端读取或发送数据-->将收到的数据写在poll令牌中放入RW链表 读写子线程: 阻塞的方式一直查询RW链表-->从RW链表中读到新令牌->根据要求操作数据库 此时客户端需求是向数据库写命令(无数据返回)则读写子线程操作完毕后清空令牌,回收到Free链表;如果是从数据库读数据(有数据返回),操作完后将令牌送到Poll链表中(交互子线程负责根据Poll链表的令牌向客户端通信),通过交互子线程将需要返回的数据发送到客户端。