Android最佳实践——深入浅出WebSocket协议

Posted _区长

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android最佳实践——深入浅出WebSocket协议相关的知识,希望对你有一定的参考价值。

首先明确一下概念,WebSocket协议是一种建立在TCP连接基础上的全双工通信的协议。概念强调了两点内容:

  • TCP基础上
  • 全双工通信

那么什么是全双工通信呢?

全双工就是指客户端和服务端可以同时进行双向通信,强调同时、双向通信

WebSocket可以应用于即时通信等场景,比如现在直播很火热,直播中的弹幕也可以使用WebSocket去实现。

WebSocket的协议内容可以见 The WebSocket Protocol,讲得最全面的官方说明。简单介绍可以见维基百科WebSocket

android客户端,一般可以使用下面的库完成WebSocket通信

  • okhttp,一般人我不告诉他okhttp还可以用来进行WebSocket通信
  • Java-WebSocket,纯java实现的WebSocket客户端和服务端实现

那么在没有服务端支持的情况下,我们客户端如何进行WebSocket的测试呢?一般人我也不告诉他!答案还是okhttp,这次是okhttp的扩展模块mockserver,不过最新版本的okhttp已经把WebSocket合入okhttp核心库中去了,如果你用的版本比较低,就可能需要依赖okhttp-ws模块。

先来看协议内容组成,先上一张神图

这里写图片描述

WebSocket按上面图中协议规则进行传输,上图称为一个数据帧。

  • FIN,共1位,标记消息是否是最后1帧,1个消息由1个或多个数据帧构成,若消息由1帧构成,起始帧就是结束帧。
  • RSV1,RSV2,RSV3,各1位,预留位,用于自定义扩展。如果没有扩展,各位值为0;如果定义了扩展,即为非0值。如果接收的帧中此处为非0,但是扩展中却没有该值的定义,那么关闭连接。
  • OPCODE,共4位,帧类型,分为控制帧和非控制帧。如果接收到未知帧,接收端必须关闭连接。已定义的帧类型如下图所示:
    这里写图片描述

除了上图中的0,1,2外(0x0,0x1,0x2),3-7(0x3-0x7)暂时没有进行定义,为以后的非控制帧保留。
除了上图中的8,9,10(0x8,0x9,0xA)外,11-15(0xB-0xF)暂时没有进行定义,为以后的控制帧保留。

消息的分片,一般来说,对于一个长度较小的消息,可以使用1帧完成消息的发送, 比如说文本消息,Fin的值为1,表示结束,Opcode值不能为0,0表示后续还有数据帧会发送过来。
而对于一些长度较长的消息,则需要将消息进行分片发送。比如语音消息,这时候起始帧的FIN值为0,Opcode为非0,接着是若干帧(FIN值都为0,Opcode值为0),结束帧FIN值为1,Opcode值为0。

WebSocket的控制帧有3种,关闭帧、Ping帧、Pong帧,关闭帧很好理解,客户端如果收到关闭帧直接关闭连接即可,当然客户端也可以发送关闭帧给服务器端。而Ping帧和Pong帧则是WebSocket的心跳检测,用于保证客户端是在线的,一般来说,只有服务端给客户端发送Ping帧,然后客户端发送Pong帧进行回应,表示自己还在线,可以进行后续通信。

  • MASK,共1位,掩码位,表示帧中的数据是否经过加密,客户端发出的数据帧需要经过掩码处理,这个值都是1。如果值是1,那么Masking-key域的数据就是掩码秘钥,用于解码PayloadData,否则Masking-key长度为0。

WebSocket协议规定数据通过帧序列传输。客户端必须对其发送到服务器的所有帧进行掩码处理。

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

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

更多状态码如下图所示:

这里写图片描述

  • Payload len,7位或者7+16位或者7+64位,表示数据帧中数据大小,这里有好几种情况。

    • 如果值为0-125,那么该值就是payload data的真实长度。
    • 如果值为126,那么该7位后面紧跟着的2个字节就是payload data的真实长度。
    • 如果值为127,那么该7位后面紧跟着的8个字节就是payload data的真实长度。
    • 长度遵循一个原则,就是用最少的字节表示长度,举个例子,当payload data的真实长度是124时,在0-125之间,必须用7位表示;不允许将这7位表示成126或者127,然后后面用2个字节或者8个字节表示124,这样做就违反了原则。
  • Masking-key ,0或者4个字节,当MASK位为1时,4个字节,否则0个字节。如果MASK值为1,则发出去的数据需要经过加密处理,加密流程如下: