Websocket协议数据帧传输和关闭链接

以前总结了关于Websocket协议的握手链接方式等其余细节,如今对socket链接创建后的数据帧传输和关闭细节总结。web

1、数据帧格式

数据传输使用的是一系列数据帧,出于安全考虑和避免网络截获,客户端发送的数据帧必须进行掩码处理后才能发送到服务器,不管是否是在TLS安全协议上都要进行掩码处理。服务器若是没有收到掩码处理的数据帧时应该关闭链接,发送一个1002的状态码。服务器不能将发送到客户端的数据进行掩码处理,若是客户端收到掩码处理的数据帧必须关闭链接。算法

基本的数据帧为一个opcode、一个payload长度和发送的应用数据,根据ABNF的定义,详细信息以下图缓存

这里使用的是数据存储的位(bit),当进行加密的时候,最终要的一位就是最左边的第一个。安全

 

  • FIN :1bit ,表示是消息的最后一帧,若是消息只有一帧那么第一帧也就是最后一帧。
  • RSV1,RSV2,RSV3:每一个1bit,必须是0,除非扩展定义为非零。若是接受到的是非零值可是扩展没有定义,则须要关闭链接。
  • Opcode:4bit,解释Payload数据,规定有如下不一样的状态,若是是未知的,接收方必须立刻关闭链接。状态以下:0x0(附加数据帧)    0x1(文本数据帧)   0x2(二进制数据帧)    0x3-7(保留为以后非控制帧使用)  0xB-F(保留为后面的控制帧使用)    0x8(关闭链接帧)  0x9(ping)  0xA(pong)
  •    Mask:1bit,掩码,定义payload数据是否进行了掩码处理,若是是1表示进行了掩码处理。
    Masking-key域的数据便是掩码密钥,用于解码PayloadData。客户端发出的数据帧须要进行掩码处理,因此此位是1。
  • Payload length:7位,7 + 16位,7+64位,payload数据的长度,若是是0-125,就是真实的payload长度,若是是126,那么接着后面的2个字节对应的16位无符号整数就是payload数据长度;若是是127,那么接着后面的8个字节对应的64位无符号整数就是payload数据的长度。
  • Masking-key:0到4字节,若是MASK位设为1则有4个字节的掩码解密密钥,不然就没有。
  • Payload data:任意长度数据。包含有扩展定义数据和应用数据,若是没有定义扩展则没有此项,仅含有应用数据。

2、客户端到服务器端掩码处理

前面说过客户端发送到服务器端的数据必须进行掩码处理,掩码的密钥是一个32位的随机值,客户端随机选取密钥必须是不可猜想的。这个掩码处理后并不影响Payload数据的长度。服务器收到掩码处理后的数据后,解码须要使用以下的算法进行:
j = i mod 4(i 是传输数据中的十进制的索引下标)
转换后的数据 d = original  ^ mask[j]
也就是将Payload原始数据的每一个字符的顺序下标与4去摸,而后将此原始数据字符与掩码的前面去摸后的相应位置的字符进行异或操做便可。这个算法对于加密和解密的操做都是同样的。

3、消息分片

分片目的是发送长度未知的消息。若是不分片发送,即一帧,就须要缓存整个消息,计算其长度,构建frame并发送;使用分片的话,可以使用一个大小合适的buffer,用消息内容填充buffer,填满即发送出去。服务器

分片规则:websocket

1.一个未分片的消息只有一帧(FIN为1,opcode非0)网络

2.一个分片的消息由起始帧(FIN为0,opcode非0),若干(0个或多个)帧(FIN为0,opcode为0),结束帧(FIN为1,opcode为0)。并发

3.控制帧能够出如今分片消息中间,但控制帧自己不容许分片。socket

4.分片消息必须按次序逐帧发送。加密

5.若是未协商扩展的状况下,两个分片消息的帧之间不容许交错。

6.可以处理存在于分片消息帧之间的控制帧

7.发送端为非控制消息构建长度任意的分片

8.client和server兼容接收分片消息与非分片消息

9.控制帧不容许分片,中间媒介不容许改变分片结构(即为控制帧分片)

10.若是使用保留位,中间媒介不知道其值表示的含义,那么中间媒介不容许改变消息的分片结构

