socket.io + node简单聊天室

socket.io + node 简单聊天室

首先,我想感谢提供该文章主要思想的作者。其中大半代码来源于该作者。个人只是在理解的基础下稍作完善。此文章的作用主要是学习与分享。

// 作者:luck_lin
// 来源:CSDN
// 原文:https://blog.csdn.net/qwe502763576/article/details/79672766

  1. 优化的点之一:登陆时只会通知在线的用户。(如果同时开多个客户端)
  2. 优化点之二:退出时,退出的用户自动回显到登陆前页面。在线的用户则收到用户退出的通知。
  3. 优化点三:登陆与退出,各客户端互不影响。

代码

node的安装与包的拉取我就不说了,请自觉学习。

服务端 app.js


var express = require("express");
var app = express();
//因为socket.io依赖原生http服务,所以要引入原生http模块,并且调用它的Server()方法将app传入,这样原生的http就拥有了express的方法
var http = require("http").Server(app);
var socket = require("socket.io")(http); //传入http执行socket函数,这样socket就跟http具有同一个端口了
http.listen(9999);
app.use(express.static("./html")); 
//设置静态资源路径
// 创建socket监听服务:
socket.on("connection", function(ws) {    	   
   ws.on("diyLogin", function(val) { //定义一个完全自定义事件,用来获取前端发来的登录的用户名
var address = ws.handshake.address;
console.log(address);    
   var u = checkUser(val);     
      if (u.err) {         
         ws.emit("exist", u);      
      } else {            
      socket.sockets.emit("allLogin", u); //执行前端事件,把登陆的信息,发送范围为每一个在线的客户端        
      }   
  });    // 监测客户端的sendMsg个人用户消息发送   
  ws.on("sendMsg", function(msgObj) {            
       socket.sockets.emit("accept", msgObj);//把接收到的某个用户消息发送到所有客户端        
   })      
    // 监测客户端的exit退出    
   ws.on('exit', function(data) {      
        exit(data.user);         
       socket.sockets.emit("already exits", data.user);// 将退出的用户信息告知所有的客户端       
   })       
        // ws.on('close exist', function(user) {        //     if (user !== '') {        //         exit(user);        //         socket.sockets.emit("already exits", data.user); // 将退出的用户信息告知所有的客户端        //     }        // })   
  ws.on('disconnect', function(data) {           
   console.log(data);      
   console.log('断开连接了'
   );      
     // socket.sockets.emit("already exits", data.user); // 将退出的用户信息告知所有的客户端     });    // 释放资源    
     ws.manager.transports[socket.id].socket.setTimeout(15000);
   })
var arr = [];// 将登陆用户存储到arr
function checkUser(u) { //检测用户名是否已存在    
if (arr.length === 0) {       
 arr.push(u);        
 return u;    
 };   
 console.log(u);   
 for (var i = 0; i < arr.length; i++) {       
    if (arr[i] === u) {          
      return {              
        err: "用户名已存在",            
        users: arr          
       }    
     } 
 } 
 arr.push(u);
  return u;
  }
  // 退出登陆时 从arr删除指定的用户
  function exit(u) {   
   for (var i = 0; i < arr.length; i++) {     
      if (arr[i] === u) {            
      arr.splice(i, 1);       
       }    
  }}


// --------------------- // 作者:luck_lin // 来源:CSDN // 原文:https://blog.csdn.net/qwe502763576/article/details/79672766 // 版权声明:本文为博主原创文章,转载请附上博文链接!
服务端 index.html
{在app.js同级新建一个html文件夹,在里面新建index.html}
<!DOCTYPE html>
<html lang="en">
<head>    
<meta charset="UTF-8">    
<title>Document</title>   
 <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">   
  <style>        
  i {           
   font-style: normal;
    }              
  .chatList {          
   height: 200px;            
   border: 1px dashed green;          
   overflow-y: auto;  
   }                
  .myself {          
      text-align: right;           
      color: red;       
   }               
   i.lin {          
       font-weight: bold;          
       color: #ffcc01;         
       font-size: 16px;        
    }                
    i.other {            
      color: green;   
    }              
    p.me {           
     text-align: right;           
      color: orange;       
    }   
</style>
</head>
<body>   
 <div class="container">       
  <div class="loginBox">         
     <input type="text" class="form-control" id="username">          
    <button class="btn" id="sure">登录</button>       
  </div>        
    <div class="chatBox hidden">          
      <div class="chatList"></div>           
             <textarea class="form-control" id="msg" cols="30" rows="5"></textarea>        
             <button class="btn" id="send">发送</button><button class="btn" id="exit" value="">退出</button>           
            <div class="alert alert-success hidden" role="alert"></div>     
    </div>    
  </div>
</body>
                     
<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>    //链接socket  
  var ws = io.connect("ws://localhost:9999");  
  var user = '';   
   // ws.emit('close exist',user);    
  $("#sure").click(function() {            
  var name = $("#username").val();            
  if (!name) {               
     alert("好歹起个名呀,eg:李易峰");           
      } else {                
     //通知后台有人登陆了,socket.io都是基于事件的,要做的操作都是触发自定义事件的方式                
     ws.emit("diyLogin", name); //执行自定义事件传入用户名                
     user = name; //把当前用户名称保存到全局变量
     }       
    })        //获取后端返回的用户是否存在的查询结果    
 ws.on("exist", function(re) {       
  if (re.err) {            
      alert(re.err);            
      console.log("已经登陆的用户:\n", re.users)            
      return;   
     }    
  })
    
    //接收后端返回的全局的登录者的名字的事件    
    ws.on("allLogin", function(name) {     
         // user 为空说明当前客户端还没用户登陆,只有有人登陆的客户端才被通知            
         if (user !== '') {                
          var _alert = name === "刘欢" ? "欢迎 男爵 <i class='lin'>" + name + "</i> 骑着火麒麟来到了本直播间!" : "<i class='other'>" + name + " </i>进入直播间";                
          $(".alert").html(_alert).removeClass("hidden").show();                
          $(".loginBox").hide(); //登陆后隐藏登录盒子                
          $(".chatBox").removeClass("hidden"); //显示出聊天界面                
          setTimeout(function() {                    
                $(".alert").fadeOut(function() {                        
                      $(this).addClass("hidden");                    }
                );                
          }, 1500)                
          $('#exit').val(user);            
        }
     })        
        //发送聊天消息    
        $("#send").click(function() {            
        var msg = $("#msg").val();            
           if (!msg) {            
            alert("空消息也要钱哦!");            
          } else {           
             ws.emit("sendMsg", {                    
                  msg,                    
                 user 
             }); //执行事件把内容和发送者发送给后台,让后台返回给所有客户端               
             $("#msg").val("");           
            }        
          })        
          //接收聊天消息    
          ws.on("accept", function(o) {    
              var p = $(`<p>${o.user}: ${o.msg}</p>`)        
              if (o.user === user) {        
                  p.addClass("me");    
             }       
              $(".chatList").append(p).scrollTop($(".chatList")[0].scrollHeight);    
          })
          $('#exit').click(() => {    
                ws.emit("exit", {'user': user,});
           });
          ws.on("already exits", function(data) {      
            // 退出,只有对应点了退出的用户才去执行退出操作       
             if (data === user) {            
                  $(".loginBox").show(); //登陆后隐藏登录盒子           
                   $(".chatBox").addClass("hidden"); //显示出聊天界面            
                   user = '';        
           } else {          
             //没有退出的用户则被通知有用户退出            
             $(".alert").html(`<i class='other'>${data} </i>退出了直播间`).removeClass("hidden").show();
             setTimeout(function() {           
                  $(".alert").fadeOut(function() {                    
                        $(this).addClass("hidden");          
                  });           
               }, 1500)      
          }
    })</script>
</html>
<!-- --------------------- 作者:luck_lin 来源:CSDN 原文:https://blog.csdn.net/qwe502763576/article/details/79672766 版权声明:本文为博主原创文章,转载请附上博文链接! -->
运行
  1. 安装好node,利用cmd、git、或编辑器比如vscode,其中一个,在app.js所在文件夹下 运行 node app.js
运行效果
  1. 进入聊天室效果。
    进入聊天室效果
  2. 退出聊天室效果退出聊天室
不足:

在本例子中有几个不足之处;

  1. 通过用户名存储的不同客户端的信息,虽然在本例子里便于操作,但是在关闭浏览器页面时,无法通过ID删除服务端里存储的客户信息,导致不重启服务的情况下(清理服务端的在线用户信息),误判断为已经在线,无法重新登录。
  2. 后期本人会改进,采用存储socketId的形式去改写该聊天室的例子,实现退出登陆以及关闭页面实现退出房间的操作。
本例子的知识点
  1. 利用node建立服务端 。
  2. socket.io 双向通信的使用(感兴趣的可去了解:https://www.w3cschool.cn/socket/socket-odxe2egl.html )。
  3. socket.io 中 emit()发送方法、on()监听方法的使用。
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值