作者:磊磊860219 | 来源:互联网 | 2023-08-10 09:55
Websocket背景历史上,如果一个web应用程序需要和server进行双向通信(例如,实时聊天和游戏),需要大量的http请求来检查server的内容是否有更新,同时也需要很多
Websocket
背景
历史上,如果一个web应用程序需要和server进行双向通信(例如,实时聊天和游戏),
需要大量的http请求来检查server的内容是否有更新, 同时也需要很多http请求来发送
通知,这种方式有许多问题:
server端必须使用大量的tcp连接来服务每一个client:一类连接用来发送信息给
client, 另一类连接用来接收新的消息。
有大量不必要网络开销,因为每一次消息通讯都都包含http header。
client需要维护一个map来映射发送数据的连接和接受数据的连接。
一个简单的解决方案就是使用一个tcp连接来进行双向通讯,这就是websocket的作用。
websocket使用80和443端口,对HTTP代理和网关友好。
连接握手过程
client发送
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
server响应
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
连接握手的目的是兼容基于HTTP的server和代理,所以一个端口可以同时服务HTTP请求和
websocket请求。
请求中Upgrage: websocket
表示这是一个websocket请求。服务端收到该请求后会根据
请求中携带的Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
通过特定算法生成
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
响应给客户端,客户端校验
通过握手成功。
握手结束后,双方就可以进行双向通讯了,所有的通讯内容都以数据帧格式来传输。
数据帧
![《浅析websocket》](https://img.php1.cn/3cd4a/1eebe/cd5/ed19db63ee478b98.png)
FIN: 1比特
表示一个message中的最后一个frame。
RSV1, RSV2, RSV3: 每个1比特
必须为0,后续扩展使用。
Optcode: 4比特
定义负载数据的解析方式。
%x0 表示一个连续帧。
%x1 表示一个文本帧。
0x2 表示一个二进制帧。
0x3-7 保留,以后给非控制帧使用。
0x8 表示连接关闭。
0x9 表示ping。
0xA 表示pong。
0xB-F 保留,以后给控制帧使用。
Mask: 1比特
表示负载数据是否masked。如果为1,masking-key
包含一个key,用来unmask负载
数据。所有从客户端方向发送的数据,该位必须置1。
*Playload length: * 7比特,7+16比特, 或者7+64比特
Masking key: 0或者4字节
如果mask
标志为1时存在,保存mask key。
Payload data: 负载数据。
关闭握手过程
![《浅析websocket》](https://img.php1.cn/3cd4a/1eebe/cd5/d67981797265d9c7.webp)
关闭握手比连接握手简单的多,连接的任何一端都可以发送一个close frame,
开始关闭握手,收到这个control frame的端发送一个close frame响应,
另一端收到这个close frame后关闭连接。
一端发送close frame后就表示这个连接将会被关闭并且不会再发送任何数据到另一端, 对端
收到close frame后知道这个连接将会被关闭,后续收到的数据都会被丢弃。
websocket关闭握手的目的是完善TCP的关闭握手,因为在端到端的情景TCP的关闭握手并不
总是可信赖的,尤其端到端中间有代理或者防火墙的情况下。
通过发送一个close frame然后等待响应,这种方式避免了不必要的数据丢失。
websocket & nginx
nginx并没有支持websocket,只是支持websocket的代理。
http {
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream websocket {
server 192.168.100.10:8010;
}
server {
listen 8020;
location / {
proxy_pass http://websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
}
nginx也有第三方支持websocket的模块nchan,但
不是为流媒体设计的。
哪些服务端支持websocket
Node.js
Socket.IO
WebSocket-Node
ws
Java
Rubby
Python
Erlang
.NET
参考资料
http://blog.teamtreehouse.com/an-introduction-to-websockets
http://www.websocket.org/aboutwebsocket.html
https://www.html5rocks.com/en/tutorials/websockets/basics
https://os.alfajango.com/websockets-slides/#/2
The WebSocket Protocol