socket.io入门:实现简单的聊天应用

socket.io是什么

说到socket.io,就不得不提一下WebSocket
WebSocket是H5开始提供的一种在单个 TCP 连接上进行全双工通讯的协议
在这里插入图片描述
在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道,两者之间就直接可以数据互相传送,使得服务端可以主动推送数据给客户端,在WebSocket出现之前,实现这种推送技术通常使用的方法都是ajax轮询,由客户端定期发送请求查询服务端有无更新,这会耗费非常多的宽带资源,WebSocket的出现解决了这一问题

socket.io是一套WebSocket库,将WebSocket,ajax轮询等各种方法进行了封装,使用时会基于所处环境,从各种方式中选出合适的方法,基于事件来实现实时的双向通讯
整套socket.io包含了客户端的js和服务端的node.js

socket.io服务端

通过和其他的node.js web框架结合,可以非常便捷的搭建一套支持socket.io的接口,这里使用express

// app.js
var app = require('express')();
var server = require('http').Server(app);
// 初始化 socket.io 实例
var io = require('socket.io')(server);

// 监听 connection 事件来接收 sockets
io.on('connection', function (socket) {
  console.log('user connected')
  // 每个socket都可以触发一个特殊的disconnect事件
  socket.on('disconnect',function(){
    console.log('user disconnected')
  })
});

客户端

通过cdn引入socket.io客户端的js文件,就可以来连接设置了socket.io的服务器了,这里使用vue来搭建一个简单的页面

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="app">
    socket.io聊天室
    </div>
  </body>
</html>

<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
  var app = new Vue({
    el: "#app",
    data: {
    
    },
    methods: {

    },
    created() {
      var socket = io.connect("http://localhost:3000");
    },
  });
</script>

此时打开该页面,服务端会打印user connected,关闭会打印user disconnected,打开多次会显示多个user connected,客户端和服务端的连接已经成功

添加逻辑

首先,在用户进入时,我们要让用户取一个昵称,在用户提交该昵称后,使用户进入聊天室,随后告知其余在聊天室的用户,该用户进入了

服务端

io.on('connection', function (socket) {
  console.log('user connected')
  socket.on('disconnect',function(){
    console.log('user disconnected')
  })
  // 接收客户端的用户进入事件
  socket.on('enter',function(data){
  	// broadcast代表广播至除了触发事件的socket之外的所有socket,用于触发客户端的新用户进入事件
    socket.broadcast.emit('userEnter',{name:data.name})
  })
});

客户端

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="app">
    	socket.io 聊天室
      <div v-if="!hasName">
        <input type="text" v-model="name" placeholder="请输入昵称" />
        <button @click="confirm">确定</button>
      </div>
      <div v-else>
        聊天室
      </div>
    </div>
  </body>
</html>

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<!-- <script src="/socket.io/socket.io.js"></script> -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
  var app = new Vue({
    el: "#app",
    data: {
      name: "",
      hasName: false,
      socket: null,
    },
    methods: {
      confirm() {
      	// 确认用户已经输入名字
        if (this.name == "") return;
        this.hasName = true;
       	// 连接至服务端
        this.socket = io.connect("http://192.168.123.170:3000");
        // 触发服务端的enter事件,告知服务端进入用户的昵称
        this.socket.emit('enter',{name:this.name})
        // 接收服务端的新用户进入事件
        this.socket.on('userEnter',data=>{
          alert(`欢迎${data.name}加入了聊天室`)
        })
      },
    },
    created() {
      // var socket = io.connect("http://localhost:3000");
    },
  });
</script>

这样就完成了进入聊天室和通知其他用户新用户进入的功能

接下来要完善聊天的功能,在一个用户输入消息发送后,广播至其余的连接用户,客户端发送对应消息的用户名与发送的消息,服务器广播至其他用户处
具体代码如下

服务端

io.on('connection', function (socket) {
  console.log('user connected')
  socket.on('disconnect',function(){
    console.log('user disconnected')
  })
  // 接收客户端的用户进入事件
  socket.on('enter',function(data){
  	// broadcast代表广播至除了触发事件的socket之外的所有socket,用于触发客户端的新用户进入事件
    socket.broadcast.emit('userEnter',{name:data.name})
  })
  // 接收客户端的发送消息事件
  socket.on('sendMsg',function(data){
	// 触发客户端的接收服务器消息事件,这里不使用broadcast
    socket.emit('receiveMsg',{name:data.name,msg:data.msg})
  })
});

客户端

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="app">
    	socket.io 聊天室
      <div v-if="!hasName">
        <input type="text" v-model="name" placeholder="请输入昵称" />
        <button @click="confirm">确定</button>
      </div>
      <div v-else>
        <input
          type="text"
          v-model="input"
          placeholder="请输入消息"
          @keydown.13="sendMsg"
        />
        <button @click="sendMsg">点我发送</button>
        <div v-for="(item,index) in chatList">
          {{item.name}}:{{item.msg}}
        </div>
      </div>
    </div>
  </body>
</html>

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<!-- <script src="/socket.io/socket.io.js"></script> -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
  var app = new Vue({
    el: "#app",
    data: {
      name: "",
      hasName: false,
      socket: null,
    },
    methods: {
      confirm() {
      	// 确认用户已经输入名字
        if (this.name == "") return;
        this.hasName = true;
       	// 连接至服务端
        this.socket = io.connect("http://192.168.123.170:3000");
        // 触发服务端的enter事件,告知服务端进入用户的昵称
        this.socket.emit('enter',{name:this.name})
        // 接收服务端的新用户进入事件
        this.socket.on('userEnter',data=>{
          alert(`欢迎${data.name}加入了聊天室`)
        })
        // 接收服务端的广播,将发送的消息添加至消息列表内
        this.socket.on("receiveMsg", (data) => {
          this.chatList.push(data);
        });
      },
      sendMsg() {
        if (this.input == "") return;
        // 发送消息给服务器,告知用户名与消息
        this.socket.emit("sendMsg", { name: this.name, msg: this.input });
        this.input = "";
      },
    },
    created() {
      // var socket = io.connect("http://localhost:3000");
    },
  });
</script>

这样就完成了一个简单的聊天室,当然还有部分可以优化的地方
1.本机发送消息后不应等服务器广播消息而是直接将消息添加至列表内
2.本机发送的消息和别人发送的消息区别显示
3.添加在线成员列表
4.添加私聊功能

欢迎分享你的改进

猜你喜欢

转载自blog.csdn.net/weixin_47232046/article/details/106146506