Lighttpd1.4.20ソース分析ノートステータスマシンのresponse


CONでSTATE_RESPONSE_START状態では、サーバがクライアントへのresponseの準備を開始します.
        case CON_STATE_RESPONSE_START:
            /*
             * the decision is done
             * - create the HTTP-Response-Header
             *
             */

            if (srv->srvconf.log_state_handling) {
                log_error_write(srv, __FILE__, __LINE__, "sds",
                        "state for fd", con->fd, connection_get_state(con->state));
            }

            if (-1 == connection_handle_write_prepare(srv, con)) {
                connection_set_state(srv, con, CON_STATE_ERROR);

                break;
            }

            connection_set_state(srv, con, CON_STATE_WRITE);
            break;

このステータスは主にconnection_を呼び出していることがわかります.handle_write_prepare関数は、クライアントから要求されたmethodに基づいてresponseのheadersを設定します(実は「Content-Longth」の値を設定します).
connection_handle_write_prepare関数の実行内容:
1.この関数は、まず接続のパターンがDIRECTであるかどうかを判断し、もしそうであれば、接続がプラグイン処理されていないことを示し、サーバ自身が処理している.
2.次に接続の要求methodを判断し、OPTIONであればAllowの値を設定し、write_をクリアするqueue、データがないので返す必要があります.con->file_の設定finishedは1で、クライアントにファイルを送信する必要がないことを示します.
3.http_の比較statusの値は、204520304の場合、サーバがクライアントにファイルを返す必要がないことを示し、responseのheadersとその前の部分だけを返し、con->file_を設定します.finishedは1です.
4.判断file_finishedの値.値が1の場合、クライアントにファイルデータを返す必要はありません.1 xx、204、304のステータスについては、Content-LongthをNull値に設定します.methodがHEADの場合、サーバはいくつかのデータを返す必要がある場合があります.この場合、対応するContent-Longthを設定します.file_の場合finishedの値は0です.keep_を設定します.aliveの値.
5.最後にhttp_を呼び出すresponse_write_ヘッダーはheadersをwrite_に書き込むqueue、クライアントへの戻りを待つ.すべてがうまくいけば、ステータスマシンはCONに入ります.STATE_WRITE状態.
次はCON_STATE_WRITEブランチの操作:
        case CON_STATE_WRITE:
            if (srv->srvconf.log_state_handling) {
                log_error_write(srv, __FILE__, __LINE__, "sds",
                        "state for fd", con->fd, connection_get_state(con->state));
            }

            /* only try to write if we have something in the queue */
            if (!chunkqueue_is_empty(con->write_queue)) {
#if 0
                log_error_write(srv, __FILE__, __LINE__, "dsd",
                        con->fd,
                        "packets to write:",
                        con->write_queue->used);
#endif
            }
            if (!chunkqueue_is_empty(con->write_queue) && con->is_writable) {
                if (-1 == connection_handle_write(srv, con)) {
                    log_error_write(srv, __FILE__, __LINE__, "ds",
                            con->fd,
                            "handle write failed.");
                    connection_set_state(srv, con, CON_STATE_ERROR);
                } else if (con->state == CON_STATE_WRITE) {
                    con->write_request_ts = srv->cur_ts;
                }
            }

            break;

