RPC

远程过程调用协议(Remote Procedure Call, RPC)并不是一个协议,而是一种调用方式,比如ONC RPC/Sun RPC, DCE/RPC, MS RPC, ONC RPC, gRPC等等

RPC重点解决三个问题:表示数据(序列化反序列化等),传递数据(传输协议),确定方法(接口描述语言)

Websocket

在一开始有这么个问题,如何让服务器自己推送数据,而不是客户端请求一次就推送一次。

  • 不断轮询:客户端每隔一定时间就查询一次,比如1s
  • 长轮询:设置http的超时时间,比如30s

以上两种方法都不能很好地解决这个问题,而websocket就可以很好解决,他是一种全双工协议。

websocket通过HTTP请求头中地Upgrade: websocketConnection: Upgrade进行升级,还需要带上随机base64码Sec-WebSocket-Accept:

如果服务器支持,那么就进行websocket握手协议,状态码变为101(协议切换),并根据随机basse64码使用公开算法生成新的码放到头部Sec-WebSocket-Accept里面,并加上头部Upgrade: WebSocket, Connection: Upgrade。客户端收到这个响应后,使用同样的算法来检验服务器发的Sec-WebSocket-Accpet。后续就可以进行WebSocket通信了。

websocket的数据包叫做,它如下所示

 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 ...                |
+---------------------------------------------------------------+
节选自 RFC 6455: https://datatracker.ietf.org/doc/html/rfc6455
  • FIN:1表示这是消息的最后一个分片,0表示这不是消息的最后一个分片
  • RSV1,2,3:默认为0,当双方协商websocket扩展时,这三个标志可以为1
  • opcode:操作码,也是表明数据部分怎么解析
    • 0表示延续帧,1表示text,2表示binary
    • 3-7保留,之后用于非控制帧
    • 8表示关闭连接
    • 9表示ping,心跳检测
    • 10表示pong,心跳响应
    • 11-15保留,之后用于控制帧
  • MASK:1负载数据需要掩码计算(客户端->服务端必须掩码,反向无需),0表示未掩码(服务端->客户端)
  • 载荷长度:
    • 0-125:直接表示长度
    • 126:后续两个字节表示长度(65535),大端序
    • 127:后续8字节表示长度($2^{64}-1$),大端序
  • 掩码密钥:如果设置了MASK,那么就有4个字节的掩码
  • 载荷数据:包含扩展数据和应用数据,扩展数据在一开始协商好

掩码算法:掩码密钥是客户端随机32位数据,算法如下

uint8_t mask[4]; // 32位掩码密钥
uint8_t data[N]; // 长度为N的数据
uint8_t unmask_data[N]; // 解密数据
for(int i = 0; i < N; ++i){
    unmask_data[i] = data[i] ^ mask[i%4];
}