TCP 粘包處理

安裝

npm i @lvgithub/stick

背景

由于 TCP 協(xié)議是面向流的協(xié)議,我們使用 TCP 通信的時候,需要解析出我們的數(shù)據(jù),就需要對流進行解析。也就是所謂的拆包,把流解析為一段段我們所需要的數(shù)據(jù)。本方案為 Node.Js 實現(xiàn)的一個粘包處理方案。喜歡的話 star,想訂閱點 watch~

原理

對要發(fā)送的數(shù)據(jù)進行協(xié)議編碼,把一份數(shù)據(jù)data分為 header +body兩個結(jié)構(gòu),header 默認(rèn)固定長度(2 byte),header的內(nèi)容描述的是 body 數(shù)據(jù)的長度。由于header定長,因此可以通過解析header,動態(tài)解析 body 的內(nèi)容。

默認(rèn) header 我們使用 2 Byte 的存儲空間,即Int16最大表示的 body 長度為 32767,也就是16M

image-20200704170816148.png

如上圖,我們看先取出數(shù)據(jù)流的前兩位,讀取到內(nèi)容 0x00, 0x02轉(zhuǎn)化為整數(shù)的長度是 2,再讀取出body第3、4位 0x61, 0x62。下面是一個簡單的demo:

// example/tcpSample.js
'use strict';
const net = require('net');
const { Stick, MaxBodyLen } = require('../index');
const stick = new Stick(1024);

// 設(shè)置最大傳輸body大小為 32K,即 header用兩個 Byte,最大表示的值為 32767
stick.setMaxBodyLen(MaxBodyLen['32K']);

// server端
const server = net.createServer(socket => {
  
    // socket 接收到的 片段 put 到 stick 中處理
    socket.on('data', data => {
        stick.putData(data);
    });
  
    // stick 會解析好一個個數(shù)據(jù)包,按照接收的順序輸出
    stick.onBody(body => {
        console.log('body:', body.toString());
    });

    server.close();
});
server.listen(8080);

// client 端
const client = net.createConnection({ port: 8080, host: 'localhost' }, () => {
  
    // 客戶端通過 stick 打包內(nèi)容
    const data = stick.makeData(JSON.stringify({ userName: 'liuwei' }));
  
    // 然后把打包對的內(nèi)容通過 TCP 發(fā)送給 服務(wù)端
    client.write(data);
  
    client.destroy();
});

Output:

$ node example/sample.js
body: {"userName":"liuwei"}

More Example

API

  • Class: Stick

    • new Stick(bufferSize: number)

      Stick 類用于處理數(shù)據(jù)包,從流中解析出用戶定義的一塊快數(shù)據(jù)

      • bufferSize Stick處理數(shù)據(jù)包初始化的緩存大小,默認(rèn) 512 Bytes
- **putData(buf: Buffer)**

    往 stick 中put 收到的數(shù)據(jù)流

    

- **onData(callback)**

    當(dāng)收到的數(shù)據(jù)流中包含了完整的數(shù)據(jù)塊,觸發(fā)回調(diào)返回數(shù)據(jù)塊(`header`+`body`)

    * **callback**: (buf: Buffer): void

    

- **onBody(callback)**

    當(dāng)收到的數(shù)據(jù)流中包含了完整的數(shù)據(jù)塊,觸發(fā)回調(diào)返回數(shù)據(jù)內(nèi)容(`body`)

    

- **makeData(body: string): Buffer**

    用于客戶端中,幫助生成符合 Stick 協(xié)議的數(shù)據(jù)塊(`data`)

    

- **setMaxBodyLen(length: MaxBodyLen)**

    設(shè)置`body` 的最大長度,提供兩種配置見 ** MaxBodyLen**
  • Enum: MaxBodyLen

    • 32K 最大32kb
    • 2048M 最大 2048M

多語言

目前數(shù)據(jù)打包方式只提供了 Node.Js 包,stick.makeData()但現(xiàn)實場景中可能很多時間,客戶端是其他語言編寫的比如C語言運行在單片機上,這時候大家可以基原理圖自行打包,規(guī)則所示:

data = header(body.length) + body

License

MIT

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容