データは一度には書けないかもしれないので、CON_STATE_WRITE状態では、まずwrite_を判断Queueが空であるかどうか、すなわちデータが送信される必要があるかどうか.同時に接続が書き込み可能かどうかを判断します.データがあり、書き込み可能な場合はconnection_を呼び出します.handle_writeはデータを送信します.データの書き込み可能または接続の書き込み不可がない場合は、switch(con->state)という文から飛び出します.
ステートマシンのステータスが変化していないため、switchの後のif文はサーバに大きなwhileループを終了させ、ループの後の小さなs witch(con->state)文に入ります(接続のステータスが変化していない場合は、接続読み書きデータがまだ終わっていないことを示しますが、IOイベントを待つ必要があります).ここで、CON_に入りますSTATE_WRITEブランチは、データが書き込み可能で、接続が書き込み可能で、トラフィック制限に達していない場合は、fdeventにこの接続を登録し、IOが終了してからデータを書き続けます.そうしないと、この接続を削除します.
書き込み可能なデータと書き込み可能な接続がある場合はconnection_handle_write関数、次の関数の役割を見てみましょう.
1.network_を最初に呼び出すwrite_chunkqueue関数、write_queueのデータはクライアントに書き込まれます.関数network_write_chunkqueueは、まず、現在の接続のトラフィックが制限を超えているかどうかを判断し、そうであれば、データを送信せずにジョブリストに接続を追加し、他の接続にデータを送信させる.制限を超えていない場合は、まずTCP_を設定します.CORKオプション.このオプションは、複数のwrite呼び出しデータを一緒に送信し、送信効率を向上させることができます.
2.次にsrv->network_を呼び出すbackend_wirte()関数は本当にデータを書きます.この関数の定義はnetwork_*.cファイルにあります.サーバーはnetworkです.cのnetwork_Init関数では、現在の実行環境に応じて異なる値が設定されます.従来のIOメソッドはreadからwriteまで4回のデータコピー(ディスクからカーネルバッファ、カーネルバッファからユーザバッファ、ユーザバッファからネットワークインタフェースのカーネルバッファ、最後に、ネットワークインタフェースのカーネルバッファからネットワークデバイスバッファ)が必要であり、サーバの効率を向上させるために、異なるOSはコピーの回数(直接IO)を減らし、ファイルの送信速度を向上させる特定の方法を提供します.Lighttpdは異なるOSに基づいて特定のインタフェースを呼び出してnetwork_を実現するbackend_wirte()関数.これらの実装はnetwork_write.cの実装例:
関数の主体は大きなループであり,すべてのchunkを遍歴する.
chunkのタイプがMEM_ならCHUNKでは、このchunkのデータはメモリにあり、writeまたはwindowsのsend関数を直接呼び出してデータを送信します.
FILEならCHUNKタイプは、このchunkがファイルを表していることを示しています.実行環境にmmap関数がある場合は、mmapを使用してファイルをマッピングして送信します.そうしないと、readはwriteになります.
このchunkの送信が完了したら、次のchunkの送信を続行します.
送信が完了していない場合(chunk_finished=0)、ループを終了し、この関数を終了します.
3.サーバはnetwork_に戻るwrite_chunkqueueでは、いくつかの統計作業を行い、接続のトラフィックが限界を超えているかどうかをもう一度確認します.
4.最後にconnection_にサーバが戻るhandle_writeで.network_write_chunkqueueは、サーバエラーを示す-1を返します.ステータスマシンがCONに入るSTATE_ERROR. -2に戻るとクライアントは接続をオフにし、ステータスマシンもCON_に入ります.STATE_ERROR. 0を返すと送信が完了し、次の状態になります.1を返すと、データが送信されていないことを示し、is_をマークします.wirtableは0です.
5.connection_からhandler_write関数が戻った後、データの送信が完了していない場合は、ステータスマシンはまだCON_STATE_WRITE状態で、接続はfdeventシステムに追加され、次のデータ送信を待つ.送信が完了したりエラーが発生するまで、上記の手順を繰り返します.
6.データ送信が完了したら、ステータスマシンはCON_に入るSTATE_RESPONSE_END状態.
状態CON_STATE_RESPONSE_END:
1.サーバがpluginsを最初に呼び出す_call_handle_request_doneは、すべてのプラグイン接続処理が完了したことを通知します.
2.接続を保持しているか判断し、保持している場合はステータスマシンをCON_に設定STATE_REQUEST_START.保持しない場合はplugins_を呼び出します.call_handle_connection_closeは、すべてのプラグイン接続が閉じていることを通知し、接続を閉じます.
3.conをリセットし、前回要求したデータを消去します.
これで、要求処理は終了する.