昨天我用多线程加上accept和read两个阻塞函数编写了一个基本能处理多个连接的服务端;
但我们在理解了这样的服务器设计之后,凭常识可以很轻易地知道这样的服务器性能并不好;
性能不好的原因是我们监听是否有新连接的accept和每个监听是否有新消息的read都要独立使用一个线程;
我们是否有某种方法,将这些accept和read放在一起监听呢?来了新消息再用相对应的socket来进行处理呢。
epoll就是这样的一种处理模型,这种模型叫做事件模型,监听一堆的事件,然后发生某些事情时根据监听的事件,处理对应的函数。
我们要使用epoll的话,首先将库包含,同时处理函数稍微修改一点,(多线程暂时不用,先注释掉):
随后我们创建一个epoll,按照它的语法初始化它的一些参数(主要是我们的socket和监听我们socket的事情是读还是写);
随后写一个循环,用epoll_wait等待网络传过来的信号,如果有对应的信号就处理(连接信号就用accept接收并创立连接,收到消息就用我们的函数处理);
这里的epoll_wait最后一个参数是设置延迟等待时间的,假如设置为负数,那就是不等待,一直监听,直到等到了一个连接或者消息发送的事件,随后执行后面的代码。
这样的话,epoll_wait就变成了实质上的阻塞函数,假如我们要执行一些连接管理的事情(比如客户端太长时间没有消息就断开连接),就会因为一直卡在epoll_wait而执行不了。
因此我们加上延迟等待时间,设置为1000ms。
同时,我们来完成我们的连接管理:
我们需要一个数据结构来保存我们连接好的socket和最后消息时间,并且在每次循环中将超过一定时间没有发送消息的连接给断掉。
这个数据结构要能适应每次客户端发送消息时候,对于socket最后消息时间的更新,同时我们每次循环的时候对其进行遍历,断开超时的连接以节省服务器资源;
我们使用map,map的底层是一个红黑树实现,对于更新和遍历都是比较方便的。(数组和最大堆都不方便更新最后消息时间):
我们需要做的是加入时间函数,并且在创建连接的时候增添键值对,同时在处理消息事件的时候同步更新时间,然后在每次循环过程中,处理超过一段时间没消息的连接: