详解websocket与http与TCP/IP的三角恋

关于websocket,从它成为标准后就一直困扰我很久,它和http,tcp究竟有啥关系?套接字不都是tcp或者udp吗?它能和tcp服务器直接通讯吗?它要包含在http的请求里发送吗?它工作在计算机网络的哪一层?今天终于有机会细细地捋一下他们的关系了;

一、关于TCP/IP

学过计算机网络的人肯定都知道,tcp是传输层协议,当一个应用程序监听某个tcp端口后,它实际上就建立了一个套接字,且可以通过该套接字发送接收消息,没学过计算机网络的小伙伴可以简单地理解为:套接字 = ip + 端口号

二、关于http协议

http协议是一个工作在应用层的协议,它是建立在tcp之上的一个协议;

三、关于websocket

我当时也被官方说的什么web支持套接字了啥啥的给弄晕了,最后仔仔细细地读了一下官档,发现这个websocket并不是我们寻常意义上的基于tcp或者udp协议的套接字,而是一个基于tcp的应用层协议,和http协议工作在计算机网络的同一层;

websocket其实就是,在tcp的基础上增加了一个协议,这个协议和tcp协议很像,也需要握手,挥手,发送大数据也要分包,也是按照位进行标识的,这里再强调下,它并不是套接字!并不是socket!socket工作在传输层,它工作应用层!

1. webscoket的数据帧格式,如下

1. FIN

1个bit位,用来标记当前数据帧是不是最后一个数据帧,因为一个消息可能会分成多个数据帧来传递,当然,如果只需要一个数据帧的话,第一个数据帧也就是最后一个。

2. RSV1, RSV2, RSV3

这三个,各占用一个bit位,根据RFC的介绍,这三个bit位是用做扩展用途,没有这个需求的话设置位0。

3. Opcode

故名思议,操作码,占用4个bit位,也就是一个16进制数,它用来描述要传递的数据是什么或者用来干嘛的,只能为下面这些值:

0x0 denotes a continuation frame 标示当前数据帧为分片的数据帧,也就是当一个消息需要分成多个数据帧来传送的时候,需要将opcode设置位0x0。

0x1 denotes a text frame 标示当前数据帧传递的内容是文本

0x2 denotes a binary frame 标示当前数据帧传递的是二进制内容,不要转换成字符串

0x8 denotes a connection close 标示请求关闭连接

0x9 denotes a ping 标示Ping请求

0xA denotes a pong 标示Pong数据包,当收到Ping请求时自动给回一个Pong

目前协议中就规定了这么多,0x3~0x7以及0xB~0xF都是预留作为其它用途的。

4. MASK

占用一个bit位,标示数据有没有使用掩码,RFC中有说明,服务端发送给客户端的数据帧不能使用掩码,客户端发送给服务端的数据帧必须使用掩码。

如果一个帧的数据使用了掩码,那么在Maksing-key部分必须是一个32个bit位的掩码,用来给服务端解码数据。

5. Payload len

数据的长度,默认位7个bit位。

如果数据的长度小于125个字节(注意:是字节)则用默认的7个bit来标示数据的长度。

如果数据的长度为126个字节,则用后面相邻的2个字节来保存一个16bit位的无符号整数作为数据的长度。

如果数据的长度大于126个字节,则用后面相邻的8个字节来保存一个64bit位的无符号整数作为数据的长度。

6. Masking-key

数据掩码,如果MASK设置位0,则该部分可以省略,如果MASK设置位1,怎Masking-key位一个32位的掩码。用来解码客户端发送给服务端的数据帧。

7. Payload data

该部分,也是最后一部分,是帧真正要发送的数据,可以是任意长度。

2.websocket握手

建立TCP连接之后,开始建立WebSocket连接,上文说过WebSocket连接只需一次成功握手即可建立。握手过程如下图所示(图片来自互联网):

1)首先客户端会发送一个握手包。这里就体现出了WebSocket与Http协议的联系,握手包的报文格式必须符合HTTP报文格式的规范。其中:

  • 方法必须位GET方法
  • HTTP版本不能低于1.1
  • 必须包含Upgrade头部,值必须为websocket
  • 必须包含Sec-WebSocket-Key头部,值是一个Base64编码的16字节随机字符串。
  • 必须包含Sec-WebSocket-Version头部,值必须为13
  • 其他可选首部可以参考:https://tools.ietf.org/html/rfc6455#section-4.1

2)服务端验证客户端的握手包符合规范之后也会发送一个握手包给客户端。格式如下:

  • 必须包含Connection头部,值必须为Upgrade
  • 必须包含一个Upgrade头部,值必须为websocket
  • 必须包含一个Sec-Websocket-Accept头部,值是根据如下规则计算的:

    • 首先将一个固定的字符串258EAFA5-E914-47DA-95CA-C5AB0DC85B11拼接到Sec-WebSocket-Key对应值的后面。
    • 对拼接后的字符串进行一次SHA-1计算
    • 将计算结果进行Base-64编码

3)客户端收到服务端的握手包之后,验证报文格式时候符合规范,以2)中同样的方式计算Sec-WebSocket-Accept并与服务端握手包里的值进行比对。

其中任何一步不通过则不能建立WebSocket连接。

参考:

https://timefly.cn/learn-websocket-protocol-2/

https://timefly.cn/learn-websocket-protocol-1/

发布了130 篇原创文章 · 获赞 105 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/THMAIL/article/details/103990996