ホームページ  >  記事  >  ウェブフロントエンド  >  NODEJS での http 実装の詳細な紹介

NODEJS での http 実装の詳細な紹介

亚连
亚连オリジナル
2018-06-13 17:31:291942ブラウズ

この記事では主に、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)

}

7. parserOnIncoming で、ServerResponse インスタンスを作成します。

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 の分析は含まれていません。ボディを含むネットワーク リクエストの場合、実際の状況はさらに複雑で、一部の詳細は完全には理解されていません。次回要約して共有するときは、不足している詳細をすべて埋めるように最善を尽くします。

上記は私があなたのためにまとめたものです。

関連記事:

JSを使ってノード要素を取得する方法

NodeJSを使ったWebSocket機能の実装方法

Expressにおけるlog4jsの実際の使い方について

以上がNODEJS での http 実装の詳細な紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。