Socket.IO高频高量发送消息出现丢包,如何保证客户端完整接收所有消息?
问题根因
你遇到的断连+丢消息问题核心有两个:
- 短时间内密集发送大量大体积Base64消息,超过Socket.IO默认的传输缓冲区和报文大小限制,触发传输错误导致断连
- 没有实现消息确认、断点续传机制,断连期间发送的消息没有补发逻辑
解决方案
1. 实现ACK确认的受控发送逻辑,禁止一次性批量推送
不要直接用forEach一口气发完全部消息,改为分批发送+客户端确认机制,确保上一批消息客户端确认收到后再发下一批,同时支持重连后从断点续传:
服务端示例代码
// 给每条图片消息加唯一自增ID,方便做断点追踪 const imgList = [原大数组].map((base64, index) => ({ id: index, content: base64 })); const BATCH_SIZE = 50; // 可根据实际网络情况调整单批发送数量 let sendPointer = 0; // 批量发送函数 function sendNextBatch(socket) { const batch = imgList.slice(sendPointer, sendPointer + BATCH_SIZE); if (batch.length === 0) { socket.emit('allImgSent', { total: imgList.length }); // 通知客户端全部发送完成 return; } // 发送批次,等待客户端ACK确认 socket.emit('imgBatch', batch, (ackResult) => { if (ackResult.received) { sendPointer += BATCH_SIZE; sendNextBatch(socket); } }); } // 监听客户端重连后上报的最后收到的消息ID,调整发送指针 socket.on('reportLastId', (lastReceivedId) => { sendPointer = lastReceivedId + 1; sendNextBatch(socket); }); // 首次连接启动发送 sendNextBatch(socket);
客户端示例代码
let lastReceivedImgId = -1; // 接收图片批次 socket.on('imgBatch', (batch, ackCallback) => { batch.forEach(imgItem => { // 你的业务处理逻辑 lastReceivedImgId = Math.max(lastReceivedImgId, imgItem.id); }); // 返回确认收到的ACK ackCallback({ received: true }); }); // 重连成功后上报最后收到的ID,触发续传 socket.on('connect', () => { socket.emit('reportLastId', lastReceivedImgId); }); // 完整性校验 socket.on('allImgSent', ({ total }) => { const receivedCount = lastReceivedImgId + 1; if (receivedCount < total) { // 少收的主动向服务端请求补发对应ID的图片即可 } });
2. 调优Socket.IO传输配置
服务端初始化时调整缓冲区、超时相关参数,避免大流量下误判断连:
const io = require('socket.io')(server, { maxHttpBufferSize: 1e8, // 最大报文大小调整为100M,满足5700张100*100图片的传输需求 pingTimeout: 60000, // 心跳超时调整为60秒,避免大批次传输时触发超时断连 });
3. 优化传输体积降低IO压力
Base64编码会比原始二进制数据大33%,如果业务允许,直接传输二进制Buffer替代Base64字符串,可以大幅降低单条消息体积,减少断连概率。
内容的提问来源于stack exchange,提问作者user2272048
相关产品推荐
相关产品推荐

