WebSocket系列之二进制数据设计与传输

概述

通过前三篇博客,我们能够了解在通过WebSocket发送数据之前,我们需要传递的数据是如何变成ArrayBuffer二进制数据的;在我们收到二进制数据之后,我们又如何将其变成了JavaScript中的常见数据类型。 本文作为WebSocket系列的第四篇内容,将会用一个简单的IM聊天应用把整个WebSocket传输二进制数据类型的内容连接起来,让用户对整个WebSocket传输二进制数据的方法有个了解。 本文的主要内容如下:

  • 如何设计一个二进制协议
  • WebSocket如何发送二进制数据
  • WebSocket如何处理接收的二进制数据

之前的博客我们介绍过了WebSocket基础知识,数字类型和字符串类型与二进制数据间的转换,如果没有相关的基础,建议先依次阅读以下文章:

如何设计一个二进制协议

什么是协议

协议,网络协议的简称,网络协议是通信计算机双方必须共同遵从的一组约定。如怎么样建立连接、怎么样互相识别等。只有遵守这个约定,计算机之间才能相互通信交流。它的三要素是:语法、语义、时序。

通过百度百科中的介绍,我们对协议的概念有了一个基础的了解。通俗来说,协议就是通信双方约定好的一套规则。

为什么要设计协议

没有规矩不成方圆。通信双方只有通过协议,才能够识别对方发送的数据内容。

我们应该如何设计这套协议

首先,协议的设计应该能够区分不同的各个数据包;其次,它还需要具备一定的兼容性。 根据上述两点要求,我们设计了一套简单的IM聊天协议,支持文本、图片、文件三种消息。这套协议是按照最简单的思路来设计的,因此也只是给大家一个参考的观点,在真正的线上使用场景中,协议会比本文中的复杂和更加有层次。具体格式如下:

{
    "id": "short", // 消息类型,1是文本协议格式;2是图片协议格式;3是文件协议格式
    "sender": "long", // 发送用户唯一id
    "reciever": "long", // 接受用户唯一id
    "data": "string" // 消息内容,如果是文本协议则为文本内容;如果是图片协议则为图片地址;如果是文件协议则为文件地址
}

这套协议如何使用

发送消息

从协议格式可知,将上述数据按照上述固定顺序放入ArrayBuffer中,即可得到一个有特定含义的二进制数据。例如:

{
    "id": 1,
    "sender": "123",
    "reciever": "456",
    "data": "Hellow World"
}

当我们需要发送此消息时,只需要:

  1. 在前2个Byte放入id
  2. 接下来8个Byte中放入sender
  3. 再接下来8个Byte放入reciever
  4. 最后紧接着放入一个string类型(以WebSocket系列之字符串如何与二进制数据进行转换博客中的格式为例,先将字符串长度构造成一个int类型,放在前4个Byte中,接下来将string类型编码后放入)。

此数据就完全按照协议构造完成了。我们只需将次协议通过WebSocket发送即可。具体方法将会在后面章节中说明。

接收消息

从协议格式可知,当我们收到一条消息时,只需要按照协议规范来进行反向解析即可。例如:

{
    "id": 1,
    "sender": "123",
    "reciever": "456",
    "data": "Hellow World"
}

如果发送端发送的数据仍然为此消息,我们的解析顺序为:

  1. 先根据前2个Byte读取一个Short类型的id数值。
  2. 将接下来的8个Byte读取为Long类型的sender字段。
  3. 再接下来的8个Byte读取为Long类型的reciever字段。
  4. 接下来读取一个string类型(以发送消息这一节的数据为例,先读取4个Byte长度的int类型字符串长度,然后再根据长度读取字符串即可)。

扩展此协议

当此协议字段无法满足并且已经在线上使用时,我们应该如何扩展呢? 根据我们的写入和读取步骤,我们可以知道:每次我们读取的二进制数据可以认为是一个格式固定的数据(string类型在构造时会有长度信息,因此认为也是长度相对固定),所以我们在读取二进制数据时读取的长度也是固定的。因此,我们在扩展时只需要往协议后面增加字段即可。

  • 扩展前的应用仍然会读取之前已经确定的数据协议,只需要保证内容不变,那么功能也不会变。
  • 扩展后的应用能够解析扩展后的协议,因此得到更多的数据,从而可以实现更多的功能。

WebSocket如何发送二进制数据

通过如何设计一个二进制协议一章,我们知道了如何定义WebSocket传输的二进制数据格式。下面,我们来看下如何在WebSocket中发送二进制数据:

