websocket协议

websocket概念

HTML5开始提供的一种浏览器与服务器进行全双工通讯的网络技术,属于应用层协议。它基于TCP传输协议,并复用HTTP的握手通道。

优势

  • 支持双向通道,时时通信
  • 更好的支持二进制数据
  • 较少的控制开销。
    1. 握手,创建链接
    2. 数据交换(数据帧),每次通信不需要携带完整的请求头

创建连接

  • 客户端:请求协议升级

    GET / HTTP/1.1
    Host: localhost:8080
    Origin: http://127.0.0.1:3000
    Connection: Upgrade
    Upgrade: websocket
    Sec-WebSocket-Version: 13
    Sec-WebSocket-Key: w4v7O6xFTi36lq3RNcgctw==
    
    • sec-websocket-key :与服务端返回的sec-websocket-accept匹配,提供基本的防护,防止恶意or无意连接
  • 服务端:响应协议升级

    HTTP/1.1 101 Switching Protocols
    Connection:Upgrade
    Upgrade: websocket
    Sec-WebSocket-Accept: Oy4NRAQ13jhfONC7bP8dTKb4PTU=
    
  • Sec-WebSocket-Accept AS a 是根据客户端请求头的sec-websocket-key AS b 计算出来的

    1. c = b . “258EAFA5-E914-47DA-95CA-C5AB0DC85B11”
    2. a = base64encode( sha1( c ));

数据交换的数据帧格式

  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 ) :
    1. data == 1 数据的最后一帧
    2. date == 0 非最后一帧
  • 3个RSV(3 BIT ) 默认都是0
  • opcode (4 BIT) : 为什么用16进制数,因为一位16进制 0-f 刚好是 0-4Bit 0000-1111
    1. 0x0:表示此帧是一个延续帧,并且不是数据的第一帧
    2. 0x1:数据的第一帧,表示数据是文本格式传输
    3. 0x2:数据的第一帧,表示数据是二进制数据传输
    4. 0x3-0x7:保留自定义
    5. 0x8:表示连接断开
    6. 0x9:ping操作
    7. 0xa:pong操作
    8. 0xb - 0xf :保留自定义
  • MASK(1 BIT)
    1. 客户端 请求 服务端一定 mask 必须 是1,必须对数据进行掩码操作, 否则服务端断开连接。所以会定义一个掩码键(masking-key 4字节),用这个键对数据载荷进行反掩码。所以数据帧的请求头最小 6 字节 前面定义的 1+3+4+1+4*8 =
    2. 服务端 响应 客户端不需要进行掩码操作
  • payload length(7BIT or 7+16 BIT or 7+32 BIT):数据载荷的长度,单位是字节
    1. 假设 payload-ength == x
    2. 0 < x < 126 : x就是数据的长度 7 BIT (1111100 == 125)
    3. x == 126 :那么payload-length数据的后面2个字节(16位无符号整数)是数据的长度范围 2^16-1= 65535(字节)
    4. x == 127:那么payload-length数据的后面4个字节(32位无符号整数)是数据的长度范围 2^32 -1 = 4294967295(字节)
  • masking-key(0 or 4字节)
    1. mask == 0 masking-key == 0(字节)
    2. mask == 1 masking-key == 4(字节)

数据传递

一旦WebSocket客户端、服务端建立连接后,后续的操作都是基于数据帧的传递。

WebSocket根据opcode来区分操作的类型。比如0x8表示断开连接,0x0-0x2表示数据交互。

数据分片

WebSocket的每条消息可能被切分成多个数据帧。当WebSocket的接收方收到一个数据帧时,会根据FIN的值来判断,是否已经收到消息的最后一个数据帧。

FIN=1表示当前数据帧为消息的最后一个数据帧,此时接收方已经收到完整的消息,可以对消息进行处理。FIN=0,则接收方还需要继续监听接收其余的数据帧。

此外,opcode在数据交换的场景下,表示的是数据的类型。0x01表示文本,0x02表示二进制。而0x00比较特殊,表示延续帧(continuation frame),顾名思义,就是完整消息对应的数据帧还没接收完。

数据分片例子

直接看例子更形象些。下面例子来自MDN,可以很好地演示数据的分片。客户端向服务端两次发送消息,服务端收到消息后回应客户端,这里主要看客户端往服务端发送的消息。

第一条消息

FIN=1, 表示是当前消息的最后一个数据帧。服务端收到当前数据帧后,可以处理消息。opcode=0x1,表示客户端发送的是文本类型。

第二条消息

  1. FIN=0,opcode=0x1,表示发送的是文本类型,且消息还没发送完成,还有后续的数据帧。
  2. FIN=0,opcode=0x0,表示消息还没发送完成,还有后续的数据帧,当前的数据帧需要接在上一条数据帧之后。
  3. FIN=1,opcode=0x0,表示消息已经发送完成,没有后续的数据帧,当前的数据帧需要接在上一条数据帧之后。服务端可以将关联的数据帧组装成完整的消息。
Client: FIN=1, opcode=0x1, msg="hello"
Server: (process complete message immediately) Hi.
Client: FIN=0, opcode=0x1, msg="and a"
Server: (listening, new message containing text started)
Client: FIN=0, opcode=0x0, msg="happy new"
Server: (listening, payload concatenated to previous message)
Client: FIN=1, opcode=0x0, msg="year!"
Server: (process complete message) Happy new year to you too!

心跳连接

WebSocket为了保持客户端、服务端的实时双向通信,需要确保客户端、服务端之间的TCP通道保持连接没有断开。然而,对于长时间没有数据往来的连接,如果依旧长时间保持着,可能会浪费包括的连接资源。

  1. 发送方 -》 接收方 opcode : PING
  2. 接收方 -》 发送方 opcode:PONG

ping、pong的操作,对应的是WebSocket的两个控制帧,opcode分别是0x90xA

举例,WebSocket服务端向客户端发送ping,只需要如下代码(采用ws模块)

ws.ping('', false, true);

巨人的肩膀:https://www.cnblogs.com/chyingp/p/websocket-deep-in.html

你可能感兴趣的:(websocket,网络协议,网络)