小菜学网络之WebSocket协议

Web应用 采用 HTTP 协议进行通信:客户端向服务器发送 HTTP 请求,服务器对请求进行处理后,向客户端回复 HTTP 响应。换句话讲,HTTP 协议只能客户端主动发起请求,服务器被动进行响应。

图片

不少应用场景要求服务主动向客户端进行推送,这时 HTTP 协议就有点捉襟见肘了。举个例子,为实现 Web 聊天室功能,当新消息到达时,服务器必须向客户端推送通知。只用 HTTP 协议来实现,我们必须在客户端做轮询。

轮询有个致命的缺陷——性能比较差:如果轮询频率很高,服务器要消耗很多资源;但如果控制轮询频率,应用消息通知的实时性又大打折扣。

很显然,服务器主动向客户端推送数据,也是一个非常常见的应用场景,最好能从网络协议层面进行支持。为此,计算机网络先驱们设计了 WebSocket 协议。

WebSocket 协议,顾名思义为 Web 应用引入了 套接字( socket )通信能力。Websocket 是一种应用层协议,以 TCP 为底层传输协议,为通信双方提供了一个 全双工 的信道。

为了兼容 Web 主流应用协议 HTTP ,WeSocket 复用 80 和 443 端口,并使用 HTTP 请求来建立连接(配合 Upgrade 头部)。因此,WebSocket 可以兼容现有的 HTTP代理 和中间件,例如 Nginx 。

URL

和 HTTP 协议一样,WebSocket 服务器地址也用 URL 表示,只是协议部分为 ws 或 wss 。例如:

复制
# ws代表WebSocket协议,端口为80 ws://api.fasionchan.com/chat # wss代表WebSocket安全协议,与https类似,端口为443 wss://api.fasionchan.com/chat1.2.3.4.5.

连接建立

客户端先通过 TCP 协议连到服务器,然后通过 TCP 连接向服务器发送 HTTP 请求。请注意,HTTP 请求头中要带 Upgrade 头部,告诉服务器将连接升级到 WebSocket 协议:

复制
GET /chat HTTP/1.1 Host: localhost:8080 User-Agent: Go-http-client/1.1 Connection: Upgrade Sec-WebSocket-Key: bLPIf/xpAnrtCKuifPKTUg== Sec-WebSocket-Version: 13 Upgrade: websocket1.2.3.4.5.6.7.

服务器接到请求后,检查 Upgrade 头部,发现客户端想将连接协议升级到 WebSocket 。如果应用服务器支持 WebSocket ,它便回复 101 状态码,表示同意切换协议:

复制
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: lShvB7NL9TbGxezz+KUd5ee6jhA=1.2.3.4.

图片

HTTP 请求和响应交互完毕后,通信双方就可以在 TCP 连接上互相发送 WebSocket 报文了。

数据帧

连接建好后,通信双方就可以用 WebSocket 协议来发送数据了。WebSocket 将数据组织成一系列帧( frame )来传输,一条应用层消息可以封装成一个或多个数据帧。数据帧报文结构如下所示:

图片

标志位 ,占 4每个标识占一位;

a.FIN

b.RSV1 、RSV2 和 RSV3

a.0 这是前面数据帧的续帧(一个消息封装成多个帧时);

b.1表示这是一个文本帧;

c.2 表示这是一个二进制( binary )帧;

d3~7 保留,未来可以分配给新的非控制( non-control )帧;

e.8 表示这是一个连接关闭( close )帧;

f.9 表示这是一个 ping 帧;

g.10 表示这是一个 pong 帧;

h.11~15 保留,未来可以分配给新的控制( control )帧;

MASK 位,表示 承载数据( payload data )是否做掩码处理,1 表示掩码处理,0 表示不做掩码处理(客户端发的帧必须做掩码处理,主要出于避免网络中间件混淆和安全上的考虑);数据长度( payload len ),占 7 位,用来表示数据负载的长度(以字节为单位);

a.该字段小于 126 时,该字段直接表示数据长度,其后的扩展字段为空( 0 字节),可表示 0~125 字节的数据;

b.当该字段等于 126 时,数据长度由其后的扩展字段表示,这是扩展字段为 2 字节,可表示长度为 126~65535 字节的数据;

c.

扩展数据长度( extended payload len ),占用 0 、2 或 8 字节,由前一个字段决定;掩码Key( masking key ),数据帧开启掩码处理时( MASK=1 )才有,占用  4 个字节,用于掩码计算;承载数据( payload data ),即数据帧承载的应用层数据;

数据长度字段比较复杂,需要分三种情况讨论,分别举个例子帮助理解:

图片

注意到,为了简化报文,我们假设 MASK=0 ,未启动掩码处理。

WebSocket 帧结构看似复杂,但无非还是先分成 头部 和 数据 两大部分,其中头部保存 数据类型(操作码)和 数据长度 ,而操作码又分成控制和非控制两种。

控制帧则继续分为 close 、ping 和 pong 三种:close 用于关闭连接;ping 和 pong 用于检测连接状态,检测方发 ping ,被检测方回复 pong 。这样当应用暂时没有数据要发送时,ping/pong 可让连接保持活跃。当连接断开时,也能及时检测到。

而非控制帧则分为 text 和 binary 两种,上层应用使用文本协议,则选 text ;使用二进制协议,则选 binary 。

总结

WebSocket 兼容 HTTP 协议,借助 HTTP 请求建立连接;WebSocket 通信分为两个阶段:连接建立阶段:使用 HTTP数据通信阶段:使用 WebSocketWebSocket 通信报文为 帧 ,一个帧由 头部 和 数据 两部分组成;WebSocket 帧头部保存 操作码 和 数据长度 等字段;根据操作码不同,WebSocket 帧可以分成 控制帧 和 非控制帧 两类;WebSocket 控制帧分为 close 、ping 和 pong 三种;ping / pong 控制帧用于连接保活和状态检测;close 控制帧用于关闭连接;WebSocket 非控制帧分为 文本帧 和 二进制帧 两种;

THE END
本站服务器由亿华云赞助提供-企业级高防云服务器