发个Nodejs处理socket粘包、分包的方法~求前辈们指点下~

发个Nodejs处理socket粘包、分包的方法~求前辈们指点下~

对JS的API还是不太熟悉,第一次写求各位指点指点

function exPackag(aCallback)
{
this.mBuffer=new Array();//缓冲容器
this.mBuffer_len=0;//协议长度
this.mData_len_Median=2;//协议的长度所占的位数
this.mCallback=aCallback;//回调函数
}

exPackag.prototype.putData=function(aData)
{
if(this.mBuffer_len==0)
{
	if(aData.length<this.mData_len_Median)
	{
		console.log('包头不全直接忽略');
		return;//包头不全直接忽略
	}else{
		this.mBuffer_len=getIntToByte16(aData)+this.mData_len_Median;
	}
}
for(var index=0; index<aData.length; index++) {
	this.mBuffer.push(aData[index]);
}
while (true)
 {
	/** 如果缓存中的长度刚好是一个包的长度*/
	if(this.mBuffer.length==this.mBuffer_len){
		this.mCallback(this.mBuffer);
		this.mBuffer=null;
		this.mBuffer=new Array();
		this.mBuffer_len=0;
		return;
	}
	/** 如果缓存中的长度大于一个包的长度*/
	else if (this.mBuffer.length>this.mBuffer_len){
		/** 先获取一个完整的包*/
		var tBuffer=this.mBuffer.splice(0,this.mBuffer_len);
		this.mCallback(tBuffer);
		tBuffer=null;
		if(this.mBuffer.length>=this.mData_len_Median)
		{
			this.mBuffer_len=getIntToByte16(this.mBuffer)+this.mData_len_Median;
		}
	}else{
		/** 不满足长度*/
		console.log('长度不符合退出');
		return;
	}
}
}


function getIntToByte16(aRecv){
var targets= (aRecv[0] & 0xff)| ((aRecv[1]<<8) & 0xff00);
return targets;
}

exports.exPackag = exPackag;

/*******************使用***********************************/

var mPackageSystem=require('../shared/packageSystem');
var tBuffer=new mPackageSystem.exPackag(onReceivePackData);
sock.on('data', function(data) {
    tBuffer.putData(data);
});
/** 一个完整的包*/
function onReceivePackData(aBuffer)
{
    console.log(aBuffer);
}

3 回复

发个Nodejs处理socket粘包、分包的方法

大家好,我正在学习Node.js中处理socket通信时遇到的粘包和分包问题。希望能得到前辈们的指点。

背景

在处理网络数据传输时,经常会遇到数据包粘连(多个数据包粘在一起)或者数据包被分割成多部分(单个数据包被分成多个部分)的情况。为了解决这些问题,我编写了一个简单的类来管理数据的接收和解析。

示例代码

function ExPackage(aCallback) {
    this.buffer = new Uint8Array(); // 缓冲区
    this.expectedLength = 0; // 预期的数据包长度
    this.headerSize = 2; // 数据包头部大小(假设头部为2字节)
    this.callback = aCallback; // 回调函数
}

ExPackage.prototype.putData = function (data) {
    const newData = new Uint8Array([...this.buffer, ...data]);
    
    while (newData.length >= this.headerSize) {
        if (this.expectedLength === 0) {
            // 计算预期的数据包长度
            this.expectedLength = newData[0] + (newData[1] << 8);
        }

        if (newData.length >= this.expectedLength) {
            // 当前缓冲区包含一个完整数据包
            const packet = newData.slice(0, this.expectedLength);
            this.callback(packet);

            // 移除已处理的数据包
            newData = newData.slice(this.expectedLength);
            this.expectedLength = 0; // 重置预期长度
        } else {
            // 当前缓冲区数据不足一个完整数据包
            break;
        }
    }

    this.buffer = newData; // 更新缓冲区
};

// 示例回调函数
function onReceivePacket(packet) {
    console.log('Received packet:', packet);
}

// 使用示例
const packageSystem = require('./packageSystem');
const packetHandler = new packageSystem.ExPackage(onReceivePacket);

// 假设 sock 是一个已连接的 socket 对象
sock.on('data', function (data) {
    packetHandler.putData(new Uint8Array(data));
});

解释

  1. 类定义

    • buffer:用于存储接收到的数据。
    • expectedLength:表示当前数据包的预期长度。
    • headerSize:表示数据包头部的大小(假设为2字节)。
    • callback:当接收到完整数据包时调用的回调函数。
  2. 方法 putData

    • 将新数据追加到现有缓冲区。
    • 检查缓冲区是否包含足够的数据以形成一个完整数据包。
    • 如果包含,则调用回调函数并处理该数据包。
    • 如果不包含,则更新缓冲区以等待更多数据。
  3. 回调函数 onReceivePacket

    • 简单地打印接收到的数据包。
  4. 使用示例

    • 创建 ExPackage 实例,并将其与 socket 的 'data' 事件关联起来。

希望这个示例能帮助你更好地理解和处理Node.js中的socket粘包和分包问题。如果有任何疑问或建议,请留言!


处理Socket粘包和分包问题通常需要定义一种协议来确定数据包的边界。这里提供一个简单的例子,使用前两个字节表示数据包的长度,并据此来处理数据包。

以下是一个简化的实现:

const net = require('net');

class PacketHandler {
    constructor(callback) {
        this.buffer = Buffer.alloc(0);
        this.callback = callback;
    }

    handleData(data) {
        this.buffer = Buffer.concat([this.buffer, data]);

        while (this.buffer.length >= 2) {
            const packetLength = this.buffer.readUInt16BE(0);
            if (this.buffer.length < packetLength + 2) break;

            const packet = this.buffer.slice(2, packetLength + 2);
            this.callback(packet);

            this.buffer = this.buffer.slice(packetLength + 2);
        }
    }
}

const server = net.createServer((socket) => {
    const handler = new PacketHandler((packet) => {
        console.log(`Received: ${packet.toString()}`);
    });

    socket.on('data', (data) => {
        handler.handleData(data);
    });
});

server.listen(8080, () => {
    console.log('Server listening on port 8080');
});

解释:

  • PacketHandler 类负责管理数据包的接收和解析。
  • handleData 方法首先将新接收到的数据追加到现有的缓冲区中。
  • 然后检查缓冲区是否包含至少两个字节(即数据包长度)。
  • 如果有足够的数据来组成一个完整包,就提取该包并调用回调函数。
  • 剩余未处理的数据继续保留在缓冲区中,以供后续数据包的处理。

这样可以有效地处理粘包和分包问题,确保每个完整的数据包都被正确处理。

回到顶部