webSocket 连接有它自己的连接方案(从 http 连接开始)、从 http 到 webSocket 协议的升级方案、它自己的安全协商方案和它自己的数据格式,并且在规范中有一些变化时间,这意味着您可能必须支持多个版本才能支持所有客户端。要实现 webSocket 服务器,您必须实现所有这些。
这里定义了原始协议:https://www.rfc-editor.org/rfc/rfc6455
简而言之:
-
每个 webSocket 连接都以包含一些自定义标头的 http 请求开始,这些标头表明它是“升级”到 webSocket 协议的请求。该初始请求还包含一个安全密钥和一个安全版本号。
-
如果服务器接受升级到 webSocket 协议,它会返回一个带有另一个安全密钥的响应。
-
在确认后,此时,客户端或服务器可以开始使用 webSocket 数据帧数据包格式并使用适当的安全密钥向另一端发送数据包。
例子:
客户端发送:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com
服务器响应:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
还有,从MDN 了解数据框的外观:
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 ... |
+---------------------------------------------------------------+
您可以在这些其他答案中看到有关协议如何的其他讨论:
nodejs net sockets + websocket without socket.io
Do websocket implementations use http protocol internally?
What's the difference between WebSocket and plain socket communication?
除非这纯粹是出于学习原因的学术练习,否则在重新实现已经存在标准、经过良好测试的开源实现的低级协议时,会非常非常低效地利用开发人员的时间。随着标准的不断发展,您将花费大量时间在低级位旋转和与不同客户端实现的兼容性测试上,然后将更多时间用于维护。