您的位置:首页 > 理论基础 > 计算机网络

lighttpd-1.4.39 : alarm

2016-02-15 11:34 543 查看
原文: http://bbs.chinaunix.net/thread-1251434-5-1.html

本节相对简单, 讲讲lighttpd中如何处理超时的连接.

方法很简单, lighttpd创建一个每隔一秒触发的定时器, 被触发后查找当前的所有连接, 看它们的时间是否已经超过了最长的生存期, 如果是就关闭连接.

创建定时器的代码在server.c的main函数中:

#ifdef USE_ALARM
struct itimerval interval;

interval.it_interval.tv_sec = 1;
interval.it_interval.tv_usec = 0;
interval.it_value.tv_sec = 1;
interval.it_value.tv_usec = 0;
#endif

...
#ifdef USE_ALARM
// 定时
signal(SIGALRM, signal_handler);

/* setup periodic timer (1 second) */
if (setitimer(ITIMER_REAL, &interval, NULL)) {
log_error_write(srv, __FILE__, __LINE__, "s", "setting timer failed");
return -1;
}

getitimer(ITIMER_REAL, &interval);
#endif


定时器触发的时候产生ALARM信号,此时在服务器主循环中轮询所有的连接,这段代码同样在server.c的main函数中:

// 如果产生了alarm信号 那么一秒钟过去了...
if (handle_sig_alarm) {
/* a new second */

#ifdef USE_ALARM
/* reset notification */
handle_sig_alarm = 0;
#endif

/* get current time */
// 获得当前的时间
min_ts = time(NULL);

// 如果当前时间不等于server上次记录的时间
if (min_ts != srv->cur_ts) {
int cs = 0;
connections *conns = srv->conns;
handler_t r;

switch(r = plugins_call_handle_trigger(srv)) {
case HANDLER_GO_ON:
break;
case HANDLER_ERROR:
log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed");
break;
default:
log_error_write(srv, __FILE__, __LINE__, "d", r);
break;
}

/* trigger waitpid */
// 更新server的当前时间
srv->cur_ts = min_ts;

/* cleanup stat-cache */
// 每秒清空一次stat cache
stat_cache_trigger_cleanup(srv);

/**
* check all connections for timeouts
*/
// 检查所有连接是否已经超时
for (ndx = 0; ndx < conns->used; ndx++) {
int changed = 0;
connection *con;
int t_diff;

con = conns->ptr[ndx];

if (con->state == CON_STATE_READ ||
con->state == CON_STATE_READ_POST) {
if (con->request_count == 1) {
// 如果当前时间与read_idle_ts之差大于max_read_idle, 超时
if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
/* time - out */

connection_set_state(srv, con, CON_STATE_ERROR);
changed = 1;
}
} else {
// 如果当前时间与read_idle_ts之差大于max_keep_alive_idle, 超时
if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) {
/* time - out */

connection_set_state(srv, con, CON_STATE_ERROR);
changed = 1;
}
}
}

if ((con->state == CON_STATE_WRITE) &&
(con->write_request_ts != 0)) {
// 如果当前时间与write_request_ts之差大于max_write_idle, 超时
if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) {
/* time - out */
#if 1
log_error_write(srv, __FILE__, __LINE__, "sbsosds",
"NOTE: a request for",
con->request.uri,
"timed out after writing",
con->bytes_written,
"bytes. We waited",
(int)con->conf.max_write_idle,
"seconds. If this a problem increase server.max-write-idle");
#endif
connection_set_state(srv, con, CON_STATE_ERROR);
changed = 1;
}
}

/* we don't like div by zero */
// 如果接收连接的时间 = server当前时间
if (0 == (t_diff = srv->cur_ts - con->connection_start))
t_diff = 1;

if (con->traffic_limit_reached &&                        // 如果已经达到了传输的极限
(con->conf.kbytes_per_second == 0 ||        // 似乎这个值一直是0啊
((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) {        // 如果每秒发送的数据量小于kbytes_per_second * 1024
/* enable connection again */
// 传输极限不再
con->traffic_limit_reached = 0;

changed = 1;
}

// 如果状态发生了改变, 那么进入状态机进行处理
if (changed) {
connection_state_machine(srv, con);
}

con->bytes_written_cur_second = 0;
*(con->conf.global_bytes_per_second_cnt_ptr) = 0;

}

if (cs == 1)
fprintf(stderr, "\n");
}
}


需要注意的是, 由于lighttpd采用了这种方式处理超时连接, 会触发大量的ALARM信号产生,在编码的时候要特别注意被信号中断的情况.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: