この記事では、接続エラー ECONNREFUSED を例に、Node.js がエラーを処理するプロセスを確認します。 次のようなコードがあるとします 1. const net = require('net'); 2. net.connect({ポート: 9999}) このマシンでポート 9999 がリッスンしていない場合は、次の出力が表示されます。 1. イベント.js:170 2. throw er; // 処理されない「エラー」イベント 3. ^ 4. 5. エラー: connect ECONNREFUSED 127.0.0.1:9999 6. TCPConnectWrap.afterConnect [oncomplete として] (net.js:1088:14) 7. 次の場合に「エラー」イベントが発行されます: 8. でemitErrorNT (internal/streams/destroy.js:91:8) 9. で、emitErrorAndCloseNT (internal/streams/destroy.js:59:3) 10. processTicksAndRejections で (internal/process/task_queues.js:81:17) connect の呼び出しプロセスを簡単に見てみましょう。 1. const req = new TCPConnectWrap(); 2. req.oncomplete = afterConnect; 3. req.address = アドレス; 4. req.port = ポート; 5. req.localAddress = localAddress; 6. req.localPort = localPort; 7. // 接続を確立するために 3 ウェイ ハンドシェイクを開始します 8. err = self._handle.connect(req, address, port); 次に、C++レイヤーの接続ロジックを見てみましょう。 1. エラー = req_wrap->Dispatch(uv_tcp_connect, 2. &wrap->handle_, 3. reinterpret_cast<const sockaddr*>(&addr)、 4. AfterConnect); C++ レイヤーは Libuv の uv_tcp_connect を直接呼び出し、コールバックを AfterConnect に設定します。次に、libuv の実装を見てみましょう。 1. 行う { 2. エラー番号 = 0; 3. // 非ブロッキング呼び出し 4. r = connect(uv__stream_fd(handle), addr, addrlen); 5. } while (r == -1 && errno == EINTR); 6. // 接続エラー、エラーコードを決定する 7. if (r == -1 && errno != 0) { 8. // まだ接続中ですが、エラーではありません。接続が完了してイベントが読み取り可能になるまで待機しています。9. if (errno == EINPROGRESS) 10. ; /* エラーではない */ 11. それ以外の場合 (errno == ECONNREFUSED) 12. // 接続が拒否されました 13. handle->delayed_error = UV__ERR(ECONNREFUSED); 14. そうでなければ 15. UV__ERR(errno) を返します。 16. } 17. uv__req_init(handle->loop, req, UV_CONNECT); 18. req->cb = cb; 19. req->handle = (uv_stream_t*) ハンドル; 20. QUEUE_INIT(&req->queue); 21. // ハンドルにマウントし、書き込み可能なイベントを待機します 22. handle->connect_req = req; 23. uv__io_start(handle->loop, &handle->io_watcher, POLLOUT); Libuv はオペレーティング システムを非同期的に呼び出し、リクエストをハンドルにマウントして、書き込み可能なイベントを待機するように登録していることがわかります。接続が失敗すると、uv stream_io コールバックが実行されます。Libuv の処理 (uv stream_io) を見てみましょう。 1. getsockopt(uv__stream_fd(ストリーム)、 2. ソルソケット、 3. SO_ERROR、 4. &エラー、 5. &errorsize); 6. エラー = UV__ERR(エラー); 7. if (req->cb) 8. req->cb(req, エラー); エラー情報を取得した後、C++ レイヤーの AfterConnect をコールバックします。 1. ローカル<値> argv[5] = { 2. Integer::New(env->isolate(), ステータス)、 3. wrap->object(), 4. req_wrap->object(), 5. ブール値::New(env->isolate(), 読み取り可能)、 6. Boolean::New(env->isolate(), 書き込み可能) 7. }; 8. 9. req_wrap->MakeCallback(env->oncomplete_string(), arraysize(argv), argv); 次に、JS レイヤーの oncomplete コールバックを呼び出します。 1. const ex = exceptionWithHostPort(ステータス, 2. 「接続」 3. 必要住所、 4. 要求ポート、 5. 詳細); 6. if (詳細) { 7. ex.localAddress = req.localAddress; 8. ex.localPort = req.localPort; 9. } 10. // ソケットを破棄する 11. 自己を破棄します(ex); exceptionWithHostPort はエラー メッセージを作成し、ソケットを破棄して、ex をパラメーターとしてエラー イベントをトリガーします。 uvExceptionWithHostPort の実装を見てみましょう。 1. 関数 uvExceptionWithHostPort(err, syscall, アドレス, ポート) { 2. const [ code, uvmsg ] = uvErrmapGet(err) || uvUnmappedError; 3. const message = `${syscall} $[code]: ${uvmsg}`; 4. details = '' とします。 5. 6. if (ポート && ポート > 0) { 7. details = `${address}:${port}`; 8. } else if (アドレス) { 9. details = `${address}`; 10. } 11. const tmpLimit = Error.stackTraceLimit; 12. Error.stackTraceLimit = 0; 13. const ex = new Error(`${message}${details}`); 14. Error.stackTraceLimit = tmpLimit; 15. 例:code = コード; 16. 例: errno = err; 17. 例.syscall = syscall; 18. 例:address = アドレス; 19. if (ポート) { 20. 例:port = ポート; 21。 } 22. // 呼び出しスタック情報を取得しますが、現在呼び出されている関数 uvExceptionWithHostPort を除外し、スタック フィールドを ex23 に挿入します。Error.captureStackTrace(ex,excludedStackFn ||uvExceptionWithHostPort); 24. 戻る ex; 25. } エラー情報は主にuvErrmapGetを通じて取得されることがわかります。 1. 関数uvErrmapGet(名前) { 2. uvBinding = lazyUv(); 3. if (!uvBinding.errmap) { 4. uvBinding.errmap = uvBinding.getErrorMap(); 5. } 6. uvBinding.errmap.get(name); を返します。 7. } 8. 9. 関数 lazyUv() { 10. if (!uvBinding) { 11. uvBinding = 内部バインディング('uv'); 12. } 13. uvBindingを返します。 14. } さらに下を見ていくと、uvErrmapGet は C++ レイヤーの uv モジュールの getErrorMap を呼び出します。 1. void GetErrMap(const FunctionCallbackInfo<Value>& args) { 2. 環境* env = Environment::GetCurrent(args); 3. 分離* isolate = env->isolate(); 4. ローカル<Context> context = env->context(); 5. 6. Local<Map> err_map = Map::New(isolate); 7. // per_process::uv_errors_map からエラー情報を取得します8. size_t errors_len = arraysize(per_process::uv_errors_map); 9. // 代入 10. for (size_t i = 0; i < errors_len; ++i) { 11. // マップのキーは uv_errors_map の各要素の値であり、値は名前とメッセージです。 12. const auto& error = per_process::uv_errors_map[i]; 13. ローカル<値> arr[] = {OneByteString(isolate, error.name), 14. OneByteString(分離、エラーメッセージ)}; 15. if (err_map 16. ->Set(コンテキスト、 17. 整数::New(分離、エラー値)、 18. Array::New(isolate, arr, arraysize(arr))) 19. .IsEmpty()) { 20. 返却する。 21。 } 22。 } 23。 24. args.GetReturnValue().Set(err_map); 25. } エラー情報は per_process::uv_errors_map に存在することがわかります。uv_errors_map の定義を見てみましょう。 1. 構造体UVError{ 2. int 値; 3. const char* 名前; 4. const char* メッセージ; 5. }; 6. 7. 静的定数構造体UVError uv_errors_map[] = { 8. #define V(名前, メッセージ) {UV_##名前, #名前, メッセージ}, 9. UV_ERRNO_MAP(V) 10. #undefV 11. }; UV_ERRNO_MAP マクロは次のように展開されます。 1. {UV_E2BIG, "E2BIG", "引数リストが長すぎます"}, 2. {UV_EACCES、「EACCES」、「権限が拒否されました」}、 3. {UV_EADDRINUSE、「EADDRINUSE」、「アドレスはすでに使用されています」}、 4. … JSレイヤーにエクスポートした結果は次のようになります 1. { 2. // キーは Libuv によって定義された数値で、実際にはオペレーティング システムの定義をカプセル化します 3. UV_ECONNREFUSED: ["ECONNREFUSED", "接続が拒否されました"], 4. UV_ECONNRESET: ["ECONNRESET", "ピアによる接続のリセット"] 5. ... 6. } Node.js は最終的にこの情報を組み立てて呼び出し元に返します。これは出力されるエラー メッセージです。では、なぜ ECONNREFUSED なのでしょうか?このエラー コードに対するオペレーティング システムのロジックを見てみましょう。 1. 静的void tcp_reset(構造体sock *sk) 2. { 3. スイッチ(sk->sk_state) { 4. TCP_SYN_SENTの場合: 5. sk->sk_err = ECONNREFUSED; 6. 破る; 7. // ... 8. } 9. 10. } オペレーティング システムは、ソケットに送信された最初のパケットを受信すると、tcp_reset を実行します。ソケットが syn パケットを送信して ack を待機しているときに、fin パケットが受信されると、エラー コードが ECONNREFUSED に設定されることがわかります。出力されるのはこのエラーコードです。 要約する これで、Node.js のエラー処理プロセス記録に関するこの記事は終了です。より関連性の高い Node.js のエラー処理コンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。 以下もご興味があるかもしれません:
|
<<: Docker+Nginx を使ってシングルページアプリケーションをデプロイする
>>: MySQLとElasticsearch間のデータ非対称性問題の解決策
目次序文配列.プロトタイプ.includes文法パラメータ戻り値例配列プロトタイプの削減文法パラメー...
導入現在、k8s は非常に人気があり、それについて学ぶために本を購入しました。しかし、k8s では数...
MySQL チューニング ツールの詳細な説明と実践的な演習の説明 ツールの紹介の説明 分析例の説明...
mysql が正常に実行されている場合、テーブル構造を表示することは難しくありません。しかし、場合...
一時テーブルとメモリテーブルメモリ テーブルとは、メモリ エンジンを使用するテーブルを指します。テー...
記事のタイトルが「模造虫眼鏡」なのはなぜですか?今日お話ししたいのは、一般的に言われているような、マ...
データベース操作を学び始めたばかりです。今日、データを保存していたところ、エラーが発生していることに...
私は最近、空洞化効果について研究しました。背景クリップ: テキスト背景はテキストの前景色にクリップさ...
明らかな HTML、隠された「公開スクリプト」 Web ページのダウンロード時間を短縮する鍵は、フ...
凡例コンポーネントは、ECharts でよく使用されるコンポーネントです。シリーズ マーカーの名前を...
サーバー: Ubuntu Server 16.04 LSSクライアント: Ubuntu 16.04 ...
脆弱性の詳細VSFTP は、GPL に基づいてリリースされた Unix ライクなシステムで使用される...
1. CentOS Linuxにffmpegをインストールする1.ダウンロードして解凍する http...
目次プロトタイプを理解するプロトタイプオブジェクトを理解するインスタンスプロパティとプロトタイププロ...
最初は速度の問題だと思ったので、その後、すべての画像リンク リクエストをクロスサイト接続ではなくサイ...