MST

星途 面试题库

面试题:Node.js TCP通信中如何处理粘包与拆包问题

在Node.js的TCP通信场景下,粘包与拆包是常见问题。请阐述粘包和拆包产生的原因,并说明至少两种处理粘包与拆包问题的方法,同时给出相应的代码示例。
21.3万 热度难度
前端开发Node.js

知识考点

AI 面试

面试题答案

一键面试

粘包和拆包产生的原因

  1. 发送端原因
    • Nagle算法:为了提高网络利用率,减少网络传输小包的开销,TCP协议默认启用Nagle算法。该算法会将小的数据包积累到一定大小或者等待一定时间后再发送。例如,应用层连续调用多次 send 方法发送数据,TCP协议可能会将这些小数据包合并成一个大的数据包发送出去,这就导致在接收端可能会出现粘包问题。
  2. 接收端原因
    • 缓冲区机制:接收端的TCP缓冲区在接收到数据后,应用层可能不会立即读取,或者一次读取的数据量小于缓冲区中的数据量。这样就会导致缓冲区中剩余的数据和下一次接收的数据粘在一起,从而产生粘包问题。另外,如果发送的数据量大于接收端缓冲区的大小,数据就会被拆分成多个部分进行传输,在接收端就会出现拆包问题。

处理粘包与拆包问题的方法及代码示例

  1. 定长包处理方法
    • 原理:每个数据包都固定长度。发送端发送固定长度的数据包,接收端每次按固定长度读取数据。
    • 代码示例
const net = require('net');
const server = net.createServer((socket) => {
    let buffer = '';
    socket.on('data', (data) => {
        buffer += data.toString('utf8');
        while (buffer.length >= 10) { // 假设每个包固定长度为10
            const packet = buffer.substr(0, 10);
            buffer = buffer.substr(10);
            console.log('Received:', packet);
        }
    });
});
server.listen(8080, () => {
    console.log('Server listening on port 8080');
});

const client = net.connect({ port: 8080 }, () => {
    const packets = ['HelloWorld', 'NodejsTCP'];
    packets.forEach((packet) => {
        // 假设每个包固定长度为10,不足10补空格
        let fixedPacket = packet.padEnd(10,' ');
        client.write(fixedPacket);
    });
});
  1. 包头 + 包体处理方法
    • 原理:数据包由包头和包体组成,包头中包含包体的长度等信息。发送端先发送包头,接收端先接收包头获取包体长度,再根据包体长度接收包体。
    • 代码示例
const net = require('net');
const server = net.createServer((socket) => {
    let buffer = Buffer.alloc(0);
    socket.on('data', (data) => {
        buffer = Buffer.concat([buffer, data]);
        while (buffer.length >= 4) { // 假设包头长度为4,存储包体长度
            const bodyLength = buffer.readUInt32BE(0);
            if (buffer.length >= 4 + bodyLength) {
                const body = buffer.slice(4, 4 + bodyLength);
                buffer = buffer.slice(4 + bodyLength);
                console.log('Received:', body.toString('utf8'));
            } else {
                break;
            }
        }
    });
});
server.listen(8080, () => {
    console.log('Server listening on port 8080');
});

const client = net.connect({ port: 8080 }, () => {
    const messages = ['Hello Nodejs', 'TCP Communication'];
    messages.forEach((message) => {
        const body = Buffer.from(message, 'utf8');
        const header = Buffer.alloc(4);
        header.writeUInt32BE(body.length, 0);
        client.write(Buffer.concat([header, body]));
    });
});