https://blog.csdn.net/freeelinux/article/category/6338658
网络编程中应用层的定时器是很有必要的,这可以让服务端主动关闭时间很久的非活跃连接。
另外一种解决方案是TCP的keepalive (它的原理应该知道:如果客端连接上,但什么都不做,keepalive是毫无办法的,它只能一定时间后不断的向客户端发送心跳包。),但它只能检测真正的死连接,即客端主机断电,或者网线被拔掉这种情况。(上面的情况他无法解决即 非活跃的连接)
#ifndef LST_TIMER #define LST_TIMER #include <time.h> #define BUFFER_SIZE 64 class util_timer;//前项申明 struct client_data { sockaddr_in address; int sockfd; char buf[ BUFFER_SIZE ];//读取缓存 util_timer* timer;//定时器 }; class util_timer//定时器类 是用来初始化每个节点的这个很重要 {//里面包含成员client_data的指针 public: util_timer() : prev( NULL ), next( NULL ){} public: time_t expire; void (*cb_func)( client_data* ); client_data* user_data;//回调函数处理的客户数据,由定时器执行者传给回调函数 util_timer* prev; util_timer* next; }; class sort_timer_lst { public: sort_timer_lst() : head( NULL ), tail( NULL ) {} ~sort_timer_lst() { util_timer* tmp = head; while( tmp ) { head = tmp->next; delete tmp; tmp = head; } } void add_timer( util_timer* timer ) { if( !timer ) { return; } if( !head ) { head = tail = timer; return; } if( timer->expire < head->expire ) { timer->next = head; head->prev = timer; head = timer; return; } add_timer( timer, head ); } void adjust_timer( util_timer* timer ) { if( !timer ) { return; } util_timer* tmp = timer->next; if( !tmp || ( timer->expire < tmp->expire ) ) { return; } if( timer == head ) { head = head->next; head->prev = NULL; timer->next = NULL; add_timer( timer, head ); } else { timer->prev->next = timer->next; timer->next->prev = timer->prev; add_timer( timer, timer->next ); } } void del_timer( util_timer* timer ) { if( !timer ) { return; } if( ( timer == head ) && ( timer == tail ) ) { delete timer; head = NULL; tail = NULL; return; } if( timer == head ) { head = head->next; head->prev = NULL; delete timer; return; } if( timer == tail ) { tail = tail->prev; tail->next = NULL; delete timer; return; } timer->prev->next = timer->next; timer->next->prev = timer->prev; delete timer; } void tick() {//SIGALRM信号每次被触发就在其信号处理函数(如果使用同一事件源,则是主函数) //中执行一次tick函数,以处理链表上到期的任务 //下文会给出使用SIGALRM测试的代码,当然也可以使用其他方式 if( !head ) { return; } printf( "timer tick " ); time_t cur = time( NULL ); util_timer* tmp = head; while( tmp ) { if( cur < tmp->expire )//时间还没到就不干活先 { break; } tmp->cb_func( tmp->user_data ); head = tmp->next; if( head ) { head->prev = NULL; } delete tmp; tmp = head; } } private: void add_timer( util_timer* timer, util_timer* lst_head ) { util_timer* prev = lst_head; util_timer* tmp = prev->next; while( tmp ) { if( timer->expire < tmp->expire ) { prev->next = timer; timer->next = tmp; tmp->prev = timer; timer->prev = prev; break; } prev = tmp; tmp = tmp->next; } if( !tmp ) { prev->next = timer; timer->prev = prev; timer->next = NULL; tail = timer; } } private: util_timer* head; util_timer* tail; }; #endif
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <assert.h> #include <stdio.h> #include <signal.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <fcntl.h> #include <stdlib.h> #include <sys/epoll.h> #include <pthread.h> #include "lst_timer.h" #define FD_LIMIT 65535 #define MAX_EVENT_NUMBER 1024 #define TIMESLOT 5 static int pipefd[2]; static sort_timer_lst timer_lst; //使用升序链表来管理定时器 static int epollfd = 0; int setnonblocking( int fd )//非阻塞 { int old_option = fcntl( fd, F_GETFL ); int new_option = old_option | O_NONBLOCK; fcntl( fd, F_SETFL, new_option ); return old_option; } void addfd( int epollfd, int fd )//添加fd到红黑树 读、ET、非阻塞 { epoll_event event; event.data.fd = fd; event.events = EPOLLIN | EPOLLET; epoll_ctl( epollfd, EPOLL_CTL_ADD, fd, &event ); setnonblocking( fd ); } void sig_handler( int sig ) { int save_errno = errno; int msg = sig; send( pipefd[1], ( char* )&msg, 1, 0 );//写端口发送信号 errno = save_errno; } void addsig( int sig ) { struct sigaction sa; memset( &sa, '