WebSocket指南:5分钟带你写一个小型的双端通信

1,590 阅读3分钟

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

WebSocket基础概念

WebSocket 是一种在浏览器和服务器之间建立持久连接来交换数据的方法。直观来说, 它基于tcp,先通过HTTP/HTTPS协议发起一条特殊的http请求进行握手后创建一个用于交换数据的TCP连接协议。 是不同于http的一种协议。

连接过程

new WebSocket(url) 被创建后,它将立即开始连接。

在连接期间,浏览器(使用 header)问服务器:“你支持 WebSocket 吗?”如果服务器回复说“我支持”,那么通信就以 WebSocket 协议继续进行,注意该协议不是 HTTP。

用三个端口来演示WebSocket的运行过程

WebSocket的主要特点是长连接双向通信,其中双向通行是实现即时通信,通知等功能的关键。

这里我们使用Koasocket.io来快速实现两个端口模拟的即时通讯效果,从而直观的感受下WebSocket的作用。

(注:这里的socket.io是一个实现WebSocket的包,以下的实例,是经过官网的实例改进而成的,有兴趣的可以去官网了解一下 Socket.IO

搭建两个端口:

const Koa = require("koa");
const { createServer } = require("http");
const { Server } = require("socket.io");
const app = new Koa();
const httpServer = createServer(app.callback());
//注意多个端口要解决一下跨域问题
const io = new Server(httpServer, { cors:{
    origin:'http://localhost:3001'
} });
io.on('connection', (socket) => {           //监听WebSocket的连接
    console.log('一个用户开始连接',socket.id)
    socket.on('chat message', (msg) => {    //监听chat message
        io.emit('chat message from 3000', msg);  //发送chat message from 3000及其包含的数据
      });
    socket.on('disconnect', () => {
        console.log('一个用户断开连接');
      });
});
​
​
httpServer.listen(3000,()=>{
    console.log('start 3000')
});
//index2.js 3001端口,用来模拟用户发送和接收信息
const Koa = require("koa");
const { createServer } = require("http");
const router = require('koa-router')(); 
const static = require('koa-static')
const app = new Koa();
const httpServer = createServer(app.callback());
app.use(router.routes()); 
​
router.get('/',static(__dirname+'/public')) //静态网页显示
​
httpServer.listen(3001,()=>{
    console.log('start 3001')
});

服务器引用的静态页面

<!DOCTYPE html>
<html>
  <head>
    <title>Socket.IO chat</title>
    <style>
      body { margin: 0; padding-bottom: 3rem; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }
​
      #form { background: rgba(0, 0, 0, 0.15); padding: 0.25rem; position: fixed; bottom: 0; left: 0; right: 0; display: flex; height: 5rem; box-sizing: border-box; backdrop-filter: blur(10px); }
      #input { border: none; padding: 0 1rem; flex-grow: 1; border-radius: 2rem; margin: 0.25rem; font-size: 50px;}
      #input:focus { outline: none; }
      #form > button { background: #333; border: none; padding: 0 1rem; margin: 0.25rem; border-radius: 3px; outline: none; color: #fff; }
​
      #messages { list-style-type: none; margin: 0; padding: 0; }
      #messages > li { padding: 0.5rem 1rem; }
      #messages > li:nth-child(odd) { background: #efefef; }
    </style>
  </head>
  <body>
    <ul id="messages"></ul>
    <form id="form" action="">
      <input id="input" autocomplete="off" /><button>Send</button>
    </form>
      <!--CDN加载socket.io-->
    <script src="https://cdn.bootcdn.net/ajax/libs/socket.io/4.1.3/socket.io.js"></script>
    <script>
    var socket = io('http://localhost:3000'); //向3000端口发起连接请求
    var form = document.getElementById('form');
    var input = document.getElementById('input');
​
    form.addEventListener('submit', function(e) {
        e.preventDefault();
        if (input.value) {
        socket.emit('chat message', input.value); //发送 chat message
        input.value = '';
        }
    });
    socket.on('chat message from 3000', function(msg) { //监听'chat message from 3000',并将其数据动态渲染到页面
        var item = document.createElement('li');
        item.textContent = msg;
        item.style.fontSize = '50px'
        messages.appendChild(item);
        window.scrollTo(0, document.body.scrollHeight);
    });
    </script>
  </body>
</html>

之后我们启动两个端口,然后分别在浏览器上打开两个3001端口,在3001端口,我们可以看到: 屏幕截图 2021-10-20 185729.png

在服务器端,我们可以看到3000端口打印出了如下内容:

屏幕截图 2021-10-20 185901.png

可以看到,两个3001端口,分别建立两个WebSocket连接,同时生成了两个socket.id来区分不同的用户。

我们在第一个页面发送消息,可以看到,这则消息通过服务器的广播,分别发送给了两个已经建立连接的页面发送了消息:

演示.gif

通过样例,我们可以很容易的看到,WebSocket实现了双端通信的效果。

WebSocket知识点(补)

WebSocket常用状态码

1000 CLOSE_NORMAL 正常关闭; 无论为何目的而创建, 该链接都已成功完成任务.

1001 CLOSE_GOING_AWAY 终端离开, 因为服务端错误或浏览器跳转到其他页面或关闭

1009 CLOSE_TOO_LARGE 由于收到过大的数据帧而断开连接.

1011 Internal Error 客户端由于遇到没有预料的情况阻止其完成请求, 因此服务端断开连接.

连接状态

  • 0 —— “CONNECTING”:连接还未建立,
  • 1 —— “OPEN”:通信中,
  • 2 —— “CLOSING”:连接关闭中,
  • 3 —— “CLOSED”:连接已关闭。

其他

  • 浏览器对WebSocket支持很好
  • WebSocket可以发送/接收字符串和二进制数据
  • 注意websocket需要长连接的支持。