暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

对 Websocket 完全不懂,但又想搞个聊天室,行吗?

勾勾的前端世界 2021-10-14
982

回忆以下上一篇内容:《有了 HTTP 协议,为什么还需要 Websocket?》,了解一下 Websocket 的特点和通信原理,我们接着来看 Websocket 服务端与客户端实现。


Websocket 服务端与客户端实现


经过前面对通信过程的梳理,我们将 WebSocket 通信的基本机制已经说的差不多了,为了方便你快速进入实战阶段,我们暂时放弃纯手写实现,直接选择使用老牌的 WebSocket 库:  WebSocket-Nodehttps://github.com/theturtle32/WebSocket-Node 


简单介绍一下 WebSocket-Node,它有多老牌呢?


NPM 的包名字就是直接使用的 “WebSocket”。曾经,我们西岭老湿看到之后就给出了两个字的评价:“猖狂”


这个库完全使用 JavaScript 实现,包含了客户端及服务端的实例。其中,客户端包含了 Node 和 浏览器 两个运行环境的代码,除了支持我们前面提到的 Websocket 协议的 13 版本,它同时还支持 Websocket 协议 8 这个老版本,实属优秀。


接下来,我们就来看看,如何借助 Websocket-Node 实现一个 Websocket 服务。


服务端

