开始学习Nodejs的TCP服务器了,有点小疑问。
开始学习Nodejs的TCP服务器了,有点小疑问。
老规矩,先学习书上的代码
// JavaScript Document
var net = require(‘net’);//加载net模块包含了node需要的所有TCP功能
var chatServer = net.createServer();//创建一个新的服务器
var clientList = [];//定义一个存放多个用户的容器
chatServer.on(‘connection’,function(client){//调用on方法添加一个事件监听器 /* 连接事件在调用回调函数时,会传给我们新客户端所对应的TCP socket对象的引用,就是client */ client.write(‘Welcome To ChatRoom’);//通过client,可以将信息发送给客户端
client.name = client.remoteAddress + ':' + client.remotePort;
client.write('Hi' + client.name + '!\n');
//client.write('World');//同上
//client.end();//关闭连接
clientList.push(client);//将登入的用户推入容器中
client.on('data',function(data){//监听client,如果发现client发送数据给服务器时,这一事件就会被触发
//console.log(data);
broadcast(data,client);
});
});
function broadcast(message,client){ for(var i=0,length = clientList.length;i<length;i++){//遍历容器中所有的用户 if(client !== clientList[i]){//如果不是发信用户,则信息可见,即即自己发信,让别人看到,自己不需要再次显示 clientList[i].write(client.name + ‘says:’ + message); } } } chatServer.listen(9000);//让node知道是监听哪个端口 console.log(‘服务器启动成功’);
我尝试开了多个客户端,问题是,为啥我的用户间传输信息是一个字符一个字符的显示。如何将一段字符串打好后,再进行传输?
好的,让我们来解答你的问题,并且提供一些示例代码和解释。
问题分析
你提到的“用户间传输信息是一个字符一个字符地显示”的问题,通常是因为TCP协议本身是基于流的,而不是基于消息块的。因此,当客户端发送数据到服务器,或者从服务器发送数据到客户端时,这些数据可能会被打包成任意大小的数据块。这可能导致你在读取数据时,一次只读取了一个字符。
解决方案
为了确保一段完整的字符串在传输过程中不会被打断,你需要确保在接收数据时,能够完整地读取整个字符串。一种常见的做法是使用data
事件处理函数来累积接收到的数据,直到接收到一个完整的字符串。
示例代码
下面是改进后的代码:
var net = require('net'); // 加载net模块包含了node需要的所有TCP功能
var chatServer = net.createServer(); // 创建一个新的服务器
var clientList = []; // 定义一个存放多个用户的容器
chatServer.on('connection', function (client) { // 调用on方法添加一个事件监听器
/*
连接事件在调用回调函数时,会传给我们新客户端所对应的TCP socket对象的引用,就是client
*/
client.write('Welcome To ChatRoom\n'); // 通过client,可以将信息发送给客户端
client.name = client.remoteAddress + ':' + client.remotePort;
client.write('Hi ' + client.name + '!\n');
// client.write('World\n'); // 同上
// client.end(); // 关闭连接
clientList.push(client); // 将登录的用户推入容器中
let buffer = ''; // 用于存储累积的数据
client.on('data', function (data) {
buffer += data.toString(); // 累积数据
if (buffer.endsWith('\n')) { // 当接收到一个完整的字符串时
const message = buffer.trim();
buffer = ''; // 清空缓冲区
broadcast(message, client);
}
});
});
function broadcast(message, client) {
for (var i = 0, length = clientList.length; i < length; i++) { // 遍历容器中所有的用户
if (client !== clientList[i]) { // 如果不是发信用户,则信息可见,即自己发信,让别人看到,自己不需要再次显示
clientList[i].write(client.name + ' says: ' + message + '\n');
}
}
}
chatServer.listen(9000); // 让node知道是监听哪个端口
console.log('服务器启动成功');
代码解释
- 缓冲区:我们使用一个名为
buffer
的变量来累积接收到的数据。每次接收到新的数据时,将其追加到buffer
中。 - 完整字符串检测:我们检查
buffer
是否以换行符\n
结尾。如果是,说明我们已经接收到一个完整的字符串,然后我们可以处理它。 - 清除缓冲区:处理完一个完整的字符串后,清空
buffer
以便继续累积新的数据。
这样可以确保每个完整的字符串在传输过程中不会被打断,从而避免一个字符一个字符地显示的问题。
能上传一下客户端的代码吗?
客户端是如何send的~感觉是对端send的问题。
没有客户端代码,启动后,直接开两个终端进行通信
用socket.io和socket.io-client更好实现类似的东西吧 除非你是要学习socket编程
在你的代码中,TCP连接默认是以流的形式处理数据的,这意味着每次接收到的数据可能是不完整的。为了确保一次发送一整段字符串而不是一个个字符,你需要确保发送的数据是一个完整的字符串。
你可以在发送数据时确保使用完整的字符串,而不是部分数据。例如,在 broadcast
函数中,你可以确保每个客户端接收到的数据是一个完整的字符串。
以下是一些修改建议:
- 确保在
broadcast
函数中发送的数据是完整的字符串。 - 如果你在接收数据时使用了
data
事件,注意可能需要累积数据片段来组成一个完整的字符串。
示例代码如下:
var net = require('net');
var chatServer = net.createServer();
var clientList = [];
chatServer.on('connection', function(client) {
client.write('Welcome To ChatRoom\n');
client.name = client.remoteAddress + ':' + client.remotePort;
client.write('Hi ' + client.name + '!\n');
clientList.push(client);
client.on('data', function(data) {
var message = data.toString(); // 将接收到的Buffer转换为字符串
broadcast(message, client);
});
});
function broadcast(message, client) {
for (var i = 0, length = clientList.length; i < length; i++) {
if (client !== clientList[i]) {
clientList[i].write(client.name + ' says: ' + message);
}
}
}
chatServer.listen(9000);
console.log('服务器启动成功');
在这个示例中,我们将接收到的 data
转换为字符串,并确保 broadcast
函数中的消息是一个完整的字符串。这样可以避免字符逐个显示的问题。