WebSocket 实现原理

栏目: 编程语言 · IOS · 发布时间: 6年前

内容简介:之前我们将 CocoaAsyncSocket 作为底层实现,在其上面封装了一套 Socket 通信机制以及业务接口,最近我们开始研究 WebSocket ,并用来替换掉原先的 CocoaAsyncSocket ,简单来说一下两者的关系,WebSocket 和 Socket 虽然名称上很像,但两者是完全不同的东西...

背景

之前我们将 CocoaAsyncSocket 作为底层实现,在其上面封装了一套 Socket 通信机制以及业务接口,最近我们开始研究 WebSocket ,并用来替换掉原先的 CocoaAsyncSocket ,简单来说一下两者的关系,WebSocket 和 Socket 虽然名称上很像,但两者是完全不同的东西, WebSocket 是建立在 TCP/IP 协议之上,属于应用层的协议,而 Socket 是在应用层和传输层中的一个抽象层,它是将 TCP/IP 层的复杂操作抽象成几个简单的接口来提供给应用层调用。为什么要做这次替换呢?原因是我们服务端在做改造,同时网页版 IM 已经使用了 WebSocket ,客户端也采用的话对于服务端来说维护一套代码会更好更方便,而且 WebSocket 在体积、实时性和扩展上都具有一定的优势。

WebSocket 最新的协议是 13 RFC 6455 ,要理解 WebSocket 的实现,一定要去理解它的协议!~

前言

WebSocket 的实现分为握手,数据发送/读取,关闭连接。

这里首先放上一张我们组 @省长 (推荐大家去读一读省长的博客,干货很多????)整理出来的流程图,方便大家去理解:

WebSocket 实现原理

握手

握手要从请求头去理解。

WebSocket 首先发起一个 HTTP 请求,在请求头加上 Upgrade 字段,该字段用于改变 HTTP 协议版本或者是换用其他协议,这里我们把 Upgrade 的值设为 websocket ,将它升级为 WebSocket 协议。

同时要注意 Sec-WebSocket-Key 字段,它由客户端生成并发给服务端,用于证明服务端接收到的是一个可受信的连接握手,可以帮助服务端排除自身接收到的由非 WebSocket 客户端发起的连接,该值是一串随机经过 base64 编码的字符串。

我们可以简化请求头,将请求以字符串方式发送出去,当然别忘了最后的两个空行作为包结束:

收到请求后,服务端也会做一次响应:

里面重要的是 Sec-WebSocket-Accept ,服务端通过从客户端请求头中读取 Sec-WebSocket-Key 与一串全局唯一的标识字符串(俗称魔串)“258EAFA5-E914-47DA- 95CA-C5AB0DC85B11”做拼接,生成长度为160位的 SHA-1 字符串,然后进行 base64 编码,作为 Sec-WebSocket-Accept 的值回传给客户端。

处理握手 HTTP 响应解析的时候,可以用 nodejs 的 http-paser ,解析方式也比较简单,就是对头信息的逐字读取再处理,具体处理你可以看一下它的状态机实现。解析完成后你需要对其内容进行解析,看返回是否正确,同时去管理你的握手状态。

数据发送/读取

数据的处理就要拿这个帧协议图来说明了:

首先我们来看看数字的含义,数字表示位,0-7表示有8位,等于1个字节。

所以如果要组装一个帧数据可以这样子:

ok,了解了帧数据的样子,我们反过来去理解值对应的帧字段。

首先0x81是什么,这个是十六进制数据,转换成二进制就是1000 0001, 是一个字节的长度,也就是这一段里面每一位的值:

  • FIN 表示该帧是不是消息的最后一帧,1表示结束,0表示还有下一帧。
  • RSV1, RSV2, RSV3 必须为0,除非扩展协商定义了一个非0的值,如果没有定义非0值,且收到了非0的 RSV ,那么 WebSocket 的连接会失效。
  • opcode 用来描述 Payload data 的定义,如果收到了一个未知的 opcode ,同样会使 WebSocket 连接失效,协议定义了以下值:
    • %x0 表示连续的帧
    • %x1 表示 text 帧
    • %x2 表示二进制帧
    • %x3-7 预留给非控制帧
    • %x8 表示关闭连接帧
    • %x9 表示 ping
    • %xA 表示 pong
    • %xB-F 预留给控制帧

0xff 作用就是取出需要的二进制值。

下面再来看126,126则表示的是 Payload len ,也就是 Payload 的长度:

  • MASK 表示Playload data 是否要加掩码,如果设成1,则需要赋值 Masking-key 。所有从客户端发到服务端的帧都要加掩码
  • Playload len 表示 Payload 的长度,这里分为三种情况
    • 长度小于126,则只需要7位
    • 长度是126,则需要额外2个字节的大小,也就是 Extended payload length
    • 长度是127,则需要额外8个字节的大小,也就是 Extended payload length + Extended payload length continued ,Extended payload length 是2个字节,Extended payload length continued 是6个字节
  • Playload len 则表示 Extension data 与 Application data 的和

而数据的发送和读取就是对帧的封装和解析。

数据发送:

数据解析:

关闭连接

关闭连接分为两种:服务端发起关闭和客户端主动关闭。

服务端跟客户端的处理基本一致,以服务端为例:

服务端发起关闭的时候,会客户端发送一个关闭帧,客户端在接收到帧的时候通过解析出帧的opcode来判断是否是关闭帧,然后同样向服务端再发送一个关闭帧作为回应。

总结

对WebSocket的学习主要是对协议的理解,理解了协议,上面复杂的代码自然而然就会明白~

后记

对于I/O操作的原理,推荐大家可以看看这个:epoll 或者 kqueue 的原理是什么?


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

人类2.0

人类2.0

皮埃罗∙斯加鲁菲(Piero Scaruffi) / 闫景立、牛金霞 / 中信出版集团股份有限公司 / 2017-2-1 / CNY 68.00

《人类2.0:在硅谷探索科技未来》从在众多新技术中选择了他认为最有潜力塑造科技乃至人类未来的新技术进行详述,其中涉及大数据、物联网、人工智能、纳米科技、虚拟现实、生物技术、社交媒体、区块链、太空探索和3D打印。皮埃罗用一名硅谷工程师的严谨和一名历史文化学者的哲学视角,不仅在书中勾勒出这些新技术的未来演变方向和面貌,还对它们对社会和人性的影响进行了深入思考。 为了补充和佐证其观点,《人类2.0......一起来看看 《人类2.0》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换