WebSocket协议
WebSocket协议是一种在单个TCP连接上进行全双工通讯的协议(应用层)。它最初是为了在web浏览器和服务器之间创建持久性的连接而设计的,用于取代HTTP长轮询。
WebSocket通信过程主要包括客户端发起连接、服务器响应、双方握手连接、连接打开并且可以通信四个步骤。它通过HTTP/HTTPS端口完成握手,然后建立持久化的通信通道。
WebSocket能够很好地满足Web应用的实时通信需求,目前已经被广泛应用在网页聊天、股票报价、多人在线游戏等场景中
特点
- 建立在TCP协议之上,服务器端的实现比较容易。
- 与HTTP协议有良好的兼容性。默认端口也是80和443,并且握手阶段采用HTTP协议,因此握手时不容易屏蔽,能通过各种HTTP代理服务器。
- 数据格式比较轻量,性能开销小,通信高效。
- 可以发送文本,也可以发送二进制数据。
- 没有同源限制,客户端可以与任意服务器通信。
- 协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。
- 连接建立以后,属于持久连接。双方都可以任意发送数据。
- 有心跳机制,可以检测连接是否断开。
- 是全双工的。客户端浏览器和服务器端都可以同时发送数据。
- 没有请求响应模型,节省了不必要的network round trip。
握手
web浏览器和服务器都必须使用websocket来建立维护连接,也可以理解为HTTP握手(handshake)和TCP数据传输 WebSocket通信的握手过程如下: 1. 客户端发送请求给服务器,请求升级到WebSocket协议。
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
- Upgrade字段表示要升级协议,Connection字段值必须设置为Upgrade,表示要升级协议。
- Sec-WebSocket-Key是随机的字符串,服务器端会用这些数据来构造出一个SHA-1的信息摘要。
- Sec-WebSocket-Version表示支持的WebSocket版本。
2. 服务器端响应101状态码表示协议切换成功。
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
- 客户端必须发送Sec-WebSocket-Version和Sec-WebSocket-Key
- 服务器必须返回Sec-WebSocket-Accept确认协议
- 客户端可以通过Sec-WebSocket-Protocol发送应用子协议列表(不是必须)
- 如果客户端发送了子协议列表,服务器必须选择一个子协议并通过Sec-WebSocket-Protocol返回协议名;如果服务器不支持任何一个协议,连接断开
- 客户端可以通过Sec-WebSocket-Extensions发送一个或多个扩展;如果服务器没有返回扩展,则连接不支持扩展
Sec-WebSocket-Accept是将客户端请求中的Sec-WebSocket-Key加上一个特殊字符串,然后计算SHA-1摘要,进行BASE64编码。
3. 握手完成,WebSocket连接建立。客户端和服务器就可以通过这个连接通道自由地进行数据传输了。
所以WebSocket握手使用HTTP协议进行,但数据传输阶段则是独立的。这种握手方式让WebSocket连接能够很好地兼容现有的HTTP服务器,实现了与HTTP的无缝衔接。
Sec-WebSocket-Key和Sec-WebSocket-Accept
Sec-WebSocket-Key和Sec-WebSocket-Accept在WebSocket握手过程中的作用是:
- Sec-WebSocket-Key是一个客户端随机生成的base64编码的字符串,用于WebSocket握手请求中。
- 服务器收到握手请求后,将Sec-WebSocket-Key和一个特定的字符串"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"拼接,并进行SHA-1哈希计算,然后进行base64编码,生成Sec-WebSocket-Accept返回给客户端。
- 客户端收到响应后,也进行同样的计算,如果计算后的结果和服务器发送的Sec-WebSocket-Accept值一致,则验证通过,握手完成。
所以它们的作用是:
- 证明这个连接确实是对客户端 WebSocket 握手请求的响应。防止其他非法连接干扰。
- 防止缓存代理服务器中间人攻击(MITM)。每次握手使用随机生成的 Sec-WebSocket-Key,所以响应结果每次都不同,不能被缓存和重用。
- 对Sec-WebSocket-Key的编码提高了安全性,避免直接暴露在请求中。
- 通过这一握手验证流程,可以批准或者拒绝客户端的 WebSocket 连接请求,实现连接权限控制。
总之,Sec-WebSocket-Key和Sec-WebSocket-Accept通过一个挑战-响应的方式在传输层上保证了连接的安全性,是WebSocket协议重要的安全机制。
数据传输
客户端和服务器连接成功后,就可以进行通信了,通信协议格式是WebSocket格式,服务器端采用Tcp Socket方式接收数据,进行解析;WebSocket的数据传输分为两种:文本和二进制
Websocket的统一资源标志符是ws或wss,而不是HTTP或HTTPS,其中,ws对应http,wss对应https。
WebSocket 以 frame 为单位传输数据, frame 是客户端和服务端数据传输的最小单元, 当一条消息过长时, 通信方可以将该消息拆分成多个 frame 发送, 接收方收到以后重新拼接、解码从而还原出完整的消息, 在 WebSocket 中, frame 有多种类型, frame 的类型由 frame 头部的 Opcode 字段指示, WebSocket frame 的结构如下所示:
- fin: 1 bit,表示这是否是消息的最后一个分片。第一个分片可设置为0,中间分片设置为0,最后一个分片设置为1。
- rsv1, rsv2, rsv3: 各1 bit,扩展用,默认是0。
- opcode: 4 bit,表示数据帧的类型:
- 0x0: 继续之前的分片消息
- 0x1: 文本消息
- 0x2: 二进制消息
- 0x8: 关闭连接
- 0x9: ping
- 0xA: pong
- mask: 1 bit,是否进行掩码操作。客户端发送为1,服务器发送为0。
- payload length: 7 bits 或者 7+16 bits 或者 7+64 bits,表示payload数据的长度。
- masking-key: 0或32 bits,客户端发送的数据需进行掩码操作的密钥。
- payload data: 实际传输的数据。
- mask: 对payload data进行按位异或运算的掩码。
所以WebSocket frame既包含了传输控制信息,如fin、opcode、length等,也包含了实际有效载荷数据。这样的设计使其传输更加高效。
服务器和客户端会根据opcode理解和处理不同类型的数据帧,分片处理可以传输超过限制长度的大消息。mask则是提供一定的传输安全性。这些设计使得WebSocket frame成为一个高效、灵活的二进制传输格式。