# 解决TCP粘包问题 **Repository Path**: cocos_creater_projects/tcp-sticky ## Basic Information - **Project Name**: 解决TCP粘包问题 - **Description**: 封装一个pipe类,解决tcp粘包问题 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-04-03 - **Last Updated**: 2025-04-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### 解决TCP粘包问题 #### TCP粘包 - TCP粘包现象:TCP是面向流的协议,它会将多个小数据包合并成一个大的数据包进行传输,以提高传输效率。这就导致了接收端无法区分原始数据的边界 - 客户端多次写入信息 ![客户端代码](./img/粘包复现1.png) - 服务端打印,第一次正常,后面九次拼接到了一起 ![服务端代码](./img/粘包复现2.png) #### 解决办法 主流解决办法:数据以定长 header(2个字节) + body(若干字节)的格式来封装 1. 封装一个pipe类: ``` typescript import { EventEmitter } from 'events' /** * 解决TCP粘包问题 * 主流解决办法:数据以定长 header(2个字节) + body(若干字节)的格式来封装 * 过程: * 维护一个数组pipe,每次接收到data就push到pipe中 * 然后判断pipe的长度是否够2个字节,够就读出header的值 * 从而得到body的长度, 这个package的长度就是header + body * 从而的出这次传输的具体数据 */ export class Pipe extends EventEmitter { private pipe: Buffer = Buffer.alloc(0) constructor() { super() } push(buffer: Buffer) { this.pipe = Buffer.concat([this.pipe, buffer]) while (this.pipe.length > 2) { const bodyLength = this.pipe.readUInt16BE(0) const packLength = bodyLength + 2 if (this.pipe.length >= packLength) { const data = this.pipe.subarray(2, packLength) this.pipe = this.pipe.subarray(packLength) this.emit('data', data) } else { break } } } pack(data: any) { const body = Buffer.from(JSON.stringify(data)) const header = Buffer.alloc(2) header.writeUInt16BE(body.length) const buffer = Buffer.concat([header, body]) return buffer } } ``` 2. 在client中调用pipe的pack方法 ``` typescript import net from 'net' import { Pipe } from './pipe' const client = net.createConnection({ host: 'localhost', port: 6666, }) const pipe = new Pipe() const buffer = pipe.pack('Hello, server!') client.write(buffer) client.write(buffer) client.write(buffer) client.write(buffer) client.write(buffer) client.write(buffer) client.write(buffer) client.write(buffer) client.write(buffer) client.write(buffer) ``` 3. 在server中接收到data中,调用pipe的push方法,同时监听pipe的data方法 ``` typescript import net from 'net' import { Pipe } from './pipe' const server = net.createServer() server.listen(6666, () => { console.log('Server is running on port 6666') }) server.on('connection', (socket) => { const pipe = new Pipe() socket.on('data', (buffer) => { pipe.push(buffer) }) pipe.on('data', (data) => { console.log('data:', data.toString()) }) }) ``` 4. 重启server端服务和client端服务,发现粘包问题解决 ![server端打印日志](./img/server端打印日志.png) #### 版本依赖 node: 20.18.0 pnpm: 10.4.1