WebSocket

概述

WebSocket**是一种网络传输协议,可在单个TCP连接上进行全双工通信,位于OSI模型应用层。WebSocket协议在2011年由IETF标准化为RFC 6455,后由RFC 7936补充规范。Web IDL中的WebSocket API由W3C标准化。

WebSocket 最大的特定是客户端和服务端都可以主动给对方发送消息。

WebSocket 应用场景

  • 实时消息
  • 弹幕
  • 游戏

WebSocket 同样支持TLS加密传输。

WebSocket 不使用TLS的时候协议是 ws:// 端口号 是: 80端口。

WebSocket 使用TLS 的时候协议是 wss:// 端口号是 : 443端口。

WebSocket 和 http ,https的 端口号占用相同,好处是可以不用单位为websocket开启防火墙的限制

WebSocket 特点

  • 建立连接

    在发送消息之前,需要先进行websocket握手建立连接,建立连接后,才能进行websocket通信。

  • 双向通信

    客户端和服务端可以相互发送消息,客户端可以向服务端发送消息

  • 没有请求头

    不用像http协议那样在传输的时候携带大量的头部信息

  • 有状态的

    websocket 是一个有状态的连接,有一个建立连接的过程,建立好连接通道后 可以相互通信。

WebSocket 客户端使用

绝大部分的web浏览器支持了WebSocket Api.

在使用WebSocket 的时候需要建立一个WebSocket 对象.

1
2
3
4
WebSocket WebSocket(
in DOMString url, //要连接的URL
in optional DOMString protocols //指定子协议,可选选项
);

示例:

1
var exampleSocket = new WebSocket("ws://www.example.com/socketserver", "protocolOne");

通过 exampleSocket 对象的 readyState 来判断连接状态。

连接状态有四种

1
2
3
4
5
6
7
8
0 (WebSocket.CONNECTING)
正在链接中
1 (WebSocket.OPEN)
已经链接并且可以通讯
2 (WebSocket.CLOSING)
连接正在关闭
3 (WebSocket.CLOSED)
连接已关闭或者没有链接成功

连接建立完成后使用websocket对象发送数据

1
exampleSocket.send("Here's some text that the server is urgently awaiting!");

具体可参考: https://developer.mozilla.org/zh-CN/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications

WebSocket 连接过程

  1. 在客户端要和服务端建立websocket连接的时候,客户端首先向服务端发送一个普通的http请求。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
GET ws://121.40.165.18:8800/ HTTP/1.1
Host: 121.40.165.18:8800
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36
Upgrade: websocket
Origin: http://www.websocket-test.com
Sec-WebSocket-Version: 13
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Sec-WebSocket-Key: 4uPJrrDC9ILz3rXuuQVthw==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

Upgrade: websocket 告诉服务端,此次请求是要升级为 websocket连接

Origin: http://www.websocket-test.com 可选,表示websocket连接发起的页面

Sec-WebSocket-Version: 13 表示支持的 Websocket 版本。RFC6455 要求使用的版本是 13.

Sec-WebSocket-Key: 4uPJrrDC9ILz3rXuuQVthw== 客户端随机生成的一个字符串

Sec-WebSocket-Extensions 如果存在,该字段的值表示客户端需要服务端支持的扩展协议.

  1. 服务端接收到客户端的请求信息后。

    收到客户端发过来的 Sec-WebSocket-Key 的值后,会进行一些操作

    Sec-WebSocket-Key 加上一个固定的GUID值 (258EAFA5-E914-47DA-95CA-C5AB0DC85B11)

    1
    4uPJrrDC9ILz3rXuuQVthw== + 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 = 4uPJrrDC9ILz3rXuuQVthw==258EAFA5-E914-47DA-95CA-C5AB0DC85B11

    然后将上面加的字符串结果做一个SHA-1的计算。

    得到结果.

    1
    a369829599a8757fc967ccf8e3a7d2af7e6d9d5a

    将上面的SHA-1的结果做一个Hex TO Base64编码。 (http://www.tomeko.net/online_tools/hex_to_base64.php?lang=en)

    1
    o2mClZmodX/JZ8z446fSr35tnVo=
  2. 服务端将计算的结果响应给客户端

    1
    2
    3
    4
    HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: o2mClZmodX/JZ8z446fSr35tnVo=

    **Sec-WebSocket-Accept ** 就是通过客户端发过期的字符串计算出来的一个结果值。

  3. 客户端接收到服务端的响应后,接下来讲于客户端使用websocket协议进行连接.