1. 程式人生 > >node.js中net網路模組TCP服務端與客戶端的使用

node.js中net網路模組TCP服務端與客戶端的使用

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);