zoukankan      html  css  js  c++  java
  • Node创建TCP聊天

    //创建新的tcp服务器
    var net = require('net');
    var chatServer = net.createServer()

    chatServer.on('connection',function(client){
        client.write('Hi ');
        client.write('Bye ');
        client.end();
    })

    chatServer.listen(9000)


    /*代码的第一行,我们加载了net模块。这个模块包含了Node需要的所有TCP功能。
    接着我们调用net.createServer()方法来厂车间一个新的TCP服务器。有了这个
    服务器我们需要他做点事。这里调用on()方法来添加一个事件监听器每当有新的客户端
    通过网络连接接入服务器,就会触发connection事件,事件监听器就会调用我们指定的函数。
    链接事件在调用回调函数是,会传给我们新的客户端对应的TCP scoket对象的引用。我们把
    他引用命名为client。调用client.write(),就能发送信息给该客户端,然后调用client.end()
    方法关闭连接。
    */

    //监听所有的链接请求
    var net = require('net');
    var chatServer = net.createServer()

    chatServer.on('connection',function(client){
        client.write('Hi ');

        client.on('data',function(data){
            console.log(data)
        })

    })

    chatServer.listen(9000)

    /*这里添加了另外一个事件监听器,调用的是client.on()。注意我们是在connection回调函数作用域
    中添加事件监听器,这样就能访问到链接事件所对应的client对象。新监视器关注的是data事件,每当
    client发送数据给服务器时,这一事件都会触发*/

    //客户端之间的通信
    var net = require('net')

    var chatServer = net.createServer(),
        clientList = []
    chatServer.on('connection',function(client){
        client.write('Hi! ');

        clientList.push(client)

        client.on('data',function(data){
            for (var i = 0; i < clientList.length; i+=1) {
                //把数据发送给客户端
                clientList[i].write(data)
            }
        })
    })

    chatServer.listen(9000)
    /*服务器没有接收记录他收到的任何消息,而且把列表中的每个客户端都轮询一遍,
    并把消息转发出去,发送消息的时候,没有检查发送者是谁,只是简单的把消息转发
    给所有的客户端*/

    //改进消息发送
    var net = require('net')
    var chatServer =net.createServer(),
        clientList = []

    chatServer.on('connection',function(client){
        client.name = client.remoteAddress + ':' + client.remotePort
        client.write('Hi ' + client.name + ' ');

        clientList.push(client)

        client.on('data',function(data){
            broadcase(data,client)
        })
    })

    function broadcase(message,client){
        for(var i = 0;i < clientList.length;i += 1){
            if(client !== clientList[i]){
                clientList[i].write(client.name + "says: " + message + ' ')
            }
        }
    }

    chatServer.listen(9000)
    /*在connection事件监听器上为每个client对象上增加name属性
    为什么我们能为client对象添加属性
    因为闭包绑定了每个client对象和相应的请求。于是,在闭包内疚可以利用
    client.remoteAddress和client.remotePort来创建client和name属性
    client.remoteAddress是客户端所在的IP地址
    client,remotePort是客户端接收从服务器返回数据的TCP端口
    当不同的客户端从一个IP发起连接时,他们各自会有唯一的remotePort。
    以后再向client发送消息时,我们就能唯一标识来找到他

    我们还把处理data的事件监听器放到了broadcast函数中,这样,通过
    调用broadcast函数就可以把消息发送到所有客户端。这一次,把发起消息
    data的client对象传递进去,以便把他从接收消息的客户端列表中排除掉。
    我们还把client.name加到要发送的消息上,好让其他客户端清楚消息来源*/

    /*此种通信弊端:建立3个tcp通信,当断掉其中一个,在向其发送消息,即
    调用broadcast()的时候,服务器会往一个断开的客户端写入数据,因为他所对应
    的socket已经无法写入和读取了,而对socket进行write()操作时,Node程序会抛出
    异常,这将导致其他服务器掉线
    这个问题应该从两个方面来解决,首先保证在一个客户端断开的时候,要把他从客户端
    列表中移除,防止他在调用write方法。V8引擎也会把相应的scoket对象作为垃圾回收
    并释放内存。其次,更保险的方式不调用write方法*/


    //把聊天服务器改造的更加健壮
    var net = require('net')
    var chatServer =net.createServer(),
        clientList = []

    chatServer.on('connection',function(client){
        client.name = client.remoteAddress + ':' + client.remotePort
        client.write('Hi ' + client.name + ' ');

        clientList.push(client)

        client.on('data',function(data){
            broadcase(data,client)
        })

        client.on('end',function(){
            clientList.splice(clientList.indexOf(client),1)
        })
    })

    function broadcase(message,client){
        for(var i = 0;i < clientList.length;i += 1){
            if(client !== clientList[i]){
                clientList[i].write(client.name + "says: " + message + ' ')
            }
        }
    }

    chatServer.listen(9000)
    /*先处理断开的客户端。当一个客户端断开时,要把它从客户端列表移除。这时
    可以用end事件来完成。一个socket断开连接会触发end事件,表示他要关闭。
    此时,调用Array.splice()将客户端从cliectList列表移除。Array.indexOf()
    方法用于找到客户端在列表的位置,然后splice()把他从列表移除。之后,
    下一个客户端调用broadcast方法时,已经断开的客户端将不出现在列表中*/


    //检查socke的可写状态
    var net = require('net')
    var chatServer =net.createServer(),
        clientList = []

    chatServer.on('connection',function(client){
        client.name = client.remoteAddress + ':' + client.remotePort
        client.write('Hi ' + client.name + ' ');

        clientList.push(client)

        client.on('data',function(data){
            broadcase(data,client)
        })
    })

    function broadcase(message,client){
        var cleanup = []
        for(var i = 0;i < clientList.length;i += 1){
            if(client !== clientList[i]){
                if(clientList[i].writable){
                    clientList[i].write(client.name + "says: " + message + ' ')
                } else{
                    cleanup.push(clientList[i])
                    clientList[i].destroy()
                }
            }
        }
        //在写如入循环中删除死节点,消除垃圾索引
        for(i = 0;i < cleanup.length;i += 1){
            clientList.splice(clientList.indexOf(cleanup[i]),1)
        }
    }

    chatServer.listen(9000)
    /*调用broadcast函数的时候,检查一下socket是否可写,以确保不会因为任何一个不可写
    的socket导致异常。不仅如此,发现任何不可写的socket后,还要通过Socket.destroy()
    方法将其关闭并从clientList中移除。注意,遍历clientList的过程没有移除socket,*/

  • 相关阅读:
    英语词汇辨异 —— 形近字、近义词
    英文构词法 —— circum- 前缀
    英文构词法 —— circum- 前缀
    MySQL Cluster-备份恢复初步测试
    MySQL root密码重置报错:mysqladmin: connect to server at 'localhost' failed的解决方案!
    [置顶] High Performance Canvas Game for Android
    [移动网关]2G环境下资源下载有一定概率失败,客户端日志显示收到403错误
    工作两年,新起点,新征程
    CloudStack 物理网络架构
    数学之路(3)-机器学习(3)-机器学习算法-欧氏距离(1)
  • 原文地址:https://www.cnblogs.com/xiao-zhang-blogs/p/6060431.html
Copyright © 2011-2022 走看看