zoukankan      html  css  js  c++  java
  • 《菜鸟教程》| Egret搭建WebSocket简易聊天室

    本文,我们通过Egret和Node.js实现一个在线聊天室的demo。主要包括,聊天,改用户名,查看其他用户在线状态的功能。大致流程为,用户访问网页,即进入聊天状态,成为新游客,通过底部的输入框,可以输入自己想说的话,点击发布,信息呈现给所有在聊天的人的页面。用户可以实时修改自己的昵称,用户离线上线都会实时广播给其他用户。

    体验链接 http://7hds.com:8888/

    下图为最终制作完成的聊天面板

     

    WebSocket服务器可以用其他语言编写,本文采用的方法建立在Node.js上 。

    在Node.js中我们使用ws第三方模块来实现服务器业务逻辑的快速搭建,还需使用uuid模块生成随机id,你需要使用npm包管理器来安装ws、uuid模块。使用以下命令:

    npm install ws -g
    npm install uuid -g
    

     安装完成之后,使用终端工具进入服务器目录,开始编写代码:

    //引入ws模块
    var WebSocket = require('ws');
    //创建websocket服务,端口port为:****
    var WebSocketServer = WebSocket.Server,
        wss = new WebSocketServer({port: 8180});
    //引入uuid模块
    var uuid = require('node-uuid');
    //定义一个空数组,存放客户端的信息 
    var clients = [];
    //定义发送消息方法wsSend
    //参数为 type:类型
    //client_uuid:随机生成的客户端id
    //nickname:昵称
    //message:消息
    //clientcount:客户端个数
    function wsSend(type, client_uuid, nickname, message,clientcount) {
        //遍历客户端
      for(var i=0; i<clients.length; i++) {
          //声明客户端
        var clientSocket = clients[i].ws;
        if(clientSocket.readyState === WebSocket.OPEN) {
            //客户端发送处理过的信息
          clientSocket.send(JSON.stringify({
            "type": type,
            "id": client_uuid,
            "nickname": nickname,
            "message": message,
            "clientcount":clientcount,
          }));
        }
      }
    }
    //声明客户端index默认为1 
    var clientIndex = 1;
    //服务端连接
    wss.on('connection', function(ws) {
    //客户端client_uuid随机生成
      var client_uuid = uuid.v4();
      //昵称为游客+客户端index
      var nickname = "游客"+clientIndex;
      //client++
      clientIndex+=1;
      //将新连接的客户端push到clients数组中
      clients.push({"id": client_uuid, "ws": ws, "nickname": nickname});
      //控制台打印连接的client_uuid
      console.log('client [%s] connected', client_uuid);
     //声明连接信息为 昵称+来了
      // var connect_message = nickname + " 来了";
      var connect_message =  " 来了";
    
      //服务器广播信息 ***来了
      wsSend("notification", client_uuid, nickname, connect_message,clients.length);
     //当用户发送消息时
      ws.on('message', function(message) {
          // 用户输入"/nick"的话为重命名消息
        if(message.indexOf('/nick') === 0) {
          var nickname_array = message.split(' ');
          if(nickname_array.length >= 2) {
            var old_nickname = nickname;
            nickname = nickname_array[1];
            var nickname_message = "用户 " + old_nickname + " 改名为: " + nickname;
            wsSend("nick_update", client_uuid, nickname, nickname_message,clients.length);
          }
        }//发送消息 
        else {
          wsSend("message", client_uuid, nickname, message,clients.length);
        }
      });
     //关闭socket连接时
      var closeSocket = function(customMessage) {
          //遍历客户端
        for(var i=0; i<clients.length; i++) {
            //如果客户端存在
            if(clients[i].id == client_uuid) {
                // 声明离开信息
                var disconnect_message;
                if(customMessage) {
                    disconnect_message = customMessage;
                } else {
                    disconnect_message = nickname + " 走了";
                }
             //客户端数组中删掉
              clients.splice(i, 1);
              //服务广播消息
              wsSend("notification", client_uuid, nickname, disconnect_message,clients.length);
            }
        }
      }
      ws.on('close', function() {
          closeSocket();
      });
     
      process.on('SIGINT', function() {
          console.log("Closing things");
          closeSocket('Server has disconnected');
          process.exit();
      });
    });

    服务器端主要是接收信息,判断是聊天信息还是重命名信息,然后发送广播。同时,当用户连接上服务器端或者关闭连接时,服务器也会发送广播通知其他用户。

    我们封装了wsSend函数用来处理消息的广播。对每个连接的用户,我们默认给他分配为游客。为了实现广播,我们用clients数组来保存连接的用户。

    将编写好的文件保存为server.js,在终端工具中,使用node server.js来启动你刚刚编写的服务器。如果终端没有报错,证明你的代码已经正常运行。

    在实际项目中,服务器逻辑远远比此示例复杂得多。服务器端完成后,再来编写客户端代码。

    界面非常简单,我们通过两张图片来实现界面效果,首先创建我们的聊天界面,此项目中为了方便我们使用EUI进行快速开发。如下图:

    首先创建一个Image来放置我们的背景图。

    创建三个Label对象,一个作为title:“多人在线聊天室”,一个作为提示:“当前在线人数”,还有一个id为lb_online的作为在线人数显示文本。

    创建一个EditableText对象id为input_msg作为消息发送输入框,用户可以在此输入消息进行发送。

    创建一个Button对象id为btn_ok,点击按钮可以执行发送消息动作。

    创建界面的操作和WebSocket对象创建动作在同时进行,在init方法中创建WebSocket对象,并执行服务器连接操作,代码如下:

    public ws;
        private init() {
            /**WebSocket连接 */
            this.ws = new WebSocket('ws://127.0.01:8180');
            this.ws.onopen = function (e) {
                console.log('Connection to server opened');
            }
        }

    由于服务器开放了8180端口,我们也需要使用8180端口进行连接。当连接成功,可执行onopen方法。

    服务器连接成功了,在控制台打印 'Connection to server opened'。

    onmessage方法中读取服务器传递过来的数据,并通过appendLog方法将数据显示在对应的文本里,

    使用newLabel方法并将一条新消息插入到消息框中。

    private init() {
            /**WebSocket连接 */
            this.ws = new WebSocket('ws://127.0.01:8180');
            this.ws.onopen = function (e) {
                console.log('Connection to server opened');
            }
            /**昵称 */
            var nickname;
            var self = this;
            this.ws.onmessage = function (e) {
                var data = JSON.parse(e.data);
                nickname = data.nickname;
                appendLog(data.type, data.nickname, data.message, data.clientcount);
                console.log("ID: [%s] = %s", data.id, data.message);
                //插入消息
                self.group_msg.addChild(self.newLabel(data.nickname, data.message))
            }
            function appendLog(type, nickname, message, clientcount) {
                console.log(clientcount)
                /**聊天信息 */
                var messages = this.list_msg;
                /**提示 */
                var preface_label;
                if (type === 'notification') {
                    preface_label = "提示:";
                } else if (type === 'nick_update') {
                    preface_label = "警告:";
                } else {
                    preface_label = nickname;
                }
                self.preface_label = preface_label;
                var message_text = self.message_text = message;
                /**在线人数 */
                self.lb_online.text = clientcount;
            }
            /**点击OK发送 */
            this.btn_ok.addEventListener(egret.TouchEvent.TOUCH_TAP, this.sendMessage, this);
        }
        private newLabel(name: string, msg: string) {
              var label1: eui.Label = new eui.Label();
              label1.text = name + ":" + msg;
              label1.textColor = 0x000000
              return label1;
        }

    最后我们来编写发送消息的函数,在btn_ok中egret.TouchEvent.TOUCH_TAP点击之后的相应函数为sendMessage方法。

    /**发送消息 */
        private sendMessage() {
            var message = this.input_msg.text;
            if (message.length < 1) {
                // console.log("不能发送空内容!");
                return;
            }
            this.ws.send(message);
            /**清空输入框内容 */
            this.input_msg.text = "";
        }

    如果输入框中内容不为空的话就将数据通过 this.ws.send(message); 发送给服务器,并清除输入框的内容。

    最终运行后,我们就可以实现多人在线聊天功能了。

    完整版代码如下:

    class Chat extends eui.Component implements eui.UIComponent {
        /**在线人数文本 */
        public lb_online: eui.Label;
        /**聊天窗口 */
        public scr_msg: eui.Scroller;
        /**聊天信息 */
        public list_msg: eui.List;
        /**输入框 */
        public input_msg: eui.EditableText;
        /**确定按钮 */
        public btn_ok: eui.Button;
        /**聊天窗口消息组 */
        public group_msg: eui.Group;
    
        public constructor() {
            super();
        }
        protected partAdded(partName: string, instance: any): void {
            super.partAdded(partName, instance);
        }
        protected childrenCreated(): void {
            this.init();
            super.childrenCreated();
        }
        /**WebSocket */
        public ws;
        public preface_label;
        public message_text;
        private init() {
            /**WebSocket连接 */
             //线上测试链接,服务端代码需在服务器启动
            //this.ws = new WebSocket('ws://7hds.com:8180');
            this.ws = new WebSocket('ws://127.0.01:8180');
            this.ws.onopen = function (e) {
                console.log('Connection to server opened');
            }
            /**昵称 */
            var nickname;
            var self = this;
            this.ws.onmessage = function (e) {
                var data = JSON.parse(e.data);
                nickname = data.nickname;
                appendLog(data.type, data.nickname, data.message, data.clientcount);
                console.log("ID: [%s] = %s", data.id, data.message);
                //插入消息
                self.group_msg.addChild(self.newLabel(data.nickname, data.message))
            }
            function appendLog(type, nickname, message, clientcount) {
                console.log(clientcount)
                /**聊天信息 */
                var messages = this.list_msg;
                /**提示 */
                var preface_label;
                if (type === 'notification') {
                    preface_label = "提示:";
                } else if (type === 'nick_update') {
                    preface_label = "警告:";
                } else {
                    preface_label = nickname;
                }
                self.preface_label = preface_label;
                var message_text = self.message_text = message;
                /**在线人数 */
                self.lb_online.text = clientcount;
            }
            /**点击OK发送 */
            this.btn_ok.addEventListener(egret.TouchEvent.TOUCH_TAP, this.sendMessage, this);
        }
        /**发送消息 */
        private sendMessage() {
            var message = this.input_msg.text;
            if (message.length < 1) {
                // console.log("不能发送空内容!");
                return;
            }
            this.ws.send(message);
            /**清空输入框内容 */
            this.input_msg.text = "";
            // console.log(this.ws.bufferedAmount);
        }
        private newLabel(name: string, msg: string) {
            var label1: eui.Label = new eui.Label();
            label1.text = name + ":" + msg;
            label1.textColor = 0x000000
            return label1;
        }
    
    }

    本文的demo增加了客户端与服务器的互动,同时也实现了客户端之间的联系。

     

     

  • 相关阅读:
    git version info & svn version info map(七)
    /proc/pid/statm content analysis
    git log filter(六)
    git create remote branch (五)
    learning svn diff --summarize
    learning scala akka ask_pattern
    learning scala akka tell pattern(二)
    learning scala akka actorySystem create and close
    hibernate 自动生成数据库
    STRICT_TRANS_TABLES STRICT_ALL_TABLES
  • 原文地址:https://www.cnblogs.com/egret-edcation/p/9627608.html
Copyright © 2011-2022 走看看