Nodejs 一个tcp例子,解包
Nodejs 一个tcp例子,解包
写了个tcp例子,抛砖引玉
client, 发送一个字符串
var net = require('net');
var socket = net.connect(5002, ‘localhost’, function() {
var str=‘abc’;
var len = Buffer.byteLength(str);
var buf = new Buffer(len + 2);
buf.writeUInt16BE(len, 0);
buf.write(str, 2);
for(var i=0; i<100; i++) {
socket.write(buf);
}
})
server 端,用on message来处理信息。
var net = require('net');
function getDataParser(emmiter) {
var waiting = 0
, buf
, bufOffset
;
function parseData(data, offset) {
var len = data.length;
var left = len - offset;
if(waiting) {
var toRead = Math.min(left, waiting);
if(waiting <= left) {
data.copy(buf, bufOffset, offset, offset + waiting);
offset += waiting;
waiting = 0;
emmiter.emit('message', buf);
if (offset < len) {
parseData(data, offset);
}
} else {
data.copy(buf, bufOffset, offset, len);
waiting -= (len - offset);
}
} else {
waiting = data.readUInt16BE(offset);
buf = new Buffer(waiting);
// UINT length is 2
parseData(data, offset + 2)
}
}
return parseData;
}
function handler(socket) {
var parseData = getDataParser(socket);
socket.on('data', function(data) {
console.log('data');
console.log(data);
parseData(data, 0);
});
socket.on('message', function(buf) {
console.log('msg');
console.log(buf);
})
}
net.createServer(handler).listen(5002);
Node.js TCP 示例:解包
本文将介绍如何使用 Node.js 实现一个简单的 TCP 客户端和服务端通信,并且在服务端实现数据包的解析。
客户端代码
客户端的任务是连接到服务器并发送一个字符串。我们使用 net
模块创建一个 TCP 连接,并通过这个连接发送数据。
var net = require('net');
var socket = net.connect(5002, 'localhost', function() {
var str = 'abc';
var len = Buffer.byteLength(str);
var buf = new Buffer(len + 2);
buf.writeUInt16BE(len, 0); // 写入长度前缀
buf.write(str, 2); // 写入实际数据
for (var i = 0; i < 100; i++) {
socket.write(buf); // 发送数据包
}
});
在这个例子中,我们首先计算字符串的长度(Buffer.byteLength(str)
),然后创建一个包含长度前缀和实际数据的缓冲区。长度前缀是一个 2 字节的无符号整数,表示后面跟随的实际数据的长度。然后我们把这个缓冲区发送给服务器 100 次。
服务端代码
服务端的任务是接收客户端发送的数据,并正确地解析这些数据包。为了实现这一点,我们需要处理粘包问题(即多个数据包可能被合并成一个数据包发送)。
var net = require('net');
function getDataParser(emitter) {
var waiting = 0;
var buf;
var bufOffset;
function parseData(data, offset) {
var len = data.length;
var left = len - offset;
if (waiting) {
var toRead = Math.min(left, waiting);
if (waiting <= left) {
data.copy(buf, bufOffset, offset, offset + waiting);
offset += waiting;
waiting = 0;
emitter.emit('message', buf);
if (offset < len) {
parseData(data, offset);
}
} else {
data.copy(buf, bufOffset, offset, len);
waiting -= (len - offset);
}
} else {
waiting = data.readUInt16BE(offset);
buf = new Buffer(waiting);
parseData(data, offset + 2);
}
}
return parseData;
}
function handler(socket) {
var parseData = getDataParser(socket);
socket.on('data', function(data) {
parseData(data, 0);
});
socket.on('message', function(buf) {
console.log('Received message:', buf.toString());
});
}
net.createServer(handler).listen(5002);
在服务端代码中,我们定义了一个 getDataParser
函数,该函数用于解析从客户端收到的数据。解析逻辑包括检查当前缓冲区是否已经包含了完整的消息,如果还没有,则继续读取更多的数据,直到完整的消息被读取为止。一旦完整的消息被读取,它就会被传递给 'message'
事件处理器。
最后,我们在 net.createServer
中注册了这个处理函数,并启动了服务器监听 5002 端口。
这样我们就完成了一个简单的 TCP 客户端和服务端通信的例子,其中服务端能够正确地解析客户端发送的数据包。
沒人感興趣啊
這個例子是將包長度放在包頭,保證可以整條整條消息的讀取。 反饋機制是可以的,序列號挺好的,也不會大很多,序列號16位就夠了,循環使用。
如果发过来的包不完整,好像没有校验
对包的整体作一个加法校验放到包头里 当然也可以做crc检验
在这个帖子中,您提供了一个简单的TCP客户端和服务器示例,并且重点在于如何解包接收到的数据。以下是对您的问题的回答,包含示例代码和简要解释。
客户端
客户端发送一个字符串,并在每次发送时添加一个长度前缀(2字节),这样服务器可以知道每个消息的长度。这有助于正确地解包数据。
var net = require('net');
var socket = net.connect(5002, 'localhost', function() {
var str = 'abc';
var len = Buffer.byteLength(str);
var buf = new Buffer(len + 2);
buf.writeUInt16BE(len, 0); // 写入长度前缀
buf.write(str, 2); // 写入实际数据
socket.write(buf); // 发送数据
});
socket.on('end', function() {
console.log('Connection closed');
});
服务器端
服务器端使用自定义的getDataParser
函数来解析数据。该函数首先读取长度前缀,然后根据该长度读取实际的数据。
var net = require('net');
function getDataParser(emitter) {
let waiting = 0;
let buf;
let bufOffset;
function parseData(data, offset) {
const len = data.length;
const left = len - offset;
if (waiting) {
const toRead = Math.min(left, waiting);
if (waiting <= left) {
data.copy(buf, bufOffset, offset, offset + waiting);
offset += waiting;
waiting = 0;
emitter.emit('message', buf);
if (offset < len) {
parseData(data, offset);
}
} else {
data.copy(buf, bufOffset, offset, len);
waiting -= (len - offset);
}
} else {
waiting = data.readUInt16BE(offset);
buf = new Buffer(waiting);
parseData(data, offset + 2);
}
}
return parseData;
}
function handler(socket) {
const parseData = getDataParser(socket);
socket.on('data', function(data) {
parseData(data, 0);
});
socket.on('message', function(buf) {
console.log('Message received:', buf.toString());
});
}
net.createServer(handler).listen(5002);
解释
- 客户端:向服务器发送一个带有长度前缀的字符串。
- 服务器端:通过
getDataParser
函数解析数据,首先读取2字节的长度前缀,然后根据长度前缀读取实际数据,并将其传递给'message'
事件处理器。
这样,即使发送的数据是分块到达的,服务器也能正确地解包并处理这些数据。