那谁的技术博客

感兴趣领域:高性能服务器编程,存储,算法,Linux内核
随笔 - 210, 文章 - 0, 评论 - 1183, 引用 - 0
数据加载中……

lighttpd1.4.18代码分析(五)--处理超时连接

本节相对简单, 讲讲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信号产生,在编码的时候要特别注意被信号中断的情况.


posted on 2008-09-05 19:33 那谁 阅读(3148) 评论(1)  编辑 收藏 引用 所属分类: 网络编程服务器设计Linux/Unixlighttpd

评论

# re: lighttpd1.4.18代码分析(五)--处理超时连接  回复  更多评论   

在程序中并没有定义宏USE_ALARM,唯一的一处定义也被作者注释掉了:
/*
* IRIX doesn't like the alarm based time() optimization
*/
/*
* #define USE_ALARM
*/
好像每次循环中
// 如果产生了alarm信号 那么一秒钟过去了
if (handle_sig_alarm) {。。。
都会运行,因为handle_sig_alarm始终是1.
2010-03-18 22:24 | hcykernel

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理