WebSocket 原理及应用:搭建一个在线的答案之书

244 阅读4分钟

思维导图

WebSocket.png

1. 为什么要使用WebSocket

为什么要使用WebSocket协议?它跟 HTTP 协议有什么不同?

因为HTTP协议的通信只能由客户端发起,对于想要双向通信的服务而言,如聊天室等,就会有性能瓶颈,鉴于此,WebSocket 就这样闪亮登场,提升Web的浏览速度。

2. 什么是WebSocket

WebSocket,即 Web 浏览器与 Web 服务器之间全双工通信标准。其中,WebSocket 协议由 IETF 定为标准,WebSocket API 由W3C定为标准。

2.1. WebSocket协议

Web 服务器与客户端之间建立起 WebSocket 协议的通信连接,之后所有的通信都依靠这个专用协议进行。通信过程中可互相发送 JSON、XML、HTML 或图片等任意格式的数据。

由于是建立在 HTTP 基础上的协议,因此连接的发起方仍是客户端,而一旦确立 WebSocket 通信连接,不论服务器还是客户端,任意一方都可直接向对方发送报文。

WebSocket协议有以下的特点

  • WebSocket协议建立在 TCP 协议之上。

  • 与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。

  • 同源策略不适用于WebSocket,因此可以打开到任意站点的连接。

  • 推送功能:支持由服务器向客户端推送数据的推送功能。这样,服务器可直接发送数据,而不必等待客户端的请求。

  • 减少通信量:只要建立起 WebSocket 连接,就希望一直保持连接状态。和 HTTP 相比,不但每次连接时的总开销减少,而且由于 WebSocket 的首部信息很小,通信量也相应减少了。

WebSocket首部

WebSocket首部的格式如下,相较于HTTP协议的定义,数据量比较小。

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-------+-+-------------+-------------------------------+
     |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
     |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
     |N|V|V|V|       |S|             |   (if payload len==126/127)   |
     | |1|2|3|       |K|             |                               |
     +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
     |     Extended payload length continued, if payload len == 127  |
     + - - - - - - - - - - - - - - - +-------------------------------+
     |                               |Masking-key, if MASK set to 1  |
     +-------------------------------+-------------------------------+
     | Masking-key (continued)       |          Payload Data         |
     +-------------------------------- - - - - - - - - - - - - - - - +
     :                     Payload Data continued ...                :
     + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
     |                     Payload Data continued ...                |
     +---------------------------------------------------------------+

2.2. WebSocket API

WebSocket API 由 W3C定为标准。JavaScript可调用 WebSocket 程序接口,以实现 WebSocket 协议下全双工通信。

var socket = new WebSocket('ws://game.example.com:12010/updates');
  • 必须给WebSocket构造函数传入一个绝对的URL
  • 同源策略不适用于WebSocket,因此可以打开到任意站点的连接

3.WebSocket的工作过程

为了实现 WebSocket 通信,在 HTTP 连接建立之后,需要完成一次握手的步骤。

Screenshot

3.1. HTTP 阶段

HTTP请求的Request

HTTP-Request.png

  • Origin字段表示这本身是一个HTTP请求
  • Connection字段的值为Upgrade,告知服务器通信协议发生改变
  • Upgrade字段的值为websocket,表示通信协议发生改变,改为websocket,以达到握手的目的。

HTTP请求的Response

HTTP-Response.png

  • 对于之前的请求,返回状态码 101 Switching Protocols 的响应。

3.2. WebSocket 阶段

成功握手确立 WebSocket 连接之后,通信时不再使用 HTTP 的数据 帧,而采用 WebSocket 独立的数据帧。

WebSocket-data.png

  • 绿色的表示客户端发送给服务器端的数据
  • 红色的表示服务器端发送给客户端的数据
  • 在此过程中,连接一直保持畅通

4 示例:在线的答案之书

答案之书是一本神奇的书,你想问的所有问题都可以在这本书中找到答案。默默想到一个问题,然后翻开这本书,随便找到一页,这页上就有你所想问题的答案。

那么要是有一本线上的答案之书,那就更方便了?该如何使用WebSocket实现一本线上的答案之书

在页面input框里输入你的问题,然后点击interactbutton与服务器交互,寻求答案。还可以只点击readingbutton,看到源源不断的答案

4.1. 效果图

demo.mov.gif

4.2. 客户端

客户端实现的主要代码如下:

// main code part
const socket = new WebSocket(`ws://localhost:8080/chinese`);

const interactButton = document.getElementById('interact');
interactButton.addEventListener('click', () => {
    const value = document.getElementById('input').value;
    //客户端给服务器发送消息
    socket.send(value);
})
  • ws wss表示这是一个WebSocket请求,其中wss类似于https,带加密的
  • socket.send()是给服务器发送消息的方法

4.3 服务器端

服务器端实现的主要代码如下:

// main code part
const ws = require('ws');
const http = require('http');
const {parse} = require("url");

const server = http.createServer();
const wss = new ws.WebSocketServer({noServer: true});

wss.on('connection', (ws, req) => {
    const { pathname } = parse(req.url);
    const language = pathname === '/english' ? 'english' : 'chinese';

    ws.on('message', function message(data) {
        // 服务器发送消息给客户端
        ws.send(resultMsg);
    });
});


server.listen(8080, () => {
    console.log(`listening port at ${PORT}...`);
});

  • 服务器端的代码引入了http模块,使用http模块创建了server服务,然后监听在8080端口
  • wss服务监听connection,当有客户端的消息来到时,服务器发送消息返回,同样使用的是send方法

5. 参考