《菜鸟教程》| Egret搭建WebSocket简易聊天室

egret-edcation 2018-09-11 原文

《菜鸟教程》| 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增加了客户端与服务器的互动,同时也实现了客户端之间的联系。

 

 

posted on 2018-09-11 14:48 白鹭教育 阅读() 评论() 编辑 收藏

 

 
版权声明:本文为egret-edcation原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/egret-edcation/p/9627608.html

《菜鸟教程》| Egret搭建WebSocket简易聊天室的更多相关文章

  1. iOS 14 egret H5游戏卡顿问题分析和部分解决办法

    现象 总体而言,iOS 14 渲染性能变差,可以从以下几个测试看出。   测试1:简单demo,使用egret […]...

  2. Egret 菜鸟级使用手册–第二天

    ################新的一天,我还是大佬 今天加载个英雄,先在GameScene里搞一个英雄出来, […]...

  3. egret 入门学习笔记之问题解决

    一、super()的用处 MaskLayer继承了eui.Component, constructor是类的入 […]...

  4. Egret Engine 2D

    缩放模式和旋转模式说明 缩放模式showAll 常用 noScale noBorder exactFit 次常 […]...

  5. egret 入门学习笔记

      一、使用exml搭建界面 1.创建exml文件,进入到编辑模式 2.组织UI界面元素 将所需的控件下的组件 […]...

  6. 菜鸟教程 | egret EUI卡牌游戏制作

    写在前面    随着越来越多的新人开始接触白鹭引擎,创作属于自己的游戏。考虑到初学者会遇到的一些实际操作问题, […]...

  7. 插件使用案例

    插件使用案例 插件使用案例 2018年8月13日,白鹭引擎发布5.2.7 版本。本次版本主要新增了两大功能:命 […]...

  8. 白鹭引擎 5.2.7 新增自动合图插件、二进制和声音缓存方案功能

    白鹭引擎 5.2.7 新增自动合图插件、二进制和声音缓存方案功能   2018年8月13日,白鹭引擎发布5.2 […]...

随机推荐

  1. Jmh测试JDK,CGLIB,JAVASSIST动态代理方式的性能

      前言 JDK,CGLIB,JAVASSIST是常用的动态代理方式。 JDK动态代理仅能对具有接口的类进行代 […]...

  2. supervisor 安装和使用教程

    在项目中,经常有脚本需要常驻运行的需求。以PHP脚本为例,最简单的方式是: $ nohup php cli.p […]...

  3. js数组与字符串相互转换

    1. 数组转字符串 .join() 将数组中所有元素放到一个字符串中,并用指定的分隔符进行分割 const a […]...

  4. mysql 数据库信息常用命令 Mysql查询数据库状态及信息

    使用MySQL时,需要了解当前数据库的情况,例如当前的数据库大小、字符集、用户等等。下面总结了一些查看数据库相 […]...

  5. Gitbook详解(六)-导出电子书详解

    目录 1. 导出格式 2. 基本命令 3. 导出书籍为HTML格式的静态网站 4. 导出书籍为PDF格式文件 […]...

  6. memcache 详解

    memcache函数所有的方法列表如下: Memcache::add – 添加一个值,如果已经存在,则返回fa […]...

  7. 使用TaskScheduler 调度器 实现跨线程的控件访问

    1 //任务调度器 2 TaskScheduler UIscheduler = null; 3 public […]...

  8. 记:打开Charles后,win10 chrome访问https的网站提示“您的链接不是私密链接”的解决过程

    一、Charles破解 Charles注册码: (适用于Charles所有版本) Registered Nam […]...

展开目录

目录导航