Java后端那些事码农的世界@IT·互联网

websocket协议简析

2017-08-04  本文已影响251人  假文艺的真码农

websocket协议是基于tcp的网络协议,实现了浏览器与客户端的全双工通信,与http协议不同的是,它允许服务器主动推送消息给客户端。这样便可以取代原来低效的轮询。

背景

在websocket出现之前,客户端获取服务器消息,需要通过不停的轮询。有如下缺陷:

1)服务器被迫为每个客户端使用许多不同的底层TCP连接:一个用于向客户端发送信息,其它用于接收每个传入消息。

2)http协议有额外的开销,每个消息都有HTTP头。

3)客户端需要通过映射来维护传出连接和传人连接用以追踪响应。

Websocket协议的出现正是弥补了上述缺陷,实现全双工通信,允许服务器主动推送消息给客户端。

协议分析

websocket协议分为两部分,一是握手建立连接;二是数据传输。

建立连接;

websocket的连接建立是基于http协议的。

请求报文示例:

GET /chat HTTP/1.1

Host: server.example.com

Upgrade: websocket

Connection:Upgrade

Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==

Origin: http://example.com

Sec-WebSocket-Protocol: chat, superchat

Sec-WebSocket-Version: 13

响应报文示例:

HTTP/1.1 101 Switching Protocols

Upgrade: websocket

Connection: Upgrade

Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

Sec-WebSocket-Protocol: chat

下面来分析一下上述报文:

WebSocket借用http请求进行握手,相比正常的http请求,多了一些内容。其中,

HTTP/1.1 101表示websocket连接已成功建立,其他任何code表示连接建立失败。

Upgrade: websocket

Connection: Upgrade

表示希望将http协议升级到Websocket协议。

Sec-WebSocket-Key是浏览器随机生成的base64 encode的值,用来询问服务器是否是支持WebSocket。

服务器返回

Upgrade: websocket

Connection: Upgrade

告诉浏览器即将升级的是Websocket协议

Sec-WebSocket-Accept是将请求包"Sec-WebSocket-Key"的值,与"258EAFA5-E914-47DA-95CA-C5AB0DC85B11″这个字符串进行拼接,然后对拼接后的字符串进行sha-1运算,再进行base64编码得到的。用来说明自己是WebSocket助理服务器。

Sec-WebSocket-Version是WebSocket协议版本号。

若请求报文中,Sec-WebSocket-Version: 25,服务端可能的响应会是

HTTP/1.1 400 Bad Request ... Sec-WebSocket-Version: 13, 8, 7

此时客户端将会重新进行握手,并将版本修改为 Sec-WebSocket-Version: 13

数据传输:

websocket协议中数据是通过一系列的帧来传输。出于安全性考虑,所有客户端发往服务器的数据帧需要掩码,若服务器收到未掩码的数据帧将会主动断开连接;所有服务器发往客户端的数据帧不能掩码,若客户端收到掩码的数据帧将会主断开连接。

数据帧的定义:

FIN: 1 bit --是否是消息的最后一个数据帧。一个消息可以通过一个或多个数据帧发送,第一个帧也可能是最后一个帧。

RSV1, RSV2, RSV3: 1 bit each-- 保留字段,如果有自定义的扩展数据时使用。当没有扩展数据时,若保留字段非0,则会导致连接失败。

Opcode: 4 bits--说明数据的类型。eg:%x1表示文本帧;%x2表示二进制帧;%x8表示关闭连接帧;%x9表示ping帧;%xA 表示 pong帧。从此可以看出,目前websocket支持的传输类型包含文本,二进制和ping/pong。

Mask: 1 bit--是否掩码。(规则上文已述)

Payload length: 7 bits, 7+16 bits, or 7+64 bits--数据长度

Masking-key: 0 or 4 bytes--掩码的key(若mask is 1)

Payload data: (x+y) bytes-- 数据,包含扩展数据和应用数据。

Extension data: x bytes--私有定制协议。

Application data: y bytes--传输的数据

示例

o 非掩码的Hello: * 0x81 0x05 0x48 0x65 0x6c 0x6c 0x6f

注解:

0x81 -->10000001

-->Fin=1(最后帧);RSV=000;Opcode=0001(文本帧)

0x05 -->00000101

--> mask=0(不掩码);Payload length=0000101(5个字符)

0x48 0x65 0x6c 0x6c 0x6f -->Hello

o掩码的Hello: * 0x81 0x85 0x37 0xfa 0x21 0x3d 0x7f 0x9f 0x4d 0x51 0x58 (contains "Hello")

o多帧不掩码的Hello * 0x01 0x03 0x48 0x65 0x6c (contains "Hel")

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

256字节二进制非掩码数据* 0x82 0x7E 0x0100 [256 bytes of binary data]

64KiB单帧二进制非掩码数据

0x82 0x7F 0x0000000000010000 [65536 bytes of binary data]

数据发送规则:

1)保证连接状态为open。

2)不知大小或太大的数据,会分为一系列的帧来发送。

3)数据发送帧中必须标明数据类型

4)最后一个数据帧必须将Fin设置为1

5)客户端发送的数据必须掩码

6)扩展数据必须有定义

7)数据必须通过下行连接发送。

上一篇下一篇

猜你喜欢

热点阅读