基于net.socket的粘包和半包(Nodejs相关)

基于net.socket的粘包和半包(Nodejs相关)

一直用net.socket在局域网内做东西,一直没有出现粘包或者是半包的问题,偶然在群里看见几个前辈在讨论放到外网后会出现粘包的现象,应为是在局域网或者是数据不是很大信息量不是很多,所以很难被发现。这么说需要自己处理粘包写粘包处理,自己封了一层消息头里面包含了这个包的长度,但是写到后来忽然想到一种情况,就是包MSG1由于过大被分成了MSG-1和MSG-2 二个包发送,服务器接收到MSG-1后接收了另外的一个MSG2后再接收到了MSG-2呢不知道会不会出现…

5 回复

基于 net.socket 的粘包和半包问题(Node.js 相关)

在使用 Node.js 的 net 模块进行网络通信时,可能会遇到粘包和半包问题。这些问题在局域网中可能不太明显,但在外网环境中由于网络不稳定或传输延迟较大时,可能会频繁发生。

什么是粘包和半包?

  • 粘包:一个完整的数据包被拆分成多个小的数据包,或者多个数据包被合并成一个大包。
  • 半包:一个数据包没有完整地被接收,只接收到了部分数据。

如何处理粘包和半包?

为了处理粘包和半包问题,通常的做法是给每个数据包加上一个固定长度的消息头,消息头中包含数据包的实际长度。这样接收端可以根据消息头中的长度信息来完整地读取数据包。

示例代码

下面是一个简单的示例,展示如何使用 net 模块实现粘包和半包的处理:

const net = require('net');

// 创建服务器
const server = net.createServer((socket) => {
    console.log('Client connected');
    
    socket.on('data', (data) => {
        handleData(data, socket);
    });

    socket.on('end', () => {
        console.log('Client disconnected');
    });
});

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

function handleData(data, socket) {
    let buffer = data;
    
    while (buffer.length >= 4) { // 假设消息头长度为4字节
        const length = buffer.readUInt32BE(0); // 读取消息头中的长度
        
        if (buffer.length < length + 4) {
            break; // 数据包不完整,跳出循环
        }
        
        const message = buffer.slice(4, 4 + length); // 提取实际数据
        console.log(`Received message: ${message.toString()}`);
        
        buffer = buffer.slice(4 + length); // 更新缓冲区
    }

    if (buffer.length > 0) {
        // 如果缓冲区中还有剩余数据,则存储起来,等待下次接收
        console.log('Partial data:', buffer.toString());
    }
}

解释

  1. 创建服务器:首先创建一个 TCP 服务器,并监听客户端连接。
  2. 处理数据:当接收到数据时,首先检查缓冲区中的数据是否足够读取消息头(假设消息头长度为4字节)。
  3. 读取消息头:从缓冲区中读取消息头中的长度信息。
  4. 提取数据:根据消息头中的长度信息提取实际的数据包。
  5. 处理剩余数据:如果缓冲区中还有剩余数据,则继续处理,直到数据包完整。

通过这种方式,可以有效地解决粘包和半包问题,确保数据包的完整性。


前辈们都休息了吗

不能沉

【NodeJs的TCP中的粘包、分包问题的解决方案!?】问题传送门:https://github.com/lvgithub/stickPackage

粘包和半包问题是网络编程中常见的问题,尤其是在使用TCP协议时。TCP是一种流式协议,它不会为数据包添加边界标记。因此,当数据通过网络传输时,可能会出现多个数据包粘在一起(粘包),或者一个数据包被拆分成多个片段(半包)。

解决方案

为了处理这个问题,通常的做法是为每个数据包添加一个固定长度的消息头,该消息头包含当前数据包的实际长度。这样接收端可以根据这个长度来准确地解析出完整的数据包。

示例代码

以下是一个简单的示例,展示了如何在Node.js中处理粘包和半包问题:

const net = require('net');

// 创建服务器
const server = net.createServer((socket) => {
    console.log('Client connected');

    socket.on('data', (data) => {
        let totalLength = data.readUInt32BE(0); // 假设消息头长度为4字节
        let receivedLength = 4; // 已经读取的消息头长度

        let buffer = Buffer.alloc(totalLength);
        data.copy(buffer, 0, 0, totalLength);

        while (receivedLength < totalLength) {
            socket.on('data', (chunk) => {
                chunk.copy(buffer, receivedLength, 0, Math.min(chunk.length, totalLength - receivedLength));
                receivedLength += chunk.length;
            });
        }

        console.log('Received message:', buffer.toString());
    });

    socket.on('end', () => {
        console.log('Client disconnected');
    });
});

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

代码解释

  1. 消息头:我们假设消息头的长度为4字节,并且在这4字节中存储了整个数据包的长度。
  2. 接收数据:服务器接收到来自客户端的数据后,首先读取消息头中的长度信息。
  3. 拼接数据:然后,服务器根据总长度继续读取后续的数据片段,并将这些片段拼接到一起。
  4. 完整数据包:一旦接收到完整的数据包,就进行相应的处理。

这种方法确保即使数据被分割成多个片段,服务器也能正确地识别并组装完整的数据包。

回到顶部