ホームページ > 記事 > ウェブフロントエンド > Node における TCP と UDP の簡単な分析
Node
はネットワーク指向のプラットフォームであり、イベント駆動型、ノンブロッキング、シングルスレッドであり、優れたスケーラビリティを備えているため、非常に軽量です分散ネットワークでさまざまな役割を果たすのに適しています。
Node
は、net
、dgram
、http
、http2
、 https を提供します。
およびその他のモジュールは、それぞれ TCP
、UDP
、HTTP
、HTTPS
を処理するために使用され、サーバーとクライアントの両方に適しています。
TCP
サービスはネットワーク アプリケーションで非常に一般的であり、現在のアプリケーションのほとんどは TCP# に基づいています。 # # 構築された、その正式名は Transmission Control Protocol であり、
OSI モデルのトランスポート層プロトコルに属します。多くのアプリケーション層プロトコルは
TCP に基づいて構築されており、一般的な
HTTP 、
SMTP、
IMAP およびその他のプロトコル。
TCP 関連のナレッジ ポイントについてはここでは説明しません。興味がある場合は、私の
コンピューター ネットワーク コラムを参照して学習してください。
TCP サーバーの作成
TCP の動作原理を基本的に理解した後、## の作成を開始できます。 #TCP
サーバー側はネットワーク リクエストを受け入れます。net
モジュールは、stream
## に基づいて TCP# を作成するための非同期ネットワーク
API を提供します。または
IPC サーバーとクライアント。 [関連チュートリアルの推奨事項:
nodejs ビデオ チュートリアル 、
プログラミング教育 ]以下の例をご覧ください。server.js## に記述されています。 # file 次のコードは次のとおりです:
import net from "net"; const server = net.createServer((socket) => { socket.on("data", (data) => { console.log("监听到客户端的数据:", data.toString()); }); // 监听客户端断开连接事件 socket.on("end", () => { console.log("客户端断开连接"); }); // 发送数据给客户端 socket.end("over over over\n"); }); // 启动服务 server.listen(3000, () => { console.log("服务创建成功"); });
net.createServer(listener)
を通じて
サーバーを作成できます。この関数のパラメータはリンクですイベント 接続
のリスナー。 ターミナルでファイルを実行すると、
サービスは正常に作成され、
出力がターミナルに表示されます。
nodemon .\server.js
先ほど、net.createServer
を通じてサーバーを作成し、次に
を使用してセッション用のクライアントを作成しました。具体的なコードは次のとおりです。 : <pre class="brush:js;toolbar:false;">import net from "net";
const client = net.connect({ port: 3000 }, () => {
client.write("今晚出去吃饭,收到请 over\n");
});
// 接收服务端的数据
client.on("data", (data) => {
console.log("接收服务端的数据: ", data.toString());
// 断开连接
client.end();
});
// 断开连接
client.on("end", () => {
console.log("断开连接");
});</pre>
以下に示すように、この時点で 2 つのファイルを実行します。
client.write() は複数回データを送信していますが、
setTimeout 以外のデータだけが正常であり、setTimeout
で送信される連続データは 1 回に 1 つではないようです返される代わりに、それらはランダムにマージされて返され、スティッキー パケットがここに表示されます。 TCP
ネットワーク内の小さなデータ パケットには、特定の最適化戦略があります。
アルゴリズム、最適化なしで一度に 1 バイトのコンテンツのみが送信される場合、ネットワークは、有効なデータが非常に少ないデータグラムでいっぱいになるため、ネットワーク リソースが大幅に無駄になります。この状況に対して、このアルゴリズムでは、バッファ内のデータが送信前に一定の量または一定の時間に達する必要があります。小さなデータ パケットはバッファによって送信され、ネットワークを最適化するためにアルゴリズムが結合されます。この最適化によりネットワークを効率的に利用できるようになりますが、データの送信に遅延が発生する場合があります。 Node
では、
がデフォルトで Negle
アルゴリズムを有効にするため、socket.setNoDelay(true)## を呼び出すことができます。
#Negle アルゴリズムを削除して、
write() がすぐにネットワークにデータを送信できるようにします。
#Close
このアルゴリズムは、サーバー側でマージを完了するため、常に有効であるとは限りません。TCP
受信したデータは、最初に独自のバッファーに格納され、その後、アプリケーションにそれを受信するように通知されます。アプリケーション層は、ネットワークまたはその他の問題によりブロックされます。その理由は、TCP バッファーからデータを時間内に取得できない場合、複数のデータ ブロックが TCP バッファーに格納され、スティッキーが発生するためです。パケット。
TCP 原則
new Server() を呼び出すことと同じです。 、具体的な結果を以下の図に示します:
<p>这主要的原因它在 <code>Node
源码中有如下定义,所以调用 createServer()
函数实际上调用的是 new Server()
,具体代码如下图所示:
function createServer(options, connectionListener) { return new Server(options, connectionListener); }
该构造函数的定义主要有如下所示:
function Server(options, connectionListener) { EventEmitter.call(this); // 注册连接到来时执行的回调 if (typeof options === "function") { connectionListener = options; options = {}; this.on("connection", connectionListener); } else if (options == null || typeof options === "object") { options = { ...options }; if (typeof connectionListener === "function") { this.on("connection", connectionListener); } } // 服务器建立的连接数 this._connections = 0; this[async_id_symbol] = -1; this._handle = null; this._usingWorkers = false; this._workers = []; this._unref = false; // 服务器下的所有连接是否允许半连接 this.allowHalfOpen = options.allowHalfOpen || false; // 有连接时是否注册读事件 this.pauseOnConnect = !!options.pauseOnConnect; this.noDelay = Boolean(options.noDelay); // 是否支持keepAlive this.keepAlive = Boolean(options.keepAlive); this.keepAliveInitialDelay = ~~(options.keepAliveInitialDelay / 1000); } ObjectSetPrototypeOf(Server.prototype, EventEmitter.prototype); ObjectSetPrototypeOf(Server, EventEmitter);
listen
它返回的是一个普通的 JavaScript
对象,接着调用 listen
函数监听端口,listen
方法支持多种使用方式主要有以下这几种方法:
TCP
服务器,而不是需要创建的一个服务器;fd
字段;TCP
服务器,并启动该服务器,如果传入了 host
会对其进行域名解析;该方法的的主要逻辑有如下代码所示:
Server.prototype.listen = function (...args) { /* 处理入参,根据文档我们知道listen可以接收好几个参数, 假设我们这里是只传了端口号9297 */ var normalized = normalizeArgs(args); // normalized = [{port: 9297}, null]; var options = normalized[0]; var cb = normalized[1]; // 第一次listen的时候会创建,如果非空说明已经listen过 if (this._handle) { throw new errors.Error("ERR_SERVER_ALREADY_LISTEN"); } // listen成功后执行的回调 var hasCallback = cb !== null; if (hasCallback) { // listen成功的回调 this.once("listening", cb); } options = options._handle || options.handle || options; // 第一种情况,传进来的是一个TCP服务器,而不是需要创建一个服务器 if (options instanceof TCP) { this._handle = options; this[async_id_symbol] = this._handle.getAsyncId(); listenIncluster(this, null, -1, -1, backlogFromArgs); return this; } // 第二种,传进来一个对象,并且带了fd if (typeof options.fd === "number" && options.fd >= 0) { listenIncluster(this, null, null, null, backlogFromArgs, options.fd); return this; } // 创建一个tcp服务器 var backlog; if (typeof options.port === "number" || typeof options.port === "string") { backlog = options.backlog || backlogFromArgs; // 第三种 启动一个TCP服务器,传了host则先进行DNS解析 if (options.host) { lookupAndListen( this, options.port | 0, options.host, backlog, options.exclusive ); } else { listenIncluster( this, null, options.port | 0, 4, backlog, undefined, options.exclusive ); } return this; } };
在每种方式的最后丢回调用 listenIncluster
方法,该方法主要做的事情是区分 master
进程 和 worker
进程,采用不同的处理策略:
mastr
进程: 直接调用 server._listen
启动监听;worker
进程: 使用 cluster._getServer
处理传入的 server
对象,修改 server._handle
再调用了 server._listen
启动监听;UDP
又称用户数据包协议,与 TCP
一样同属于网络层传输层。UDP
和 TCP
最大的不同是 UDP
不是面向链接的。
创建 <span style="font-size: 18px;">UDP</span>
服务
创建 UDP
套接字十分简单,UDP
套接字一旦创建,既可以作为客户端发送数据,也可以作为服务端接收数据,下面的代码创建了一个 UDP
套接字,具体代码如下所示:
import dgram from "node:dgram"; const server = dgram.createSocket("udp4"); server.on("error", (err) => { console.error(`server error:\n${err.stack}`); server.close(); }); server.on("message", (msg, rinfo) => { console.log(`server got: ${msg} from ${rinfo.address}:${rinfo.port}`); }); server.on("listening", () => { const address = server.address(); console.log(`server listening ${address.address}:${address.port}`); }); server.bind(3000);
该套接字将接收所有网课上 3000
端口上的消息,在绑定完成后,将触发 listening
事件,会终端执行,会输出 server listening 0.0.0.0:3000
字段。
接下来我们创建一个客户端和服务端进行对话,具体代码如下所示:
import dgram from "node:dgram"; import { Buffer } from "node:buffer"; const message = Buffer.from("你个叼毛"); const client = dgram.createSocket("udp4"); client.send(message, 0, message.length, 3000, "localhost", () => { client.close(); });
终端的最终输出结果如下图所示
UDP 广播
在 dgram
模块中,可以使用 socket
端口对象的 setBroadcast
方法来进行数据的广播:
socket.setBroadcast(flag);
flag
: 当 flag
为 true
时,UDP
服务器或者客户端可以利用其所用的 socket
端口对象的 send
方法中的地址修改为广播地址。服务端的代码定义在 server.js
文件,具体代码如下所示:
import dgram from "dgram"; const server = dgram.createSocket("udp4"); server.on("message", function (msg, rinfo) { console.log( "server got: " + msg + " from " + rinfo.address + ":" + rinfo.port ); }); server.on("listening", function () { var address = server.address(); console.log("server listening " + address.address + ":" + address.port); }); server.bind(3000);
客户端的代码定义在 server.js
文件,具体代码如下定义:
import dgram from "dgram"; import { Buffer } from "buffer"; const socket = dgram.createSocket("udp4"); const params = process.argv.splice(2); socket.bind(function () { socket.setBroadcast(true); }); const message = Buffer.from(...params); socket.send(message, 0, message.length, 3000, "255.255.255.255", () => { socket.close(); });
具体运行效果如下图所示:
更多node相关知识,请访问:nodejs 教程!
以上がNode における TCP と UDP の簡単な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。