Node.js Socket接收R51-GPRS设备UTF-8 JSON数据时出现乱码的问题排查求助
解决R51-GPRS设备TCP JSON数据乱码与解析问题
核心问题分析
从你的描述和代码来看,乱码的主要原因有两个:
- 错误将普通TCP连接当作WebSocket处理:你的代码默认所有新连接都是WebSocket请求,会尝试提取
Sec-WebSocket-Key并返回握手响应,但R51-GPRS设备是直接发送UTF-8编码的JSON数据,根本不会发起WebSocket握手,这导致设备的初始JSON数据被错误解析成WebSocket握手帧,后续数据处理完全混乱。 - TCP流的粘包/拆包未处理:TCP是面向流的协议,
data事件触发时可能只收到JSON的一部分,直接转字符串或解析会导致格式错误,甚至乱码。
修复后的代码实现
下面是修正后的Node.js TCP服务代码,专门针对R51-GPRS设备的JSON数据接收场景:
var net = require('net'); var sockets = []; net.createServer(function (socket) { console.log('设备已连接'); let buffer = Buffer.from(''); // 用Buffer存储未完成的数据流 socket.on('data', function(data) { // 拼接收到的二进制数据 buffer = Buffer.concat([buffer, data]); try { // 尝试将Buffer转UTF-8字符串并解析JSON // 注意:如果设备有特定分隔符(比如换行),可以按分隔符拆分数据 const jsonStr = buffer.toString('utf8'); const jsonData = JSON.parse(jsonStr); console.log('解析成功的JSON数据:', jsonData); // 解析成功后清空buffer,准备接收下一条数据 buffer = Buffer.from(''); } catch (err) { // 解析失败,说明数据不完整(粘包/拆包),继续等待后续数据 console.log('数据不完整,等待后续片段:', err.message); } }); socket.on('end', function() { console.log('设备连接断开(end)'); const index = sockets.indexOf(socket); if (index !== -1) sockets.splice(index, 1); }); socket.on('close', function() { console.log('设备连接关闭(close)'); const index = sockets.indexOf(socket); if (index !== -1) sockets.splice(index, 1); }); socket.on('error', function(e) { console.log('连接错误:', e); }); sockets.push(socket); }).listen(7788, function() { console.log('TCP服务监听端口7788'); });
关键修复点说明
- 移除WebSocket握手逻辑:完全去掉了针对WebSocket的
Sec-WebSocket-Key处理和握手响应,因为R51-GPRS设备用的是普通TCP协议。 - 用Buffer处理二进制数据流:不再直接将
data转字符串,而是先拼接Buffer,确保能处理不完整的JSON片段(粘包/拆包场景)。 - UTF-8显式编码:调用
buffer.toString('utf8')显式指定编码,避免Node.js默认编码可能带来的问题。
额外排查步骤
如果修复后仍有乱码,建议做以下验证:
- 抓包确认设备发送的实际数据:用Wireshark抓取设备到服务器的TCP包,查看原始二进制数据是否符合UTF-8编码的JSON格式,是否有额外的前缀/后缀字节。
- 测试设备的编码格式:有些设备可能标注UTF-8但实际用GBK等其他编码,可以尝试用
buffer.toString('gbk')(需要安装iconv-lite库)测试解析。 - 检查设备的发送协议:确认设备是否用特定的分隔符(比如
\r\n)分隔每条JSON数据,如果有,代码可以按分隔符拆分Buffer,避免解析不完整的问题。
内容的提问来源于stack exchange,提问作者Ani




