这篇是基于linux高性能服务器编程:
书中说:我们可以利用定时器来处理非活动连接,服务器通常要定期处理非活动连接:给客户端发一个重连请求,或者关闭它,或者其他。linux内核中提供了对连接是否处于活动状态的定期检查机制,我们可以通过socket选项KEEPLIVE来激活它,不过使用这种方式将使得应用程序对连接的管理变得复杂。因此,我们可以考虑在应用层实现类似于KEEPLIVE的机制,以管理所有长时间处于非活动状态的连接。比如,利用alarm函数周期性地触发SIGALRM信号,该信号的信号处理函数利用管道通知主循环执行定时器链表上的定时任务---关闭非活动连接。
其下面code主要是这么实现的:
- 首先创建一个管道,其用来写入信号
- 为每个连接的客户端都分配一个定时器,设置超时时间(绝对时间),和超时回调函数(回调函数关闭连接),并将定时器加入到升序双向链表中
- 为了统一事件源,我们将信号管道的读端加入到epoll中,这样就方便监听所有客户连接和超时事件发生,然后进行处理
- 在主循环中,判断是否是信号管道的读端文件描述符,如果是超时信号,就调用超时处理函数,不过是在所有I/O事件处理完成之后
- 超时处理函数,检测定时器升序链表,若有超时事件,则调用回调函数,关闭连接,删除定时器
//定时器节点
class util_timer
{
public:
time_t expire; /* 任务的超时时间 */
void (*cb_func)(cli_data* ); /* 任务回调函数 */
util_timer* pre;
util_timer* next;
cli_data *user_data;
util_timer() : pre(NULL), next(NULL) {}
};
//用户数据结构
struct cli_data
{
sockaddr_in addr;
int sockfd;
char buf[BUFFER_SZ];
util_timer* timer;
};
主函数:
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <libgen.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <errno.h>
#include "lst_timer.h"
#define ERRP(con, ret, ...) do \
{ \
if (con)