小菜学网络之WebSocket协议

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

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/chat

连接建立

客户端先通过 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: websocket

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

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

图片图片

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 。

总结

  1. WebSocket 兼容 HTTP 协议,借助 HTTP 请求建立连接;
  2. WebSocket 通信分为两个阶段:
  • 连接建立阶段:使用 HTTP
  • 数据通信阶段:使用 WebSocket
  1. WebSocket 通信报文为 帧 ,一个帧由 头部 和 数据 两部分组成;
  2. WebSocket 帧头部保存 操作码 和 数据长度 等字段;
  3. 根据操作码不同,WebSocket 帧可以分成 控制帧 和 非控制帧 两类;
  4. WebSocket 控制帧分为 close 、ping 和 pong 三种;
  • ping / pong 控制帧用于连接保活和状态检测;
  • close 控制帧用于关闭连接;
  1. WebSocket 非控制帧分为 文本帧 和 二进制帧 两种;
责任编辑:武晓燕 来源: 小菜学编程
相关推荐

2021-07-06 21:29:16

TCPIP协议栈

2021-05-18 22:11:27

DNS记录类型

2021-04-13 22:17:19

网络域名系统

2021-05-11 21:57:17

DNS报文格式

2021-04-21 20:21:07

DNS服务器网络

2015-04-01 10:22:06

WebSocket网络协议WebSocket协议

2014-06-13 13:47:31

UDP

2022-03-18 10:43:12

WebSocketHTML5TCP 连接

2023-12-29 20:25:51

2020-04-23 09:11:09

网络协议网络设备网络

2019-07-08 12:31:32

RTSP网络协议流媒体

2010-06-12 15:54:09

TCP IP协议

2011-08-24 09:56:13

网络协议BOOTP协议TFTP协议

2022-10-08 00:00:00

websocket协议HTTP

2020-07-28 08:38:10

TCPUDP协议

2014-06-16 09:22:59

2023-12-17 14:43:17

2019-04-29 10:26:49

TCP网络协议网络通信

2014-06-16 09:33:22

ICMPPingTraceroute

2019-03-29 10:31:53

点赞
收藏

51CTO技术栈公众号