发个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));
});
解释
-
类定义:
buffer
:用于存储接收到的数据。expectedLength
:表示当前数据包的预期长度。headerSize
:表示数据包头部的大小(假设为2字节)。callback
:当接收到完整数据包时调用的回调函数。
-
方法
putData
:- 将新数据追加到现有缓冲区。
- 检查缓冲区是否包含足够的数据以形成一个完整数据包。
- 如果包含,则调用回调函数并处理该数据包。
- 如果不包含,则更新缓冲区以等待更多数据。
-
回调函数
onReceivePacket
:- 简单地打印接收到的数据包。
-
使用示例:
- 创建
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
方法首先将新接收到的数据追加到现有的缓冲区中。- 然后检查缓冲区是否包含至少两个字节(即数据包长度)。
- 如果有足够的数据来组成一个完整包,就提取该包并调用回调函数。
- 剩余未处理的数据继续保留在缓冲区中,以供后续数据包的处理。
这样可以有效地处理粘包和分包问题,确保每个完整的数据包都被正确处理。