小菜学网络之WebSocket协议
小菜学网络之WebSocket协议
WebSocket协议是一种在单个TCP连接上进行全双工通信的协议,它允许服务器主动向客户端推送数据,解决了HTTP协议只能由客户端发起请求的局限性。WebSocket协议广泛应用于实时通信场景,如在线聊天、实时数据更新等。本文将详细介绍WebSocket协议的基本概念、工作原理和数据帧结构。
WebSocket协议简介
Web应用通常采用HTTP协议进行通信:客户端向服务器发送HTTP请求,服务器对请求进行处理后,向客户端回复HTTP响应。换句话说,HTTP协议只能由客户端主动发起请求,服务器被动进行响应。
然而,不少应用场景要求服务器主动向客户端进行推送,这时HTTP协议就显得捉襟见肘了。例如,为了实现Web聊天室功能,当新消息到达时,服务器必须向客户端推送通知。如果只使用HTTP协议,就必须在客户端做轮询。
轮询存在一个致命缺陷:性能较差。如果轮询频率很高,服务器要消耗很多资源;但如果控制轮询频率,应用消息通知的实时性又会大打折扣。
显然,服务器主动向客户端推送数据是一个非常常见的应用场景,最好能从网络协议层面进行支持。为此,计算机网络先驱们设计了WebSocket协议。
WebSocket协议,顾名思义为Web应用引入了套接字(socket)通信能力。WebSocket是一种应用层协议,以TCP为底层传输协议,为通信双方提供了一个全双工的信道。
为了兼容Web主流应用协议HTTP,WebSocket复用80和443端口,并使用HTTP请求来建立连接(配合Upgrade头部)。因此,WebSocket可以兼容现有的HTTP代理和中间件,例如Nginx。
WebSocket协议的关键概念
URL
和HTTP协议一样,WebSocket服务器地址也用URL表示,只是协议部分为ws
或wss
。例如:
连接建立
客户端先通过TCP协议连到服务器,然后通过TCP连接向服务器发送HTTP请求。请注意,HTTP请求头中要带Upgrade头部,告诉服务器将连接升级到WebSocket协议:
服务器接到请求后,检查Upgrade头部,发现客户端想将连接协议升级到WebSocket。如果应用服务器支持WebSocket,它便回复101状态码,表示同意切换协议:
HTTP请求和响应交互完毕后,通信双方就可以在TCP连接上互相发送WebSocket报文了。
数据帧
连接建好后,通信双方就可以用WebSocket协议来发送数据了。WebSocket将数据组织成一系列帧(frame)来传输,一条应用层消息可以封装成一个或多个数据帧。数据帧报文结构如下所示:
- 标志位,占4位,每个标识占一位;
- FIN:表示是否是最后一个数据帧;
- RSV1、RSV2和RSV3:保留位,目前未使用;
- Opcode:操作码,表示数据帧的类型;
- 0:这是前面数据帧的续帧(一个消息封装成多个帧时);
- 1:表示这是一个文本帧;
- 2:表示这是一个二进制(binary)帧;
- 3~7:保留,未来可以分配给新的非控制(non-control)帧;
- 8:表示这是一个连接关闭(close)帧;
- 9:表示这是一个ping帧;
- 10:表示这是一个pong帧;
- 11~15:保留,未来可以分配给新的控制(control)帧;
- MASK位:表示承载数据(payload data)是否做掩码处理,1表示掩码处理,0表示不做掩码处理(客户端发的帧必须做掩码处理,主要出于避免网络中间件混淆和安全上的考虑);
- 数据长度(payload len):占7位,用来表示数据负载的长度(以字节为单位);
- 该字段小于126时,该字段直接表示数据长度,其后的扩展字段为空(0字节),可表示0~125字节的数据;
- 当该字段等于126时,数据长度由其后的扩展字段表示,这是扩展字段为2字节,可表示长度为126~65535字节的数据;
- 扩展数据长度(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
- 数据通信阶段:使用WebSocket
WebSocket通信报文为帧,一个帧由头部和数据两部分组成;
WebSocket帧头部保存操作码和数据长度等字段;
根据操作码不同,WebSocket帧可以分成控制帧和非控制帧两类;
WebSocket控制帧分为close、ping和pong三种;
ping/pong控制帧用于连接保活和状态检测;
close控制帧用于关闭连接;
WebSocket非控制帧分为文本帧和二进制帧两种;