安装 npm install websocket 后,创建服务器运行文件 ws-server.js ,代码如下,请认真阅读代码及注释:

    // === 作为帅哥,一定要加注释 ===
    var Websocket = require('websocket').server
    var http = require('http')


    // 创建 HTTP 服务,作为第一次握手链接使用
    var httpServer = http.createServer().listen(8080,function(){
    console.log('http://127.0.0.1:8080')
    })


    // 创建 websocket 服务实力
    var wsServer = new Websocket({
    // 配置依赖的握手 http 服务器
    httpServer:httpServer,


    autoAcceptConnections:false
    })


    // 保存链接池
    var conArr = []


    // 监听 ws 请求事件
    wsServer.on('request',function(request){
    // 获取链接示例
    var connection = request.accept()
    // 保存连接池
    conArr.push(connection)
    // 监听消息事件
    connection.on('message',function(msg){
    console.log(msg)
    // 循环连接池,推送广播消息至客户端
    for(let i = 0;i<conArr.length;i++){
    conArr[i].send(msg.utf8Data)
    }
    })
    })


    // 据说,长得好看的都会看注释


    过多的描述,就不写了,据说,长得好看的都会看代码注释(●'◡'●)


    运行代码文件后,不出意外的情况下,命令行进程会被占用监听端口也会被占用,证明服务端运行成功。如果两个都没被占用,想啥呢?失败了呀宝子……


    如果服务器启动成功,我怎么用客户端建立链接查看呢?有一款 Websocket 客户端工具叫 WebsocketMan,如果感兴趣,你可以下载来试试。


    但是像我这样的帅哥,一般都是自己写客户端:)


    客户端

    Websocket 的客户端并没有什么技术难点,就是浏览器 API 调用。只要你把通信机制够清楚,这玩意就没有不会,因为非常简单,我们直接选择纯手写就可以了,如果你想使用 Websocket-Node 客户端,确实还会更简单。


    当然,在写之前,还是要去看看手册的,要不然你怎么知道有哪些 API 呢?

    来,手册地址给你:https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket


    你先看着,我就不客气,直接开干……

      <body>
      <div id="msg"></div>
      <input type="text" id="text">
      <input type="button" value="发送" onclick="send()">


      <script>
      //调用websocket对象建立连接:
      //参数:ws/wss(加密)://ip:port (字符串)
      var websocket = new WebSocket('ws://127.0.0.1:8080')
      // console.log(websocket.readyState) 0
      // readyState
      // 0 链接还没有建立(正在建立链接)
      // 1 链接建立成
      // 2 链接正在关闭
      // 3 链接已经关闭


      // 监听链接开启事件
      websocket.onopen = function () {
      console.log(websocket.readyState)
      }


      // 绑定按钮点击事件
      function send() {
      var text = document.getElementById('text').value
      // ws 消息发送
      websocket.send(text)
      }


      // 监听服务端消息推送事件
      websocket.onmessage = function (back) {
      console.log(back.data)
      }


      // 监听连接错误信息
      // websocket.onerror = function (evt, e) {
      // console.log('Error occured: ' + evt.data);
      // };


      //监听连接关闭
      // websocket.onclose = function (evt) {
      // console.log("Disconnected");
      // };
      </script>


      </body>


      过多的描述,就不写了,据说,长得好看的都会看代码注释(●'◡'●)


      至此,一个完整的 websocket 通信已经建立完成并能够进行双向通信了。


      Websocket-Node 确实很好用,但是功能也确实比较单一了,需要你对 WebSocket 机制有一定的理解之后,才能实现相应的能力。如果,我对 websocket  完全不懂,但又想搞个聊天室,能不能行?


      指!定!能!行!


      Socket.IO


      一个目前最为强大且好用的,基本屏蔽了 websocket 概念的 websocket 库。你几乎不用掌握 websocket 相关的知识,只需要按照 Socket.IO 中提供的 API 就能够很好的实现一个 websocket 通信。


      注意:程序员要“除机心”。

      • 在不了解 Websocket 时,学习 Websocket 中,强烈不建议使用

      • 在生产环境下,强烈建议使用


      服务端

        const { createServer } = require("http");
        const { Server } = require("socket.io");


        const httpServer = createServer();
        const io = new Server(httpServer, {
        cors: {
        origin: "*",
        methods: ["GET", "POST"]
        }
        });


        io.on("connection", (socket) => {
        socket.on('sendMsg',(data)=>{
        io.emit('pushMsg',data)
        })
        });


        httpServer.listen(3000, function () {
        console.log('http://127.0.0.1:3000')
        });


        客户端

          <!DOCTYPE html>
          <html lang="en">


          <head>
          <meta charset="UTF-8">
          <meta http-equiv="X-UA-Compatible" content="IE=edge">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>Document</title>
          <script src="https://cdn.socket.io/4.2.0/socket.io.min.js"
          integrity="sha384-PiBR5S00EtOj2Lto9Uu81cmoyZqR57XcOna1oAuVuIEjzj0wpqDVfD0JA9eXlRsj"
          crossorigin="anonymous"></script>
          </head>


          <body>
          <input type="text" id="text">
          <input type="button" value="发送" onclick="send()">


          <script>
          var socket = io.connect('http://127.0.0.1:3000')
          function send() {
          var text = document.getElementById('text').value
          socket.emit('sendMsg', text)
          }


          socket.on('pushMsg', (data) => {
          console.log(data)
          })
          </script>


          </body>


          </html>


          没什么可解释的,就直接按照 Socket.IO 的 API 写就完事了。

          吾闻之吾师,有机械者必有机事,有机事者必有机心。机心存於胸中,则纯白不备。

          -- 《庄子·天地》


          参考资料:

          《HTML5  WebSocket权威指南》 机械工业出版社  2014 年 3 月第 1 版

          http://www.ruanyifeng.com/blog/2017/05/websocket.html

          https://www.cnblogs.com/hustskyking/p/websocket-with-node.html

          https://www.cnblogs.com/jingmoxukong/p/7755643.html

          https://zhuanlan.zhihu.com/p/23467317

          https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket

          库:

          https://socket.io/docs/

          https://github.com/theturtle32/WebSocket-Node

          微信不可以跳转外链,请自行搜索,阿里嘎多!


          推荐阅读:

          有了 HTTP 协议,为什么还需要 Websocket?

          当面试官问:为什么是 TCP 三次握手?不是两次、四次?

          Snowpack,新时代前端构建的先锋

          React 数据流管理:组件之间数据是如何传递的?


          恭喜你又在前端道路上进步了一点点。

          点个“在看”和“”吧!

          文章转载自勾勾的前端世界,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

          评论