一文搞懂如何使用Node.js進行TCP網路通訊
摘要: 網路是通訊互聯的基礎,Node.js提供了net、http、dgram等模組,分別用來實現TCP、HTTP、UDP的通訊,本文主要對使用Node.js的TCP通訊部份進行實踐記錄。
本文分享自華為雲社區《一文搞懂如何使用Node.js進行TCP網路通訊》,作者:lwq1228 。
1、構建TCP伺服器
1.1、使用Node.js創建TCP伺服器
為了使用Node.js創建TCP伺服器,首先要調用require(『net』)來載入net模組,然後調用net模組的createServer方法就可以輕鬆地創建一個TCP伺服器,語法格式如下:
net.createServer([options][, connectionListener])
options是一個對象參數值,有兩個布爾類型的屬性allowHalfOpen和pauseOnConnect。這兩個屬性默認都是false;
connectionListener是一個當客戶端與服務端建立連接時的回調函數,這個回調函數以socket埠對象作為參數。
1.2、監聽客戶端的連接
使用TCP伺服器的listen方法就可以開始監聽客戶端的連接,語法格式如下:
server.listen(port[, host][, backlog][, callback]);
port:為需要監聽的埠號,參數值為0的時候將隨機分配一個埠號;
host:伺服器地址;
backlog:連接等待隊列的最大長度;
callback:回調函數。
以下程式碼可以創建一個TCP伺服器並監聽8001埠:
//引入net模組 const net = require('net'); //創建TCP伺服器 const server = net.createServer(function (socket) { console.log('有新的客戶端接入'); }); //設置監聽埠 server.listen(8001, function () { console.log('服務正在監聽中。。。') });
運行這段程式碼,可以在控制台看到執行了listen方法的回調函數,如圖所示:
可以使用相應的TCP客戶端或者調試工具來連接這個已經創建好的TCP伺服器。例如,要使用Windows的Telnet就可以用以下命令來連接:
telnet localhost 8001
連接成功後可以看到控制台列印了「有新的客戶端接入」字樣,表明createServer方法的回調函數已經執行,說明已經成功連接到這個創建好的TCP伺服器。
server.listen()方法其實觸發的是server下的listening事件,所以也可以手動監聽listening事件,程式碼如下:
//設置監聽埠 server.listen(8001); //設置監聽時的回調函數 server.on('listening', function () { console.log("服務正在監聽中。。。") });
除了listening事件外,TCP伺服器還支援以下事件:
connection:當有新的鏈接創建時觸發,回調函數的參數為socket連接對象。
close:TCP伺服器關閉的時候觸發,回調函數沒有參數。
error:TCP伺服器發生錯誤的時候觸發,回調函數的參數為error對象。
下列程式碼通過net.Server類來創建一個TCP伺服器,添加以上事件:
//引入net模組 const net = require('net'); //實例化一個伺服器對象 const server = new net.Server(); //監聽connection事件 server.on('connection', function (socket) { console.log('有新的客戶端接入'); }); //設置監聽埠 server.listen(8001); //設置監聽時的回調函數 server.on('listening', function () { console.log('服務正在監聽中。。。'); }); //設置關閉時的回調函數 server.on('close', function () { console.log('服務已關閉'); }); //設置出錯時的回調函數 server.on('error', function (err) { console.log('服務運行異常', err); });
1.3、查看伺服器監聽的地址
當創建了一個TCP伺服器後,可以通過server.address()方法來查看這個TCP伺服器監聽的地址,並返回一個JSON對象,因為這個方法返回的是TCP伺服器監聽的地址資訊,所以應該在調用了server.listen()方法或者綁定了事件listening中的回調函數中調用該方法。這個對象的屬性有:
port:TCP伺服器監聽的埠號;
family:說明TCP伺服器監聽的地址是IPv6還是IPv4;
address:TCP伺服器監聽的地址。
程式碼如下:
//引入net模組 const net = require('net'); //創建TCP伺服器 const server = net.createServer(function (socket) { console.log('有新的客戶端接入'); }); //設置監聽埠 server.listen(8001); //設置監聽時的回調函數 server.on('listening', function () { //獲取地址資訊 let address = server.address(); //獲取地址詳細資訊 console.log("伺服器監聽的埠是:" + address.port); console.log("伺服器監聽的地址是:" + address.address); console.log("伺服器監聽的地址類型是:" + address.family); });
運行結果如圖:
1.4、連接伺服器的客戶端數量
創建一個TCP伺服器後,可以通過server.getConnections()方法獲取連接這個TCP伺服器的客戶端數量。這個方法是一個非同步的方法,回調函數有兩個參數:
第一個參數為error對象。
第二個參數為連接TCP伺服器的客戶端數量。
除了獲取連接數外,也可以通過設置TCP伺服器的maxConnections屬性來設置這個TCP伺服器的最大連接數。當連接數超過最大連接數的時候,伺服器將拒絕新的連接。如下程式碼設置這個TCP伺服器的最大連接數為3。
//引入net模組 const net = require('net'); //創建TCP伺服器 const server = net.createServer(function (socket) { console.log('有新的客戶端接入'); //設置最大連接數量 server.maxConnections = 3; server.getConnections(function (err, count) { console.log("當前連接的客戶端個數為:" + count); }); }); //設置監聽埠 server.listen(8001, function () { console.log("服務正在監聽中。。。") });
運行這段程式碼,並嘗試用多個客戶端連接。可以發現當客戶端連接數超過3的時候,新的客戶端就無法連接這個伺服器了,如圖所示:
1.5、獲取客戶端發送的數據
createServer方法的回調函數參數是一個net.Socket對象(伺服器所監聽的埠對象),這個對象同樣也有一個address()方法,用來獲取TCP伺服器綁定的地址,同樣也是返回一個含有port、family、address屬性的對象。通過socket對象可以獲取客戶端發送的流數據,每次接收到數據的時候觸發data事件,通過監聽這個事件就可以在回調函數中獲取客戶端發送的數據,程式碼如下:
//引入net模組 const net = require('net'); //創建TCP伺服器 const server = net.createServer(function (socket) { //監聽data事件 socket.on("data", function (data) { //列印數據 console.log("接收到數據:" + data.toString()); }); }); //設置監聽埠 server.listen(8001, function () { console.log("服務正在監聽中。。。") });
測試結果如下:
socket對象除了有data事件外,還有connect、end、error、timeout等事件。
1.6、發送數據給客戶端
調用socket.write()可以使TCP伺服器發送數據,這個方法只有一個必需參數,就是需要發送的數據;第二個參數為編碼格式,可選。同時,可以為這個方法設置一個回調函數。當有用戶連接TCP伺服器的時候,將發送數據給客戶端,程式碼如下:
//引入net模組 const net = require('net'); //創建TCP伺服器 const server = net.createServer(function (socket) { //設置消息內容 const message = "Hello Client......"; //發送數據 socket.write(message, function () { const writeSize = socket.bytesWritten; console.log("數據發送成功,數據長度為:" + writeSize); }); //監聽data事件 socket.on("data", function (data) { const readSize = socket.bytesRead; //列印數據 console.log("接收到數據為:" + data.toString(), ";接收的數據長度為:" + readSize); }); }); //設置監聽埠 server.listen(8001, function () { console.log("服務正在監聽中。。。") });
測試結果如下:
在上面這段程式碼中還用到了socket對象的bytesWritten和bytesRead屬性,這兩個屬性分別代表著發送數據的位元組數和接收數據的位元組數。除了上面這兩個屬性外,socket對象還有以下屬性:
socket.localPort:本地埠的地址;
socket.localAddress:本地IP地址;
socket.remotePort:進程埠地址;
socket.remoteFamily:進程IP協議族;
socket.remoteAddress:進程IP地址。
2、構建TCP客戶端
Node.js在創建一個TCP客戶端的時候同樣使用的是net(網路)模組。
2.1、使用Node.js創建TCP客戶端
為了使用Node.js創建TCP客戶端,首先要調用require(『net』)來載入net模組。創建一個TCP客戶端只需要創建一個連接TCP客戶端的socket對象即可:
//引入net模組 const net = require('net'); //創建TCP客戶端 const client = new net.Socket();
創建一個socket對象的時候可以傳入一個json對象。這個對象有以下屬性:
fd:指定一個存在的文件描述符,默認值為null;
readable:是否允許在這個socket上讀,默認值為false;
writeable:是否允許在這個socket上寫,默認值為false;
allowHalfOpen:該屬性為false時,TCP伺服器接收到客戶端發送的一個FIN包後,將會回發一個FIN包;該屬性為true時,TCP伺服器接收到客戶端發送的一個FIN包後不會回發FIN包。
2.2、連接TCP伺服器
創建了一個socket對象後,調用socket對象的connect()方法就可以連接一個TCP伺服器,程式碼如下:
//引入net模組 const net = require('net'); //創建TCP客戶端 const client = new net.Socket(); //設置連接的伺服器 client.connect(8001, '127.0.0.1', function () { console.log("連接伺服器成功"); });
連接成功如下圖所示:
2.3、獲取從TCP伺服器發送的數據
socket對象有data、error、close、end等事件,因可以通過監聽data事件來獲取從TCP伺服器發送的數據,程式碼如下:
//引入net模組 const net = require('net'); //創建TCP客戶端 const client = new net.Socket(); //設置連接的伺服器 client.connect(8001, '127.0.0.1', function () { console.log("連接伺服器成功"); }); //監聽data事件 client.on("data", function (data) { //列印數據 console.log("接收到數據為:" + data.toString()); });
先啟動TCP服務端,再運行上面客戶端,可以發現命令行中已經輸出了來自服務端的數據,說明此時已經實現了服務端和客戶端之間的通訊:
2.4、向TCP伺服器發送數據
因為TCP客戶端是一個socket對象,所以可以使用以下程式碼來向TCP伺服器發送數據:
//引入net模組 const net = require('net'); //創建TCP客戶端 const client = new net.Socket(); //設置連接的伺服器 client.connect(8001, '127.0.0.1', function () { console.log("連接伺服器成功"); //給服務端發送數據 client.write("Hello Server......"); }); //監聽data事件 client.on("data", function (data) { //列印數據 console.log("接收到數據為:" + data.toString()); }); //監聽end事件 client.on("end", function () { console.log("客戶端發送數據結束") });
客戶端控制台輸出:
服務端控制台輸出:
至此使用Node.js進行TCP網路通訊完成,如有不對的地方歡迎指正