缘由:因有多个客户端会不定期的与服务器端建立联系,想要区分哪个客户端来完成相应的处理
原版代码:
var net = require('net');//1 引入net模块
var chatServer = net.createServer();//创建net服务器
var clientList=[];//保存多个客户端的数组
chatServer.on('connection', function (client) {//服务器连接客户端
client.name=client.remoteAddress+':'+client.remotePort;
/*增加name属性*/
client.write('Hi'+client.name+'!\n');
clientList.push(client);
client.on('data', function (data) {
/*添加事件监听器,这样就可以访问到连接事件所对应的client对象,当client发送数据给服务器时,这一事件就会触发*/
for(var i=0;i<clientList.length;i++){
if(clientList[i]!==this){
// 把数据发送给其他客户端
clientList[i].write(this.name+"says "+data);
}
}
});
});
chatServer.listen(9000, "127.0.0.1");//服务器端口
注意:这里有个坑——如果有个客户端断开连接,那么所有人都会玩完!
因为如果再往服务器发送消息,这时候服务器并不知道某个客户端已经断开了连接,因此会继续向其发送数据,但是这时断开的这个客户端对应的socket已经无法写入数据,而对已关闭的socket进行write()操作node程序会抛出异常,进而导致全军覆没。所以,这个问题应该从两个方面来解决:
(1)当客户端断开连接时,通知服务器,将其从客户端列表中移除,防止其调用write方法(V8引擎也会把响应的socket对象作为垃圾回收,并释放相应的内存);
(2)采用更保险的方式调用write()方法。
改进如下:
最后,监听客户端关闭事件,并记录错误
var net = require('net');//1 引入net模块
var chatServer = net.createServer();//创建net服务器
var clientList = [];//保存多个客户端的数组
chatServer.on('connection', function (client) {//服务器连接客户端
// console.log(' client remoteAddress =' + client.remoteAddress);
// console.log(' client remotePort = ' + client.remotePort);
client.name = client.remoteAddress + ':' + client.remotePort;
/*增加name属性*/
client.write('Hi' + client.name + '!\n');
// console.log(''client.name+'connected');
clientList.push(client);
console.log('clientList length = ' + clientList.length);
for(var i = 0; i<clientList.length; i++){
console.log('client remoteAddress'+[i] + clientList[i].name);
}
client.on('data', function (data) {
/*添加事件监听器,这样就可以访问到连接事件所对应的client对象,当client发送数据给服务器时,这一事件就会触发*/
//广播消息给其他客户端
broadcast(data,client);
});
//监听客户端终止
client.on('end',function(){
console.log(''+client.name+'quit');//如果某个客户端断开连接,node控制台就会打印出来
clientList.splice(clientList.indexOf(client),1);
});
/*记录错误*/
client.on('error',function(e){
console.log(' error'+e);
});
function broadcast(message,client){
var cleanup=[];//断开了的客户端们
for (var i = 0; i < clientList.length; i++) {
if (clientList[i] !== client) {
//检查socket的可写状态
if (clientList[i].writable) {
// 把数据发送给其他客户端
clientList[i].write(client.name + "says " + message);
}else{
/*socket不可写,则将其从列表中移除*/
cleanup.push(clientList[i]);
clientList[i].destroy();
}
}
}
/*删除掉服务器的客户端数组中,已断开的客户端*/
for(var i=0;i<cleanup.length;i++){
clientList.splice(clientList.indexOf(cleanup[i]),1);
}
}
});
//服务器端口
chatServer.listen(9000, function(){
console.log("server bound : 9000");
});