一、非活跃连接
- 非活跃连接:客户端(浏览器)与服务器端建立连接后,长时间不交换数据,一直占用服务器端资源。
- 针对非活跃连接,需要在内核事件表删除对应事件、关闭文件描述符、释放连接资源等。
二、信号
- Linux中的信号是一种消息处理机制,它本质上是一个整数,不同的信号对应不同的值,信号在系统中的优先级是非常高的。
- 项目中使用的信号
1. SIGALRM:定时器超时信号,超时的时间由系统调用alarm设置,默认终止进程。
2. SIGTERM:程序结束信号,kill或Ctrl+C触发,默认终止进程。
- 两个特殊信号
1. SIGKILL:9号信号,无条件终止进程,不能被捕捉、阻塞和忽略。
2. SIGSTOP:19号信号,无条件暂停进程,不能被捕捉、阻塞和忽略。
三、信号捕捉
- Linux中的每个信号产生之后都会有对应的默认处理行为,如果想要忽略某些信号或者修改某些信号的默认行为就需要在程序中捕捉该信号。
- 程序中的信号捕捉是一个注册的动作,提前告诉应用程序信号产生之后的处理动作,当进程中对应的信号产生了,这个处理动作也就被调用了。
struct sigaction
{
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
int sigaction(
int signum,
const struct sigaction *act,
struct sigaction *oldact
);
四、定时器
unsigned int alarm(unsigned int seconds);
五、统一事件源
- 1. 一般的信号处理函数需要处理该信号对应的逻辑,当该逻辑比较复杂时,信号处理函数执行时间过长,会导致信号屏蔽太久。
- 解决方法:
信号处理函数仅发送信号的值,通知程序主循环,程序主循环中执行信号对应的逻辑代码。
- 2. 统一事件源:将信号事件与其他事件一样被处理。
- 解决方法:
信号处理函数往管道的写端写入信号值,主循环则从管道的读端读出信号值。
使用I/O复用系统调用监听管道读端的可读事件与其他文件描述符,从而实现统一处理。
六、实现代码
1. lst_timer.h
#ifndef LST_TIMER
#define LST_TIMER
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <sys/stat.h>
#include <string.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <stdarg.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/uio.h>
#include <time.h>
#include "../log/log.h"
class util_timer;
struct client_data
{
sockaddr_in address;
int sockfd;
util_timer *timer;
};
class util_timer
{
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();
~sort_timer_lst();
void add_timer(util_timer *timer);
void adjust_timer(util_timer *timer);
void del_timer(util_timer *timer);
void tick();
private:
void add_timer(util_timer *timer, util_timer *lst_head);
util_timer *head;
util_timer *tail;
};
class Utils
{
public:
Utils() {}
~Utils() {}
void init(int timeslot);
int setnonblocking(int fd);
void addfd(int epollfd, int fd, bool one_shot, int TRIGMode);
static void sig_handler(int sig);
void addsig(int sig, void(handler)(int), bool restart = true);
void timer_handler();
void show_error(int connfd, const char *info);
public:
static int *u_pipefd;
sort_timer_lst m_timer_lst;
static int u_epollfd;
int m_TIMESLOT;
};
void cb_func(client_data *user_data);
#endif
2.lst_timer.cpp
#include "lst_timer.h"
#include "../http/http_conn.h"
sort_timer_lst::sort_timer_lst()
{
head = NULL;
tail = NULL;
}
sort_timer_lst::~sort_timer_lst()
{
util_timer *tmp = head;
while (tmp)
{
head = tmp->next;
delete tmp;
tmp = head;
}
}
void sort_timer_lst::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 sort_timer_lst::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;
}
}
void sort_timer_lst::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 sort_timer_lst::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 sort_timer_lst::tick()
{
if (!head)
{
return;
}
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;
}
}
void Utils::init(int timeslot)
{
m_TIMESLOT = timeslot;
}
int Utils::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 Utils::addfd(int epollfd, int fd, bool one_shot, int TRIGMode)
{
epoll_event event;
event.data.fd = fd;
if (1 == TRIGMode)
{
event.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
}
else
{
event.events = EPOLLIN | EPOLLRDHUP;
}
if (one_shot)
event.events |= EPOLLONESHOT;
epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
setnonblocking(fd);
}
void Utils::sig_handler(int sig)
{
int save_errno = errno;
int msg = sig;
send(u_pipefd[1], (char *)&msg, 1, 0);
errno = save_errno;
}
void Utils::addsig(int sig, void(handler)(int), bool restart)
{
struct sigaction sa;
memset(&sa, '\0', sizeof(sa));
sa.sa_handler = handler;
if (restart)
{
sa.sa_flags |= SA_RESTART;
}
sigfillset(&sa.sa_mask);
assert(sigaction(sig, &sa, NULL) != -1);
}
void Utils::timer_handler()
{
m_timer_lst.tick();
alarm(m_TIMESLOT);
}
void Utils::show_error(int connfd, const char *info)
{
send(connfd, info, strlen(info), 0);
close(connfd);
}
int *Utils::u_pipefd = 0;
int Utils::u_epollfd = 0;
class Utils;
void cb_func(client_data *user_data)
{
epoll_ctl(Utils::u_epollfd, EPOLL_CTL_DEL, user_data->sockfd, 0);
assert(user_data);
close(user_data->sockfd);
http_conn::m_user_count--;
}