Nodejs net socket 接收客户端tcp数据出错(已解决)
Nodejs net socket 接收客户端tcp数据出错(已解决)
var server = net.createServer(function (sock) { var dataBuff = new Buffer(512); var dataBuffLength = 0; sock.setTimeout(SocketTimeOut); sock.setEncoding(‘ascii’); sock.on(‘readable’, function() { var g_count = 0; var i_length = 0; var chunk = ‘’; while (null !== (chunk = sock.read())) { dataBuffLength += dataBuff.write(chunk, dataBuffLength, chunk.length); } console.log(“dataBuff:” + dataBuff.length); console.log(“dataBuffLength:” + dataBuffLength); console.log(dataBuff); }); }); 上面是tcp socket服务器接收代码。
dataBuff里面的16进制数据应该是: 00 02 AD 00 01 05 65 73 30 30 31 02 0C 71 77 65 72 41 53 44 46 31 32 33 34 03 06 32 30 30 33 35 36 32 11 00(这段数据我是通过网络调试助手捕捉的是我想要的数据)
但是经过上面接收代码处理变成: 00 02 2D 00 01 05 65 73 30 30 31 02 0C 71 77 65 72 41 53 44 46 31 32 33 34 03 06 32 30 30 33 35 36 32 11 00
这个问题折腾3天了,sock.setEncoding(‘ascii’);中编码全部换过都得不到我想要的数据,求前辈指点一二啊。 客户端是通过GPRS socket发送过来的数据。
Node.js TCP Socket 接收客户端TCP数据出错(已解决)
背景
最近在使用Node.js的net
模块开发一个TCP服务器时,遇到了接收客户端数据出错的问题。经过三天的调试,最终找到了问题所在并解决了它。
问题描述
服务器端接收客户端发送过来的TCP数据时,发现接收到的数据与预期不符。具体来说,原始数据中的AD
被替换成了2D
。以下是原始数据和接收后的数据对比:
-
原始数据(通过网络调试助手捕捉到的):
00 02 AD 00 01 05 65 73 30 30 31 02 0C 71 77 65 72 41 53 44 46 31 32 33 34 03 06 32 30 30 33 35 36 32 11 00
-
接收后的数据:
00 02 2D 00 01 05 65 73 30 30 31 02 0C 71 77 65 72 41 53 44 46 31 32 33 34 03 06 32 30 30 33 35 36 32 11 00
可以看到,原本的AD
变成了2D
。
解决方案
经过排查,问题出现在sock.setEncoding('ascii');
这行代码上。由于ASCII编码无法正确处理非ASCII字符,导致了数据的错误转换。正确的做法是直接读取二进制数据,并将其转换为十六进制字符串或其他需要的格式。
以下是修改后的代码示例:
const net = require('net');
const server = net.createServer((sock) => {
console.log('Client connected');
sock.setTimeout(10000); // 设置超时时间
sock.on('data', (data) => {
const hexData = data.toString('hex');
console.log(`Received data: ${hexData}`);
});
sock.on('end', () => {
console.log('Client disconnected');
});
});
server.listen(8080, () => {
console.log('Server is listening on port 8080');
});
代码解释
- 创建TCP服务器: 使用
net.createServer()
创建一个TCP服务器,并指定回调函数处理客户端连接。 - 设置超时时间: 使用
sock.setTimeout()
设置超时时间。 - 监听"data"事件: 当接收到客户端数据时,触发"data"事件。这里我们直接将数据转换为十六进制字符串并打印出来。
- 监听"end"事件: 当客户端断开连接时,触发"end"事件。
结论
通过避免使用setEncoding
方法,直接处理二进制数据并转换为所需的格式,可以有效解决接收数据时出现的编码问题。希望这个解决方案能帮助遇到类似问题的开发者。
在线等,
为什么使用readable事件,而不是data事件。 加上ascii表示将每个字节当作ascii字符来看,你确定发来的数据是按字符来看?还是若干字节表示一个数值? 另外三个字节不科学啊,TCP有错误重传机制,不可能发送的时候和接收到的不一致的情况。
我确定不是文本,是二进制数据,开始怀疑调试助手发送文件数据会有偏差,后面我打开客户端发送真是数据到服务器,服务器开启node打印数据,情况一样的。 客户端的数据发送协议在java那边解析正常的,
把net换成socket.io试试,实在没办法了。
试试,这个不分析协议,仅将收到的数据追加后显示
‘use strict’
var net = require(‘net’); var config = { tcpPort: 5000 };
var srv = net.createServer(function © {
var data = [];
c.on(‘data’, function (chunk) {
data.push(chunk);
console.log(data);
});
c.on(‘timeout’, function () {
console.log(‘timeout’);
});
c.on(‘error’, function (ex) {
console.log(‘error’);
});
c.on(‘close’, function (had_error) {
console.log(‘close’) ;
});
c.on(‘end’, function () {
console.log(‘end’);
});
});
srv.on(‘error’, function (e) { if (e.code === ‘EADDRINUSE’) { console.log(config.tcpPort,‘被占用’); } ; });
srv.listen(config.tcpPort, function () { console.log(‘在’,config.tcpPort + ‘运行’); });
调试工具用二进制发。
16进制,我常说二进制。呵呵。
sock.setEncoding(‘hex’);
dataBuffLength += dataBuff.write(chunk, dataBuffLength, chunk.length,‘hex’);
在你的代码中,setEncoding('ascii')
的使用会导致数据被转换成字符串格式,这可能会导致二进制数据被错误地解析。对于二进制数据,你应该直接读取 Buffer
而不进行编码转换。
以下是修正后的代码:
const net = require('net');
var server = net.createServer(function (sock) {
var dataBuff = Buffer.alloc(512);
var dataBuffLength = 0;
sock.setTimeout(SocketTimeOut);
sock.on('data', function(chunk) {
console.log("chunk length:", chunk.length);
chunk.copy(dataBuff, dataBuffLength);
dataBuffLength += chunk.length;
console.log("dataBuff:", dataBuff.toString('hex'));
console.log("dataBuffLength:", dataBuffLength);
});
sock.on('end', function() {
console.log("Data received completely.");
// 这里处理完整数据
});
});
server.listen(1234, () => {
console.log("Server listening on port 1234");
});
解释
- 取消
setEncoding('ascii')
:因为我们需要处理二进制数据,而不是文本数据。 - 使用
'data'
事件:'readable'
事件可能会导致多次调用,而'data'
事件更可靠。 - 使用
Buffer.copy
:将接收到的数据片段复制到dataBuff
中。 - 处理完整数据:当接收到所有数据后,可以在
'end'
事件中处理完整的数据。
这样,你就能正确地接收和处理二进制数据了。