14

WebSocket

引用

RFC中可以 看出 websocket 是一个客户端与服务端可以进行相互数据通信的一中协议,而且最主要的是建立在一个TCP连接上的,所以多个TCP连接时节省了socket的建立与断开的时间。这是一个好处,但是问题是,如果这个时候去到了其他页面,那么这个websocket就会断掉。解决的方法是将页面做成single page。

握手包

The opening handshake is intended to be compatible with HTTP-based

server-side software and intermediaries, so that a single port can be

used by both HTTP clients talking to that server and WebSocket

clients talking to that server.

客户端的握手包:
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协议并没有什么本质上的不同,如果说这两者有什么不同的话,那就是WebSocket其实属于HTTP协议的一种并且由各大浏览器厂商支持,在浏览器中可以直接查看服务器和客户端之间通信的内容。请求头中的第二个说明是请求的参数,如果服务端想利用各种不同的参数来做操作的话,加上参数还是不错的,但是如果仅仅是想要与客户端进行通信,那么,也就仅仅指定域名(IP)和端口号就可以了。

服务器端的握手包:
HTTP/1.1 101 Switching Protocols

Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

在这里的Sec-WebSocket-Accept 其实是先在客户端请求的握手包中将Sec-WebSocket-Key提取出来,然后将该字符串与魔法字符串与魔法字符串拼接,再进行SHA-1加密,然后再转化为十六进制的格式包发送给客户端。这样子的一个握手包就已经建立好了。

数据分片

利用websocket进行数据传输的时候呢, 是要遵守数据分片协议,HERE。这个协议的长度有32位,示意图如下:

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-------+-+-------------+-------------------------------+
     |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
     |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
     |N|V|V|V|       |S|             |   (if payload len==126/127)   |
     | |1|2|3|       |K|             |                               |
     +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
     |     Extended payload length continued, if payload len == 127  |
     + - - - - - - - - - - - - - - - +-------------------------------+
     |                               |Masking-key, if MASK set to 1  |
     +-------------------------------+-------------------------------+
     | Masking-key (continued)       |          Payload Data         |
     +-------------------------------- - - - - - - - - - - - - - - - +
     :                     Payload Data continued ...                :
     + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
     |                     Payload Data continued ...                |
     +---------------------------------------------------------------+
位说明:
  • FIN(1 bit):当前的信息是否是分片包的最后一个包。
  • RSV1, RSV2, RSV3 (1 bit / per ) : 必须是0,除非为非0值被协商定义。
  • Opcode(4 bit) : 定义负载信息的解释执行。如果有未知的 操作码那么接收端将会抛出_Fail the WebSocket Connection_
  • Mask(1 bit): 定义负载数据是否被掩码。
  • Payload length(7 bits, 7+16 bits, or 7+64 bits) : 负载数据的长度。

在这里插一个当时遇到的bug,就是我用php做后台对数据进行mask,结果在浏览器端会偶然出现decode frame error as utf-8大概是这样的错误,初期找到了问题在于后台mask的问题,但是直到第二天将php的mask的问题找到。应该将opcode改成‭1000 0010‬,这样就可以了。当然如果在浏览器端接收到的数据,可能会是二进制格式。可用类似于var a = new FileReader()这样的函数来处理。

一般来说,mask为是需要被设置为1的,some references ,所以在收到数据的时候,需要对数据进行特殊的处理。

一点说明

websocket只是一种协议,可以使客户端和服务端地位尽可能平等处理的一种协议,对具体的协议内容,参考协议手册或者看看别人的处理,然后在考虑自己的处理方式就好了。

python序