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

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


你可能感兴趣的:(lighttpd1.4.18代码分析(五)--处理超时连接)