WebSocket
WebSocket协议
协议概述
- WebSocket是一种网络传输协议,可在单个TCP连接上进行全双工通信,位于OSI模型的应用层。WebSocket协议在2011年由IETF标准化为RFC 6455,后由RFC 7936补充规范。Web IDL中的WebSocket API由W3C标准化。
- WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。
与Http协议的关系
- 有交集,但不是全部。
- HTTP有1.1和1.0,也就是所谓的keep-alive,把多个HTTP请求合并为一个,但是Websocket其实是一个新协议,跟HTTP协议基本没有关系,只是为了兼容现有浏览器的握手规范而已,也就是说它是HTTP协议上的一种补充。
- WebSocket是一个持久化协议。HTTP是非持久化协议,即Request=Response。
握手协议
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
- Connection:标识此次链接协议需要升级
- Upgrade:升级的目标协议
- Sec-WebSocket-Key:值为经过Base64转换的长度为16字节的一组数据
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
- Sec-WebSocket-Accept:Base64(SHA-1(Sec-WebSocket-Key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"))
报文结构
- FIN:标识这一帧数据是否是该分块的最后一帧。
- 1 为最后一帧
- 0 不是最后一帧,需要分为多个帧传输
- RSV1, RSV2, RSV3:默认值为0。
- 除非协议扩展(Extensions)声明了非0的值的含义。如果服务端收到非0的值,并且没有相应的定义,那么服务端将直接终止连接
- Opcode: 操作码,也就是定义了该数据是什么,如果不为定义内的值则连接中断。占四个位,可以表示0~15的十进制,或者一个十六进制。
- 0x0 表示一个继续帧
- 0x1 表示一个文本帧
- 0x2 表示一个二进制帧
- 0x3-0X7 非控制帧保留
- 0x8 表示一个连接关闭
- 0x9 表示一个PING
- 0xA 表示一个PONG
- 0xB-0xF 控制帧预留
- Mask:是否存在掩码。
- 客户端向服务器发送,必须掩码,值为1
- 服务端向客户端发送不需掩码,值为0
- PayLoad Length:表示Payload data的总长度。占7位,或者7+2个字节、或者7+8个字节。
- 0-125,则是payload的真实长度
- 126,则后面2个字节形成的16位无符号整型数的值是payload的真实长度,125<数据长度<65535
- 127,则后面8个字节形成的64位无符号整型数的值是payload的真实长度,数据长度>65535
- Masking-Key:当masked为1的时候才存在,为4个字节,否则为0,用于对我们需要的数据进行解密。
- PayLoad Data:定义为"Extension data" 后接"Application data"。所以字节长度是两者之和。
- Extension Data:在握手时就需要协商的扩展协议,需要指定扩展数据的长度或者如何计算长度。如若没有,则扩展数据为0字节。如有,则扩展数据会被包括在Payload中。
- Application Data:任意数据内容,数据长度是Payload长度减去Extension长度。
心跳机制
- 通俗来讲:就像心跳一样,每隔固定时间,来告诉服务器,客户端还“活着”。
- 为什么要有心跳机制?
- 客户端断网时,服务器端并没有感知。这样导致服务器继续向客户端发送数据包,并且这些数据可能会丢失。且服务端会维持这次连接,从而浪费服务端资源。
- 进一步,可以通过心跳机制来判断客户端的在线状态,客户端可以尽快重连。
- 具体实现
- Ping:Opcode为0x9,可以包含Application Data,双端都可以发送且需立即回复Pong,用来探活。如果服务端在收到Ping时,已经发送了close,则不用发送Pong。
- Pong:Opcode为0xA,Pong可以只响应最近一次的Ping。Pong必须包含Ping对应的Application Data。
握手时序图
抓包分析
TCP握手
数据传递
断开链接
- 可以看出61475端口一开始为HTTP服务的,后来由于101返回码,61475 端口转为 websocket 的 5001 端口号,服务端的8080端口对接客户端的5001端口号。关闭websocket时,由 61475 端口号发起关闭 5001 请求,与此同时 61475 端口和 服务端的8080端口通信,告诉服务端我要关闭端口,成功后61475 再告诉 5001 端口,我关闭成功了。整个关闭流程结束。
WebSocket的优点
- 较少的控制开销。相对于HTTP请求每次都要携带完整的头部,此项开销显著减少了。
- 更强的实时性。由于协议是全双工的,所以服务器可以随时主动给客户端下发数据。
- 保持连接状态。与HTTP不同的是,Websocket需要先创建连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息。而HTTP请求可能需要在每个请求都携带状态信息(如身份认证等)。
- 更好的二进制支持。Websocket定义了二进制帧,相对HTTP,可以更轻松地处理二进制内容。
- 可以支持扩展。Websocket定义了扩展,用户可以扩展协议、实现部分自定义的子协议。
- 更好的压缩效果。相对于HTTP压缩,Websocket在适当的扩展支持下,可以沿用之前内容的上下文,在传递类似的数据时,可以显著地提高压缩率。
- 支持跨域访问,没有同源限制。服务端可以根据Origin字段决定是否通过该次请求。
WebSocket与Socket之间的关系
- 通常所说的Socket API,是指操作系统中(也可能不是操作系统)提供的对于传输层(TCP/UDP)抽象的接口。
- Socket 其实并不是一个协议,它工作在 OSI 模型会话层(第5层),是为了方便大家直接使用更底层协议(一般是 TCP 或 UDP )而存在的一个抽象层。
- 而 WebSocket 则不同,它是一个完整的 应用层协议,包含一套标准的 API。
WebSocket与HTTP的比较
- 相同点
- 都是基于TCP的应用层协议;
- 都使用Request/Response模型进行连接的建立;
- 在连接的建立过程中对错误的处理方式相同,在这个阶段WS可能返回和HTTP相同的返回码;
- 都可以在网络中传输数据。
- 不同点
- WS使用HTTP来建立连接,但是定义了一系列新的header域,这些域在HTTP中并不会使用;
- WS的连接不能通过中间人来转发,它必须是一个直接连接;
- WS连接建立之后,通信双方都可以在任何时刻向另一方发送数据;
- WS连接建立之后,数据的传输使用帧来传递,不再需要Request消息;
- WS的数据帧有序。
常见的应用场景
- 即时通信
- 在线游戏
- 视频弹幕
- 直播间
- 股票行情
- 配置变更下发
- 在线调试

浙公网安备 33010602011771号