11.若是协商扩展,中间媒介不知道,那么中间媒介不容许改变消息的分片结构,一样地,若是中间媒介不了解一个链接的握手信息,也不容许改变该链接的消息的分片结构

12.因为上述规则,一个消息的全部分片是同一数据类型(由第一个分片的opcode定义)的数据。由于控制帧不容许分片,因此一个消息的全部分片的数据类型是文本、二进制、opcode保留类型中的一种。

须要注意的是,若是控制帧不容许夹杂在一个消息的分片之间,延迟会较大,好比说当前正在传输一个较大的消息,此时的ping必须等待消息传输完成,才能发送出去,会致使较大的延迟。为了不相似问题,须要容许控制帧夹杂在消息分片之间。

 

数据帧示例:

未掩码处理的文本单数据帧:  0x81 0x05 0x48 0x65 0x6c 0x6c 0x6f (contains "Hello")

掩码处理的文本单数据帧:      0x81 0x85 0x37 0xfa 0x21 0x3d 0x7f 0x9f 0x4d 0x51 0x58

分片未掩码处理的文本消息:   0x01 0x03 0x48 0x65 0x6c (contains "Hel")

 0x80 0x02 0x6c 0x6f (contains "lo")

未掩码处理的Ping请求和掩码处理的响应: 

0x89 0x05 0x48 0x65 0x6c 0x6c 0x6f (contains a body of "Hello", but the contents of the body are arbitrary) 

0x8a 0x85 0x37 0xfa 0x21 0x3d 0x7f 0x9f 0x4d 0x51 0x58 (contains a body of "Hello", matching the body of the ping)

64K的二进制数据:0x82 0x7F 0x0000000000010000 [65536 bytes of binary data]

 

4、发送和接收数据

一、发送

 

  • 端点必须确保WebSocket链接处于OPEN状态。若是在任什么时候刻WebSocket链接的状态改变了,端点必须终止如下步骤。
  • 端点必须封装/data/到一个WebSocket帧。若是要发送的数据太大或若是在端点想要开始发生数据时数据做为一个总体不可用,端点能够交替地封装数据到一系列的帧中。
  • 第一个包含数据的帧的操做码(帧-opcode)必须设置为适当的值用于接收者解释数据是文本仍是二进制数据。
  • 包含数据的最后帧的FIN位(帧-fin)必须设置位1。
  • 若是数据正由客户端发送,帧被掩码。
  • 若是任何扩展已经协商用于WebSocket链接,额外的考虑能够按照这些扩展定义来应用。
  • 已成形的帧必须在底层网络链接之上传输。

 

二、接收

为了接收WebSocket数据,端点监听底层网络链接。传入数据必须解析为WebSocket帧。当接收到一个数据帧时,端点必须注意由操做码(帧-opcode)定义的数据的/type/。这个帧的“应用数据”被定义为消息的/data/。若是帧由一个未分片的消息组成,这是说已经接收到一个WebSocket消息,其类型为/type/且数据为/data/。若是帧是一个分片消息的一部分,随后数据帧的“应用数据”链接在一块儿造成/data/。当接收到由FIN位(帧-fin)指示的最后的片断时,这是说已经接收到一个WebSocket消息,其数据为/data/(由连续片断的“应用数据”组成)且类型为/type/(分配消息的第一个帧指出)。随后的数据帧必须被解释为属于一个新的WebSocket消息。

扩展能够改变数据如何读的语义,尤为包括什么组成一个消息的边界。扩展,除了在负载中的“应用数据”以前添加“扩展数据”外,也能够修改“应用数据”(例如压缩它)。服务器必须为从客户端接收到的数据帧移除掩码。

 

5、Websocket关闭

通讯的两端中任意一端关闭均可以关闭socket链接,关闭时应该清楚全部的TCP链接资源和TLS回话的资源,同时要丢弃全部的可能接收的字节数据。首先关闭的一方通常都应该是服务器端,而后处于TIME_WAIT状态。

为了使用一个状态码关闭websocket,一端必须发送一个关闭的控制帧,当两端都发送了关闭数据帧时,双方都要关闭全部的链接资源。控制帧为一个“状态码”和一个“缘由说明”,当关闭以后,双方处于CLOSED状态。

相关文章
相关标签/搜索