Lighttpd1.4.20原始碼分析 筆記 狀態機器之錯誤處理和串連關閉

來源:互聯網
上載者:User

標籤:原始碼分析   ioctl   系統   oct   proc   階段   資源   eset   時間   

這裡所說的錯誤有兩種:
1.http協議規定的錯誤,如404錯誤。
2.server執行過程中的錯誤。如write錯誤。

對於http協議規定的錯誤,這裡的“錯誤”是針對client的。

lighttpd返回相應的錯誤提示檔案之後,相當於順利的完畢了一次請求,僅僅是結果和client想要的不一樣而已。

對於server執行中的錯誤,狀態機器進入CON_STATE_ERROR狀態。常見的錯誤原因:client提前中斷連線。

比方你不停的重新整理頁面。在你重新整理的時候,前一次的串連沒有完畢,但被瀏覽器強行斷開。對於server而言,重新整理前後的兩個串連是不相干的,server在接收後一個串連的時候仍然會繼續處理前一次的串連。而前一次的串連已斷開,這就產生了串連錯誤。

進入CON_STATE_ERROR狀態後。假設前面的請求處理已經得到了結果。也就是http_status不為空白。那麼調用plugins_call_handle_request_done告訴外掛程式請求處理結束:

            /* even if the connection was drop we still have to write it to the access log */            if (con->http_status) {                plugins_call_handle_request_done(srv, con);            }

假設使用了ssl,關閉ssl串連:

#ifdef USE_OPENSSL    if (srv_sock->is_ssl) {    /* 關閉ssl串連 */    }    ERR_clear_error();#endif

接著:

            switch(con->mode) {            case DIRECT:#if 0                log_error_write(srv, __FILE__, __LINE__, "sd",                        "emergency exit: direct",                        con->fd);#endif                break;            default:                switch(r = plugins_call_handle_connection_close(srv, con)) {                case HANDLER_GO_ON:                case HANDLER_FINISHED:                    break;                default:                    log_error_write(srv, __FILE__, __LINE__, "");                    break;                }                break;            }            connection_reset(srv, con);

假設串連模式不是DIRECT,調用plugins_call_handle_connection_close告訴外掛程式串連已經關閉。

假設設定了keep_alive。此時可能是server首先關閉串連的。調用shutdown關閉串連的讀和寫。假設關閉沒有出錯,狀態機器進入CON_STATE_CLOSE狀態。

假設沒有設定keep_alive或者shutdown調用失敗,那麼直接關閉串連。結束狀態機器的執行。

            /* close the connection */            if ((con->keep_alive == 1) &&                (0 == shutdown(con->fd, SHUT_WR))) {                con->close_timeout_ts = srv->cur_ts;                connection_set_state(srv, con, CON_STATE_CLOSE);                if (srv->srvconf.log_state_handling) {                    log_error_write(srv, __FILE__, __LINE__, "sd",                            "shutdown for fd", con->fd);                }            } else {                connection_close(srv, con);            }            con->keep_alive = 0;            srv->con_closed++;

注意到。這裡server主動關閉串連的時候用的是shutdown而不是close:

1.close使用引用計數,在計數為0時才關閉通訊端;shutdown無論引用計數,直接激發TCP的正常串連終止序列。

2.close終止讀和寫兩個方向的資料傳送。shutdown能夠指定僅僅關閉串連的讀,或僅僅關閉串連的寫。或兩者均關閉。

以上lighttpd是關閉了串連的寫這一半,對於TCP通訊端來說。這叫做半關閉:當前留在通訊端發送緩衝區的資料仍然能夠發送。可是進程不能再對其調用寫函數(因為讀端沒有關閉,所以server仍然能夠讀資料),當資料發送完畢之後,TCP串連終止。

另外。注意一下:con->close_timeout_ts = srv->cur_ts;將close_timeout_ts的值設定為目前時間,在以下會用到。

在CON_STATE_CLOSE階段:

        case CON_STATE_CLOSE:            if (srv->srvconf.log_state_handling) {                log_error_write(srv, __FILE__, __LINE__, "sds",                        "state for fd", con->fd, connection_get_state(con->state));            }            if (con->keep_alive) {                if (ioctl(con->fd, FIONREAD, &b)) {                    log_error_write(srv, __FILE__, __LINE__, "ss",                            "ioctl() failed", strerror(errno));                }                if (b > 0) {                    char buf[1024];                    log_error_write(srv, __FILE__, __LINE__, "sdd",                            "CLOSE-read()", con->fd, b);                    /* */                    read(con->fd, buf, sizeof(buf));                } else {                    /* nothing to read */                    con->close_timeout_ts = 0;                }            } else {                con->close_timeout_ts = 0;            }            if (srv->cur_ts - con->close_timeout_ts > 1) {                connection_close(srv, con);                if (srv->srvconf.log_state_handling) {                    log_error_write(srv, __FILE__, __LINE__, "sd",                            "connection closed for fd", con->fd);                }            }            break;

假設緩衝區中還有資料,server會把資料讀出來(然後丟棄),以騰出記憶體空間。

假設沒有資料可讀,那麼設定close_timeout_ts=0,關閉串連。

假設有資料可讀,讀取資料之後,串連依舊處在CON_STATE_CLOSE狀態中(在出了CON_STATE_ERROR後。進入CON_STATE_CLOSE,這段時間cur_ts是沒有改變的。假設有資料可讀,此時const_time_ts是等於cur_ts的,因此串連並未被關閉),串連相應的fd被增加到fdevent系統中監聽讀事件。

假設緩衝區中還有資料,那麼在connection_handle_fdevent 函數中,也有上面這段代碼,再次執行之,直到資料讀完。

隨著close_timeout_ts被設定為0,在下次joblist的調度中,狀態機器將會關閉串連,清理全部資源。

至此,串連正式關閉。

關於狀態機器的簡單解析就到此為止~

Lighttpd1.4.20原始碼分析 筆記 狀態機器之錯誤處理和串連關閉

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.