let arrayBuffer = getArrayBufferMessagesFromUser(); // 获取用户需要发送的消息数据,为一个ArrayBuffer对象
let webSocket = getWebSocket(); // 获取已经连接成功的WebSocket实例

websocket.binaryType = 'arraybuffer'; // 指定WebSocket接受ArrayBuffer实例作为参数

webSocket.send(arrayBuffer);

通过上面的示例我们可以知道,WebSocket在发送string类型的数据或者ArrayBuffer类型的数据时,使用的API接口都是send方法,我们只需要在WebSocket初始化后指定传输类型binaryType即可。

WebSocket如何处理接收的二进制数据

通过WebSocket如何发送二进制数据一章,我们知道了如何发送二进制数据。接下来,让我们开看下如何处理WebSocket接收到的二进制数据:

let webSocket = getWebSocket(); // 获取已经连接成功的WebSocket实例

websocket.binaryType = 'arraybuffer'; // 指定WebSocket接受ArrayBuffer实例作为参数

webSocket.addEventListener('message', (message) => {
    let arrayBuffer = message.data; // 获取用户接收到的消息数据,为一个ArrayBuffer对象
    let data = parseMessage(arrayBuffer); // 解析二进制数据
});

通过上面的示例我们可以知道,当我们在建立连接时指定了传输类型binaryType为ArrayBuffer之后,我们通过WebSocket收到的数据也是一个ArrayBuffer实例。我们只需要根据第一章讲解的方式进行解析即可。

总结

本文作为WebSocket系列的第四篇,通过一个IM聊天应用的示例将前三篇博客分享的内容串联起来,给读者完整介绍了在WebSocket中使用二进制数据进行传输的方法以及相关的数据类型转换。 通过前面4篇博客的内容,读者可以根据自己的需求快速的构造和封装WebSocket进行二进制数据传输,基本能够串联整个应用流程。 WebSocket系列下一篇文章将会介绍在线上环境中,如何保证WebSocket的连接,以及线上可能遇到的问题。通过应对WebSocket可能出现的问题,我们能够让整个长连接更加健壮。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏熊训德的专栏

Hbase compaction 源码分析一:compaction 概况分析

本文档从框架的源码角度梳理了,hbase 在什么情况下会触发compaction,并通过官方文档说明出发minor 和major compaction的时间点。

51910
来自专栏Google Dart

Dart服务器端 shelf包 原

handler是处理shelf.Request并返回shelf.Response的任何函数。它可以处理请求本身 - 例如,在文件系统上查找请求的URI的静态文件...

32410
来自专栏社区的朋友们

在共享内存实现 Redis(下)

从实现方式入手,设计了一种综合二者优点的方案:将 Redis 做成数据逻辑分离,数据存放共享内存,进程只负责存储逻辑,同时解决 Redis 长命令卡顿和 for...

43500
来自专栏码农阿宇

asp.net core轻松入门之MVC中Options读取配置文件

接上一篇中讲到利用Bind方法读取配置文件 ASP.NET Core轻松入门Bind读取配置文件到C#实例 那么在这篇文章中,我将在上一篇文章的基础上,利...

26240
来自专栏python学习之旅

Python笔记(四):异常处理机制与 open()

(一)  异常处理机制概述 就像日常生活中会遇到各种意外情况一样(例如:你可能考虑过如果中了500w该怎么做),代码运行过程中也会遇到这种意外情况,python...

32830
来自专栏个人分享

MongoDB 3.0.6的主,从,仲裁节点搭建

在MongoDB所在路径创建log和data目录 mkdir log mkdir data

26710
来自专栏pangguoming

C# 读写App.config配置文件的方法

一、配置文件概述: 应用程序配置文件是标准的 XML 文件,XML 标记和属性是区分大小写的。它是可以按需要更改的,开发人员可以使用配置文件来更改设置,而不必重...

65990
来自专栏青玉伏案

iOS开发之再探多线程编程:Grand Central Dispatch详解

Swift3.0相关代码已在github上更新。之前关于iOS开发多线程的内容发布过一篇博客,其中介绍了NSThread、操作队列以及GCD,介绍的不够深入。今...

20170
来自专栏简书专栏

Python数据持久化-小测验

现有如下图1所示的data.csv文件数据,请使用python读取该csv文件数据,并添加一条记录后输出如图2所示的output.csv文件(10分)

16730
来自专栏芋道源码1024

分布式消息队列 RocketMQ 源码分析 —— Message 拉取与消费(上)

摘要: 原创出处 http://www.iocoder.cn/RocketMQ/message-pull-and-consume-first/ 「芋道源码」欢迎...

38060

扫码关注云+社区

领取腾讯云代金券