lighttpd-1.4.39 : alarm

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值