初始实现

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


发布评论
IT序号网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

Node.js开发入门—套接字(socket)编程知识解答
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。