node.js中net網路模組TCP服務端與客戶端的使用
阿新 • • 發佈:2019-01-10
node.js中net模組為我們提供了TCP伺服器和客戶端通訊的各種介面。
一、建立伺服器並監聽埠
const net = require('net'); //建立一個tcp服務 //引數一表示建立服務的一些配置 //引數二表示 事件 'connection' 監聽回撥函式 let server = net.createServer({ //表示是否允許一個半開的TCP連線,預設為false allowHalfOpen: false, //一旦來了連線,是否暫停套接字,預設為false pauseOnConnect: false }); server.listen(6666); //一個新的連線建立時觸發 'connection' 事件 server.on('connection', function (socket) { //注意這裡的socket是一個流,既可以讀,也可以寫 //當我們監聽 'data' 事件後,系統就會不斷的從流中讀取資料 socket.on('data', function (data) { console.log('伺服器接收到 : ', data.toString()); }); }); //服務呼叫 server.listen() 監聽後就會觸發該事件 server.on('listening', function () { // address() 方法返回伺服器地址資訊物件 let addr = server.address(); console.log(`伺服器監聽 : ${addr.port} 埠`); }); //服務關閉時觸發,如果還有連線存在,則直到所有連線結束才會觸發該事件 server.on('close', function () { console.log('服務關閉'); }); //出現錯誤時觸發 server.on('error', function (err) { console.log(err); });
windows下可以通過telnet 或 xshell,putty等工具連線上該服務,進行互動。
我們可以通過 getConnections() 實時獲取當前伺服器的連線數。
const net = require('net'); let server = net.createServer(); server.listen(6666, '0.0.0.0', function () { console.log('伺服器監聽開始'); }); //一個新的連線建立時觸發 'connection' 事件 server.on('connection', function (socket) { //獲取當前伺服器的連線數 server.getConnections(function (error, count) { console.log('當前伺服器的連線數 : ', count); }); socket.on('data', function (data) { console.log('伺服器接收到 : ', data.toString()); }); });
我們可以手動的設定伺服器的最大連線數,如果超過該連線數,則會拒絕連線。
const net = require('net'); let server = net.createServer(); server.listen(6666, '0.0.0.0', function () { console.log('伺服器監聽開始'); //設定最大連線數為3,當有第4個連線請求時,連線會拒絕。 server.maxConnections = 3; }); //一個新的連線建立時觸發 'connection' 事件 server.on('connection', function (socket) { //獲取當前伺服器的連線數 server.getConnections(function (error, count) { console.log('當前伺服器的連線數 : ', count); }); socket.on('data', function (data) { console.log('伺服器接收到 : ', data.toString()); }); });
我們也可以使用 close() 手動的拒絕所有連線請求,當已連線的客戶端都關閉後,則伺服器會自動關閉,並觸發 'close' 事件。
const net = require('net'); let server = net.createServer(); server.listen(6666, '0.0.0.0', function () { console.log('伺服器監聽開始'); }); //一個新的連線建立時觸發 'connection' 事件 server.on('connection', function (socket) { //獲取當前伺服器的連線數 server.getConnections(function (error, count) { console.log('當前伺服器的連線數 : ', count); }); socket.on('data', function (data) { console.log('伺服器接收到 : ', data.toString()); }); }); server.on('close', function () { console.log('伺服器被關閉'); }); //5秒後手動關閉伺服器,拒絕所有連線請求,已有連線全部關閉後,觸發 'close' 事件 setTimeout(function () { server.close(); }, 5000);
呼叫 unref() 後,則當所有客戶端連線關閉後,將關閉伺服器。ref() 功能與 unref() 相反。
const net = require('net'); let server = net.createServer(); server.listen(6666, '0.0.0.0', function () { console.log('伺服器監聽開始'); }); //一個新的連線建立時觸發 'connection' 事件 server.on('connection', function (socket) { //獲取當前伺服器的連線數 server.getConnections(function (error, count) { console.log('當前伺服器的連線數 : ', count); }); socket.on('data', function (data) { console.log('伺服器接收到 : ', data.toString()); }); socket.on('close', function () { console.log('客戶端關閉'); //呼叫unref()後,當所有客戶端連線都關閉後,將關閉伺服器 server.unref(); }); }); server.on('close', function () { console.log('伺服器關閉'); });
二、net.Socket是一個socket埠物件,是一個全雙工的可讀可寫流
const net = require('net'); let server = net.createServer(); server.listen(6666, '0.0.0.0', function () { console.log('伺服器監聽開始'); }); server.on('connection', function (socket) { //獲取當前伺服器的連線數 server.getConnections(function (error, count) { console.log('當前伺服器的連線數 : ', count); }); console.log('客戶端資訊 : ', socket.address()); //接收到資料時觸發 socket.on('data', function (data) { //我們可以從流中讀取資料 console.log('伺服器接收到 : ', data.toString()); console.log('累計接收的資料大小 : ', socket.bytesRead); console.log('累計傳送的資料大小 : ', socket.bytesWritten); //也可以向流中寫入資料 let flag = socket.write(`伺服器向你傳送 : ${data.toString()} \r\n`); console.log('flag : ', flag); console.log('當前已緩衝並等待寫入流中的位元組數 : ', socket.bufferSize); }); //連線關閉時觸發 socket.on('end', function () { console.log('客戶端關閉'); }); //連線完全關閉時觸發 socket.on('close', function () { console.log('客戶端完全關閉'); }); //發生錯誤時觸發 socket.on('error', function (err) { console.log(err); }); });
我們可以通過 puase() 和 resume() 方法暫停讀寫資料。
const net = require('net'); let server = net.createServer(); server.listen(6666, '0.0.0.0', function () { console.log('伺服器監聽開始'); }); server.on('connection', function (socket) { //獲取當前伺服器的連線數 server.getConnections(function (error, count) { console.log('當前伺服器的連線數 : ', count); }); //接收到資料時觸發 socket.on('data', function (data) { console.log('接收到的資料 : ', data.toString()); setTimeout(function () { //3秒後暫停讀取資料 socket.pause(); }, 3000); setTimeout(function () { //6秒後恢復讀取資料 socket.resume(); }, 6000); }); });
net.Socket物件是一個流,既然是流,那麼我們可以通過 pipe() 方法建一個到檔案的可寫流,把從客戶端接收的資料寫入到一個檔案中。
const net = require('net'); const fs = require('fs'); let server = net.createServer(); server.listen(6666, '0.0.0.0', function () { console.log('伺服器監聽開始'); }); let ws = fs.createWriteStream('./1.txt'); server.on('connection', function (socket) { //獲取當前伺服器的連線數 server.getConnections(function (error, count) { console.log('當前伺服器的連線數 : ', count); }); //接收到資料時觸發 socket.on('data', function (data) { console.log('接收到的資料 : ', data.toString()); }); //注意這裡的第二個引數,設為 false。 //每當有一個新的連線時,就會建立一個新的 socket 物件。 //不然當第一個socket物件結束操作或關閉時,會自動關閉 ws 可寫流。 //後續的socket物件將無法往 ws 裡寫入資料。 socket.pipe(ws, {end: false}); socket.on('end', function () { console.log('客戶端關閉'); socket.unpipe(ws); }); });
通過 setTimeout() 我們可以設定一個連線活動的超時時間,當一個連線超時時,將觸發 'timeout' 事件。
const net = require('net'); let server = net.createServer(); server.listen(6666, '0.0.0.0', function () { console.log('伺服器監聽開始'); }); server.on('connection', function (socket) { //獲取當前伺服器的連線數 server.getConnections(function (error, count) { console.log('當前伺服器的連線數 : ', count); }); //接收到資料時觸發 socket.on('data', function (data) { console.log('接收到的資料 : ', data.toString()); }); socket.setTimeout(3 * 1000); //連線超時後,並不會斷開,需手動呼叫 end() 或 destroy() 來斷開連線 socket.on('timeout', function () { console.log('當前連線已超時'); }); });
三、建立一個tcp客戶端
const net = require('net'); //建立一個tcp客戶端 let client = new net.Socket(); client.connect({ host: '127.0.0.1', port: 6666 }); //客戶端與伺服器建立連線觸發 client.on('connect', function () { client.write('你好伺服器'); }); //客戶端接收資料觸發 client.on('data', function (data) { console.log('伺服器傳送的資料 : ', data.toString()); });
客戶端可以通過呼叫 end() 方法來主動關閉與服務端的連線。
const net = require('net'); //建立一個tcp客戶端 let client = new net.Socket(); client.connect({ host: '127.0.0.1', port: 6666 }); //客戶端與伺服器建立連線時觸發 client.on('connect', function () { //往服務端寫入資料 client.write('你好伺服器'); }); //客戶端接收資料時觸發 client.on('data', function (data) { console.log('伺服器傳送的資料 : ', data.toString()); }); setTimeout(function () { client.end(); }, 3000);
通過 setKeepAlive() 方法來禁用或啟用長連線功能,防止時間過短而斷開連線。setKeepAlive() 會發送一個空包,來保持通訊。
const net = require('net'); //建立一個tcp客戶端 let client = new net.Socket(); client.connect({ host: '127.0.0.1', port: 6666 }); //設定連線保持 client.setKeepAlive(true, 3000); //客戶端與伺服器建立連線觸發 client.on('connect', function () { client.write('你好伺服器'); }); //客戶端接收資料觸發 client.on('data', function (data) { console.log('伺服器傳送的資料 : ', data.toString()); }); setTimeout(function () { client.end(); }, 3000);