nodejs 聊天室

  • socket.io 手册
  • 菜鸟手册
  • nodejs中文文档-模块文档

首先确保本地环境已经安装了 node 环境
建立项目文件夹,我的是 node,以下操作都是在 node 文件夹下面操作的
然后安装 express 框架

npm install --save [email protected]

安装 socket.io 模块

npm install --save socket.io

我的 demo 也是安装手册上来的,

注意要点

在 vue 中的 created(){} 里面的变量,你在 data 里初始值是什么,这个变量的值就永远是什么,这个个坑跟 vue 的生命周期有关。所有在做一对一聊天,房间聊天的处理中,监听聊天通道的时候需要注意聊天对象的ID号和房间号的选择,其实你可以把这个监听放在选择聊天对象或者房间的点击事件中

  • index.js
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var config = require('config'); // 学习模块的引入

app.get('/', function (req, res) {
    // res.send('

Hello World

'); res.sendFile(__dirname + '/index.html'); }); // 监听连接处理 io.on('connection', socket => { // socket.on('chat message', function (msg) { // console.log('message:' + msg); // }); // socket.on('disconnect', function () { console.log('user disconnected'); }) // 连接后,监听 chat message 通道 socket.on('chat message', msg => { // 这个 msg 是熊 index.html 中发送过来的 io().emit('chat message', $('#m').val()); // io.emit 是往某个通道发送信息,第一个参数是通道,第二个参数是信息 这个与 socket.on 监听的通道可以不一致 io.emit('send message', msg); }); }) http.listen(config['socket_port'], function () { console.log('listening on *:3000'); })
  • inde.html



    Socket.IO chat
    
    
    
    
    


    • configs.js
    module.exports = {
       'socket_port': '3000',
    }
    
    

    程序讲解

    首先你需要对 nodejs 语法要有基本的了解,如果不了解,我建议看 菜鸟手册
    然后我们要知道,nodejs 是基于事件驱动的语法,也就是有事件,才会有相应的触发。
    事件可以理解为事件就是客户点击了某个url,触发就是我们对某个路由的控制器做的相应处理
    此处的触发,就比如 io.on('connection',function(socket){}), 此处的 on() 就相当于是监听 connection 是固定的参数,监听到有客户端连接的意思,
    on 的第二个参数就是连接后做的处理,相当于是控制器

    程序执行流程讲解

    index.js 中首 io模块 先监听了 connection连接 的处理,连接后监听了 'chat message'消息通道
    index.html 中,往 chat message 通道发送信息 socket.emit('chat message', $('#m').val());
    这个时候 index.js 中的 socket.on('chat message', msg => {}) 监听到有消息发送过来,这里的 msg 就是 index.html 中发送的消息。
    收到消息后,我们需要把消息发送到某个通道,此处的通道名字我用的是 sen message ,io.emit('send message', msg); ,我把这个消息发送到 send message 通道
    我们在 index.html 前端页面监听了 send message 通道 socket.on('send message',msg=>{}),然后对监听的数据做处理即可

    以上情况,我们是针对群聊处理的。也就是每个人都是监听的 send message 通道,发送信息都是发送到了 chat message 通道,如果需要私聊,或者指定房间,需要更改这两个参数即可


    一对一聊天

    • index.html
    
    

    请选择聊天的对象

      • index.js
      同上面的 index.js 此处只展示改变代码的部分
      ...
      // 监听连接处理
      io.on('connection', socket => {
          // 连接后,监听 chat message 通道
          socket.on('chat message', msg => {
              io.emit(msg.to, msg);
          });
      
      })
      ...
      
      • 思路分析
        我们在 index.html 页面中监听的信息通道都是to 参数的值,这个通道在 demo 中,其实就是test
        long 主动跟 test 聊天,在 long 的页面中 username=long to =test
        在 test 页面中 username 和 to 的值都是 test 所以两人都是监听的 test 通道,都可以接收到信息

      • 不适用 express 框架也可以的

      var fs = require('fs');
      var app = require('http').createServer(function (req, res) {
          fs.readFile(__dirname + '/index.html', function (err, data) {
              if (err) {
                  res.writeHead(500);
                  return res.end('Error loading index.html');
              }
              res.writeHead(200);
              res.end(data);
          })
      })
      io = require('socket.io')(app);
      // 监听连接处理
      io.on('connection', socket => {
          socket.on('disconnect', function () {
              console.log('user disconnected');
          })
      
          // 连接后,监听 chat message 通道
          socket.on('chat message', msg => {
              io.emit(msg.to, msg);
              // 如果发送人和接收人都是同一个人,则不需要重复发送给自己
              if (msg.to != msg.username) {
                  io.emit(msg.username, msg);
              }
          });
      
      })
      app.listen(3000, function () {
          console.log('listening on *:3000');
      })
      

      某人上线下线的提醒

      • index.html
          var username = prompt('请输入你的名字', '');
          var socket = io();
          socket.emit('coming', username);  // 在输入名字之后,将新用户推送到 coming 通道
      
      • index.js
      // 监听连接处理
      io.on('connection', socket => {
          // 连接后,监听 chat message 通道
          socket.on('coming', msg => {
              socket.name = msg; // 这个通道有消息过来的时候,将他赋值给 socket 的一个属性
      ,因为 disconnect 与这个不在这个作用域,所以要放在 socket 的属性上
              console.log(msg + '上线了');
          });
      
          socket.on('disconnect', function () {
           // 这里可以写自己的逻辑业务,比如通知某个房间的人
              console.log(socket.name + '离开了');
          })
      })
      

      vue 实现一对一聊天

      首先后端的服务还是使用上面的 index.js 去处理
      在前端

      • vue/index.html 中引入 socket.io.js 文件
       
      先引入后端的 socket.io.js 文件,就可以获取 io 这个对象。我们预定义 socket 变量方便程序中使用
      • vue/src/router/index.js 定义聊天路由
      import Vue from 'vue'
      import Router from 'vue-router'
      import HelloWorld from '@/components/HelloWorld'
      import Chat from '@/components/Chat'
      import ChatList from '@/components/ChatList'
      
      Vue.use(Router)
      
      export default new Router({
        routes: [
          {
            path: '/',
            name: 'HelloWorld',
            component: HelloWorld
          },{
            path: '/chat',
            name: 'Chat',
            component: Chat
          },{
            path: '/chatlist',
            name: 'ChatList',
            component: ChatList
          }
        ]
      })
      
      • vue/src/components/ChatList.vue 选择聊天对象列表,这步不重要
      
      
      
      
      • vue/src/components/Chat.vue 聊天页面
      
      
      
      
      
      nodejs 聊天室_第1张图片
      image.png

      多对多聊天(房间聊天,群聊)

      • 后端 index.js
      ....
      // 监听连接处理
      io.on('connection', socket => {
          // 私聊通道监听
          socket.on('one to one message', msg => {
              // 发送给私聊对象
              io.emit(msg.chatTo, msg);
          });
      
          // f房间聊天室监听
          socket.on('chat room message', msg => {
              // 发送给某个房间
              io.emit('chat room receive' + msg.roomNum, msg)
          });
      })
      ....
      
      • ChatRoom.vue
      
      
      
      • ChooseRoom.vue
      
      
      

      在一个小图表上显示有多少条未读数据的做法是,直接监听相关的端口,j每次有消息通知的时候将一个变量加1即可

      data() {
          return {
              msgCount: 0
          }
      },
      
      created() {
          // socket.ChatList = [];
          // 一对一聊天
          socket.on(this.username, msg => {
              this.msgCount++;
              // socket.ChatList.push({
              //     username: msg.username,
              //     chatTo: msg.chatTo,
              //     content: msg.content,
              // });
          });
      }
      

      如果想点击小图标后显示聊天的内容,可以在上面的处理中将接受的数据赋值给 socket 的一个自定义变量,这样的话,跨页面也是可以获取到这个变量的

      一对一聊天,显示聊天对象列表和内容

      • 思路,聊天用户发送信息的时候,在后端使用 redis 的 rpush 保存数据,并将聊天人使用 sadd 存入 set ,其实也可以使用 hash 的 hincryby 每次将聊天记录加1 ,但是我看 nodejs 的 redis 没有这个操作指令。
        对了,用户一对一的通道名子,我根据两人的名字比较,大的值在前面。js 语法也是可以直接比较字符串的,这样就可以统一通道规则

      • 前端首页 index.vue

      
      
      
      
      • 前端聊天页面 chat.vue
      
      
      
      
      
      
      • 后端 index.js
      var app = require('express')();
      var http = require('http').Server(app);
      var io = require('socket.io')(http);
      
      var redis = require('redis');
      var client = redis.createClient(6379, '127.0.0.1');
      const ONE_TO_ONE = 'one to one message'; // 一对一聊天
      const ROOM_CHAT = 'chat room receive'; // 房间聊天
      const SET_CHAT_LIST = 'chat list'; // 聊天对象列表
      
      app.get('/', function (req, res) {
          res.sendFile(__dirname + '/index.html');
      });
      
      // 监听连接处理
      io.on('connection', socket => {
          // 私聊通道监听
          socket.on(ONE_TO_ONE, msg => {
              console.log(msg.chatSocket);
              // 发送给私聊对象
              io.emit(msg.chatSocket, msg);
              // 将聊天语句存入 redis
              client.rpush(ONE_TO_ONE + msg.chatSocket, JSON.stringify(msg), function (err, data) {
                  console.log(data)
              })
              // 将聊天人发送给聊天对象的 set 集合中
              client.sadd(SET_CHAT_LIST + msg.chatTo, msg.username, function (err, data) {
                  console.log(data)
              });
      
          });
      
          // f房间聊天室监听
          socket.on('chat room message', msg => {
              // 发送给某个房间
              io.emit(ROOM_CHAT + msg.roomNum, msg)
              // 将聊天语句存入 redis
              client.rpush(ROOM_CHAT + msg.roomNum, JSON.stringify(msg), function (err, data) {
                  console.log(data)
              })
          });
      
      })
      
      http.listen(3000, function () {
          console.log('listening on *:3000');
      })
      
      • 后端PHP 接口 redis.php
      connect('127.0.0.1', 6379);
      //查看服务是否运行
      
      if (!isset($_GET['method'])) {
          echo $_GET['callback'] . "(请传入请求参数)";
      }
      
      $username = isset($_GET['username']) ? $_GET['username'] : ''; // 用户名
      $method = isset($_GET['method']) ? $_GET['method'] : ''; // 请求方法
      $chatSocket = isset($_GET['chatSocket']) ? $_GET['chatSocket'] : ''; // 请求方法
      $chatTo = isset($_GET['chatTo']) ? $_GET['chatTo'] : ''; // 请求方法
      
      $arr = [];
      switch ($method) {
          case 'one to one message': // 一对一聊天
              $arr = $redis->lRange($method . $chatSocket, 0, -1);
              break;
          case 'set chat list': //
              $chatTo = $_GET['chatTo'];
              $arr = $redis->hIncrBy($method . $username, $chatTo, HASH_INC_BY);
              break;
          case 'get chat list': // 获取聊天列表
              $arr = $redis->sMembers(SET_CHAT_LIST . $username);
              break;
      
      }
      
      $result = json_encode($arr);
      $callback = $_GET['callback'];
      echo $callback . "($result)";
      
      • 我这里设计的是只要发送信息,node 后端就直接使用 redis 的 sadd 存入集合,但是这样可能没必要,因为只需要存入一次就可以了,改善方式,可以是在进入本聊天页面的时候,直接请求一个 php 接口,将聊天用户存入 sadd 。但是这样就是还没有聊天就存入了聊天对象,好像也不合适


        nodejs 聊天室_第2张图片
        image.png

        nodejs 聊天室_第3张图片
        image.png

        nodejs 聊天室_第4张图片
        image.png

      你可能感兴趣的:(nodejs 聊天室)