websocket协议的解析与实现(一)

来源:互联网 发布:初一英语点读软件 编辑:程序博客网 时间:2024/06/07 05:12

HTTP协议是短连接的,通信模式如图:

如何实现服务器主动向客户端发送数据呢?!websocket协议就是解决这个问题的。

通信过程大致如下:

本文中要有两部分组成

一、建立连接请求过程

二、数据帧格式


一、建立连接请求过程

     在建立连接请求过程中使用的协议是HTTP协议。

1、客户端发送建立连接请求

      使用的是HTTP协议头,服务器端按照HTTP协议正常解析,但这块不同的是服务器程序必须判断是否是websocket请求,其实服务器只需要查看该http协议头中是否包含了websockt等字符串,请求头如下

websockt握手请求协议包含Upgrade: websocket字段,服务器通过该字段就可以知道客户端想要建立websockt连接请求。

2、服务器响应连接请求

服务器从请求协议包中获取Sec-WebSocket-Key字段值,如下图:


然后将该key值与字符串“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”拼接形成新的字符串,如"d359Fdo6omyqfxyYF7Yacw==258EAFA5-E914-47DA-95CA-C5AB0DC85B11";然后服务器对该字符串进行SHA-1加密,之后再进行一次base64加密,将加密之后的结果作为最终的响应key发送给客户端,服务器相依协议头如下:

         其中Sec-WebSocket-Accept:字段填充由请求中的Sec-WebSocket-Key字段值与字符串”258EAFA5-E914-47DA-95CA-C5AB0DC85B11“拼接而成的字符串经过加密之后的字符串组成。


按照以上两步即可建立websocket连接。接下来客户端与服务器就可以互相异步的发送数据了。


二、数据帧格式

连接建立之后,客户端与服务器就可以相互发送数据了,数据包格式如下:


注意:

如果条件不满足,则扩展字节不出现在数据帧中。

列 明

位数

含义

取值

FIN

1 bit

是否是最后一帧数据

1表示后面没数据了

0:表示后面还有数据

RSV

3 bit

保留

 

OPCODE

4 bit

消息类型

0x0表示附加数据帧

0x1表示文本数据帧

0x2表示二进制数据帧

0x3-7暂时无定义,为以后的非控制帧保留

0x8表示连接关闭

0x9表示ping

0xA表示pong

0xB-F暂时无定义,为以后的控制帧保留

 

MASK

1 bit

是否经过掩码处理;

客户端必须对其发送到服务器的所有帧进行掩码处理。

服务器一旦收到无掩码帧,将关闭连接。服务器可能发送一个状态码是1002(表示协议错误)的Close帧。

而服务器发送客户端的数据帧不做掩码处理,一旦客户端发现经过掩码处理的帧,将关闭连接。客户端可能使用状态码1002

1:表示处理过 0:表示没处理过

用于标识PayloadData是否经过掩码处理。如果是1,Masking-key域的数据即是掩码密钥,用于解码PayloadData。客户端发出的数据帧需要进行掩码处理,所以此位是1。

 

Payload length

7 bit

7+16bit

7+64 bit

 

PayloadData

数据长度

Payload长度是ExtensionData长度与ApplicationData长度之和

0-125:则是payload数据的真实长度

126:之后的2个字节的16位无符号正数值表示真是长度

127之后的8个字节形成的64位无符号整型数的值是payload的真实长度

(注意网络字节序)

 

Masking-key

32 bit

掩码

 

data

....

数据

.....................

1、客户端到服务器的数据必须通过掩码处理

2、服务器收到数据包之后需要判断是否有掩码,即MASK是否有效,无效则发送关闭连接数据包,如果掩码位有效,则解掩码来获取真正的数据

3、服务器发送给客户端的数据不需要掩码处理,相对简单

协议示例:

客户端发送给服务器的文本消息”hello”

0x81 0x85 0x37 0xfa 0x21 0x3d 0x7f 0x9f 0x4d 0x51 0x58 (包含 "Hello")

掩码与解掩码过程:

1)、计算j 

= i MOD 4

2)、计算掩码后的数据,解掩码方法相同 transformed-octet-i = original-octet-i XOR masking-key-octet-j

original-octet-i表示原始数据中下标为i的数据,如[0x7f 0x9f 0x4d 0x51 0x58]

masking-key-octet-j 表示四个字节组成的掩码数组中下标为j的掩码值,

[0x37 0xfa 0x21 0x3d ]

transformed-octet-i:表示掩码或解掩码之后的数据

示例解码过程如下:

Unsigned char original-octet[] = {0x7f,0x9f,0x4d,0x51,0x58};

Unsigned char masking-key-octet[] = {0x37,0xfa,0x21,0x3d};

//LENGTH = sizeof(original-octet);

Unsigned char Transformed-octer[LENGTH];

 

0x7f:  i = 0;   =>    j = i % 4 = 0;

Transformed-octer[i] = original-octet[i] XOR masking-key-octet[j];

   = 0x7F XOR 0x37 = 0x48

        0x48 = ‘h’

其他数字掩码或解掩码过程同上


下一篇文章将给出服务器和客户端主要代码,服务器是Linux下用C语言编写的,客户端使用js脚本实现。

0 0
原创粉丝点击