この記事では主に、NODEJS の http 実装の技術的なプロセスと詳細な分析を紹介します。必要な方は参考にしてください。
1. はじめに
現在、HTTP プロトコルはインターネット上で最も広く使用されているネットワーク プロトコルであり、フロントエンド ER が最も頻繁に使用するプロトコルでもあります。 nodejs の http モジュールの実装を読むことで、HTTP プロトコルをより深く理解できます。 HTTP プロトコルは、TCP プロトコルに基づくアプリケーション層プロトコルであり、その実装は TCP/IP プロトコル ファミリと切り離すことができません。コードの実装に関しては、http モジュールは net モジュールに依存します。
以下の図に示すように、nodejs では、http は net モジュールを通じてデータを送信し、データを取得した後、HTTP_PARSER に依存してデータを解析します。
2. ソースコード
HTTPサービスを開始する
nodejsでHTTPサービスを開始するのは非常に簡単で、Serverオブジェクトをインスタンス化し、特定のポートをリッスンするだけです:
const Server = require('./libs/http').Server const server = new Server( function(req, res) { res.writeHead(200) res.end('hello world') }) server.listen(9999)
SERVERクラス
Serverクラスnet.Server から継承し、「connection」イベントをリッスンします。
Server クラスでは、2 つの主な処理が行われます: 1. NET モジュールを初期化し、TCP ネットワーク監視を確立します。 2. 独自の要求イベントを監視します
クライアント要求が来ると、Server インスタンスは最初に「接続」をリッスンします。イベントを実行し、TCP 接続を確立し、connectionListener でソケット オブジェクトを公開します。次に、HTTP モジュールはソケット オブジェクトを通じてクライアントと対話します。
リクエストが到着すると、サーバーは独自のリクエスト イベントをトリガーし、サーバー インスタンスの作成時に渡されるコールバック関数である requestListener メソッドを呼び出します。
new Server( function(req, res) { res.writeHead(200) res.end('hello world') })
注: ソケット オブジェクトは、クライアントとデータを交換できる TCP プロトコルの実装に似ています。 注: connectionListener 関数では、パーサー インスタンスも初期化され、onIncoming 関数 HTTP パーサーがバインドされます。
全体 解析プロセスは connectionListener で実行され、ソケットは「data」イベントを通じて TCP によってプッシュされたデータを取得します。つまり、parser.excute() によってデータが解析されます。解析ツールはパーサーです。パーサーの再利用を実現するために、作成者は「FreeList プール」からパーサーを取得したことに言及する価値があります。
... const parser = parsers.alloc() ... connectionListener(socket) { socket.on('data', socketOnData) // TCP推入数据,parser进行解析 function socketOnData(d) { ... const ret = parser.execute(d) ... } }
1. TCP データが到着したら、最初にexecute()します
2. 手がかりに従って、parser.excute が Excute (node_http_parser.cc) であることがわかりました。 Excute は単なるアウトソーシングであり、具体的な作業は http_parser_excute (http_parser.c) によって実行されます。
node_http_parser.cc は、http_parser.c の単なるラッパーです。http_parser.c は、データを取得するために、外部に公開された 7 つのコールバック定期関数に依存します。
3. http_parser.c には、HTTP_CB と HTTP_DATA_CB の 2 種類のコールバックのみがあります。オーバーロードにより、以下に示すように、これら 2 種類の関数に 8 つの周期関数が登録されます。
4. http_parser には 8 つの登録されたコールバック関数がありますが、node_http_parser.cc は 4 つの周期関数のみを外部に公開します:
parserOnHeaders
parserOnHeadersComplete
parserOnBody
parserOnMessageComplete
5. http_parser.c が on_headers_complete に解析するとき、図に示すように HTTP_CB (on_headers_complete) コールバック関数を実行します。
kOnHeadersComplete コールバック関数が実行されます。つまり、parserOnHeadersComplete 関数 (common . js)
6. この時点で、リクエスト ヘッダーの解析は基本的に完了します。次に、IncomingMessage のインスタンスを作成し、そのインスタンスにリクエスト ヘッダー データをパッケージ化します。
onIncoming コールバック関数を実行し、取得した IncomingMessage インスタンスをパラメータとして渡します。function parserOnHeadersComplete (versionMajor, versionMinor, headers, method, url, statusCode, statusMessage, upgrade, shouldKeepAlive) { ... parser.incoming = new IncomingMessage(parser.socket) parser.incoming.httpVersionMajor = versionMajor parser.incoming.httpVersionMinor = versionMinor parser.incoming.httpVersion = versionMajor + '.' + versionMinor parser.incoming.url = url ... skipBody = parser.onIncoming(parser.incoming, shouldKeepAlive) }
req と res の 2 つのインスタンスにより、サーバーによって監視されているリクエスト イベントがトリガーされます。
サーバーがインスタンス化されると、リクエストイベントを監視するための関数パラメータとして requestListener が使用されます。
8. サーバーの作成時に戻ります:
const server = new Server( function(req, res) { var data = '' req.on('data', function(chunk){ console.log('chunk: ' + chunk) data += chunk; }) res.writeHead(200) res.end('hello world') })
要約すると、http_parser がヘッダーを解析した後、リクエスト イベントがトリガーされます。
本体データをどこに置くか? 実際、本体データは、ユーザーがデータイベントを使用してデータを受信するまでストリームに配置されます。つまり、リクエストがトリガーされたとき、本文は解析されません。
3. プロセスの概要 完全な http リクエストは次のとおりです: - クライアントは HTTP リクエストを開始し、最初にサーバー側で接続イベントをトリガーし、TCP リンクを確立します。
接続イベントを受信した後、サーバーは TCP 接続を確立し、ソケットを公開し、ソケットを通じて「データ」イベントをリッスンし、その後のデータの解析に備えて http-parser を初期化します。
HTTP リクエスト データがサーバーに到着し、パーサーが実行メソッドを実行して解析します。リクエスト ヘッダーが正常に解析された後、コールバックを通じてリクエスト イベントがトリガーされます。
この時点で、サーバーのコールバック関数でこの http リクエストのリクエストを受け取りました
4. 結論 nodejs の基礎となるライブラリの多くは C++/C で書かれているため、読み取りやデバッグのプロセス中に非常に不便です。私自身ソース コードを読むときは、ソース コードの JS 部分だけに注目しました。たとえば、TCP の 3 ウェイ ハンドシェイクと 4 ウェイ ウェーブは、その実装の詳細については詳しく説明されていません。 上記の分析には http-body の分析は含まれていません。ボディを含むネットワーク リクエストの場合、実際の状況はさらに複雑で、一部の詳細は完全には理解されていません。次回要約して共有するときは、不足している詳細をすべて埋めるように最善を尽くします。 上記は私があなたのためにまとめたものです。 関連記事:
以上がNODEJS での http 実装の詳細な紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。