01-websocket简介及抓包分析
1 websocket简介
websocket是⼀种⽹络传输协议,可在单个tcp链接上进⾏全双⼯通信,位于OSI模型的应⽤层。
WebSocket 与 HTTP/2 ⼀样,都是为了解决 HTTP 某⽅⾯的缺陷⽽诞⽣的。HTTP/2 针对的是“队头阻塞”,⽽ WebSocket 针对的是“请求 - 应答”通信模式。
WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成⼀次握⼿,两者之间就可以创建持久性的连接,并进⾏双向数据传输。
WebSocket协议在2011年由标准化为,后由补充规范。
RFC6455
RFC7936
WebSocket是⼀种与HTTP不同的协议。两者都位于OSI模型的应⽤层,并且都依赖于传输层的TCP协议。
虽然它们不同,但RFC 6455规定:“WebSocket设计为通过80和443端⼝⼯作,以及⽀持HTTP代理和中介”,从⽽使其与HTTP协议兼容。 为了实现兼容
性,WebSocket握⼿使⽤HTTP Upgrade头[1]从HTTP协议更改为WebSocket协议。
WebSocket协议⽀持Web浏览器(或其他客户端应⽤程序)与Web服务器之间的交互,具有较低的开销,便于实现客户端与服务器的实时数据传输。 服务器可以通过标准化的⽅式来实现,⽽⽆需客户端⾸先请求内容,并允许消息在保持连接打开的同时来回传递。通过这种⽅式,可以在客户端和服务器之间进⾏双向持续对话。 通信通过TCP端⼝80或443完成,这在防⽕墙阻⽌⾮Web⽹络连接的环境下是有益的。另外,Comet之类的技术以⾮标准化的⽅式实现了类似的双向通信。
1.1 websocket特点
websocket的特点如下所⽰:
提供全双⼯通信;
还可以在TCP之上启⽤消息流;
WebSocket协议规范将ws(WebSocket)和wss(WebSocket Secure)定义为两个新的统⼀资源标识符(URI)⽅案,分别对应明⽂和加密连接。
WebSocket 的默认端⼝也选择了 80 和 443,因为现在互联⽹上的防⽕墙屏蔽了绝⼤多数的端⼝,只对 HTTP 的 80、443 端⼝“放⾏”,所以 WebSocket 就可以“伪装”成 HTTP 协议,⽐较容易地“穿透”防⽕墙,与服务器建⽴连接。
WebSocket 更侧重于“实时通信”,⽽ HTTP/2 更侧重于提⾼传输效率。
1.2 服务器⽀持框架
在服务器⽅⾯,⽹上都有不同对websocket⽀持的服务器:
php -
websocket和socketjetty -
netty - /netty
ruby -
Kaazing - /web/20100923224709//confluence/display/KAAZING/Home Tomcat -
WebLogic - acle/us/products/middleware/cloud-app-
foundation/weblogic/overview/index.html(12.1.2开始⽀持)
node.js - github/Worlize/WebSocket-Node
node.js - socket.io
nginx - nginx/
mojolicious - mojolicio.us/
python - github/abourget/gevent-socketio
Django - github/stephenmcd/django-socketio
erlang - github/ninenines/cowboy.git
1.3 websocket 帧结构
“结束标志位 + 操作码 + 帧长度 + 掩码”
第⼀位“FIN”:相当于 HTTP/2 ⾥的“END_STREAM”,表⽰数据发送完毕。⼀个消息可以拆成多个帧,
接收⽅看到“FIN”后,就可以把前⾯的帧拼起来,组成完整的消息。
“FIN”后⾯的三个位是保留位,⽬前没有任何意义,但必须是 0。
“Opcode”,操作码:其实就是帧类型,⽐如 1 表⽰帧内容是纯⽂本,2 表⽰帧内容是⼆进制数据,8 是关闭连接,9 和 10 分别是连接保活的 PING 和 PONG。
掩码标志位“MASK”:表⽰帧内容是否使⽤异或操作(xor)做简单的加密。⽬前的 WebSocket 标准规定,客户端发送数据必须使⽤掩码,⽽服务器发送则必须不使⽤掩码。
“Payload len”:表⽰帧内容的长度。它是另⼀种变长编码,最少 7 位,最多是 7+64 位,也就是额外增加 8 个字节,所以⼀个WebSocket 帧最⼤是 2^64。
“Masking-key”:掩码密钥,它是由上⾯的标志位“MASK”决定的,如果使⽤掩码就是 4 个字节的随机数,否则就不存在。
2 websocket握⼿过程
如下所⽰是笔者根据netty ws样例进⾏浏览器浏览的⼀个⽤例,可以看到这个websocket链接可以分为三个阶段:
1. 建⽴tcp链接;
2. 客户单采⽤http头进⾏ws握⼿;
3. 协议由http切换成ws传输数据;
2.1 客户端的第⼀个GET
如下图所⽰是客户端websocket链接的第⼀个报⽂。
WebSocket 的握⼿是⼀个标准的 HTTP GET 请求,但要带上两个协议升级的专⽤头字段:
“Connection: Upgrade”,表⽰要求协议“升级”;
“Upgrade: websocket”,表⽰要“升级”成 WebSocket 协议。
另外,为了防⽌普通的 HTTP 消息被“意外”识别成 WebSocket,握⼿消息还增加了两个额外的认证⽤头字段(所谓的“挑
战”,Challenge):
Sec-WebSocket-Key:⼀个 Base64 编码的 16 字节随机数,作为简单的认证密钥;
Sec-WebSocket-Version:协议的版本号,当前必须是 13。
2.2 服务端响应 SwitchingProtocol
服务器收到 HTTP 请求报⽂,看到上⾯的四个字段,就知道这不是⼀个普通的 GET 请求,⽽是 WebSocket 的升级请求,于是就不⾛普通的 HTTP 处理流程,⽽是构造⼀个特殊的“101 Switching Protocols”响应报⽂,通知客户端,接下来就不⽤ HTTP 了,全改⽤WebSocket 协议通信。(有点像 TLS 的“Change Cipher Spec”)
WebSocket 的握⼿响应报⽂也是有特殊格式的,要⽤字段“Sec-WebSocket-Accept”验证客户端请求报⽂,同样也是为了防⽌误连接。
具体的做法是把请求头⾥“Sec-WebSocket-Key”的值,加上⼀个专⽤的 UUID “258EAFA5-E914-47DA-95CA-
C5AB0DC85B11”,再计算 SHA-1 摘要。
客户端收到响应报⽂,就可以⽤同样的算法,⽐对值是否相等,如果相等,就说明返回的报⽂确实是刚才握⼿时连接的服务器,认证成功。
握⼿完成,后续传输的数据就不再是 HTTP 报⽂,⽽是 WebSocket 格式的⼆进制帧了。
2.3 客户端ws报⽂
客户端和服务端编码则更好验证了之前开头的总结:
WebSocket 的帧头就四个部分:“结束标志位 + 操作码 + 帧长度 + 掩码”;
2.4 服务端ws回复

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。