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发送过来的数据。


10 回复

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');
});

代码解释

  1. 创建TCP服务器: 使用net.createServer()创建一个TCP服务器,并指定回调函数处理客户端连接。
  2. 设置超时时间: 使用sock.setTimeout()设置超时时间。
  3. 监听"data"事件: 当接收到客户端数据时,触发"data"事件。这里我们直接将数据转换为十六进制字符串并打印出来。
  4. 监听"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");
});

解释

  1. 取消 setEncoding('ascii'):因为我们需要处理二进制数据,而不是文本数据。
  2. 使用 'data' 事件'readable' 事件可能会导致多次调用,而 'data' 事件更可靠。
  3. 使用 Buffer.copy:将接收到的数据片段复制到 dataBuff 中。
  4. 处理完整数据:当接收到所有数据后,可以在 'end' 事件中处理完整的数据。

这样,你就能正确地接收和处理二进制数据了。

回到顶部