前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android与单片机 | 开发板 | 智能硬件 | 智能设备 | 数据协议 |开发总结

Android与单片机 | 开发板 | 智能硬件 | 智能设备 | 数据协议 |开发总结

作者头像
Android技术干货分享
发布2019-06-19 10:54:54
6480
发布2019-06-19 10:54:54
举报
文章被收录于专栏:Android技术分享Android技术分享

一、缘起

工作中经常遇到需要Android程序与各式各样的板子、智能设备进行交互,通信的方式也基本上都是Ble或者Socket tcp/udp等等.....其中最重要的一点就是通信的协议协议协议重要的是说三遍;通信协议就是用来定义与设备交互的方式和交互过程中数据包的格式 如:(包头—数据包长度—数据—校验位—包尾)

二、这里先来理理各种数据类型、所占的字节数等

1、我们写的代码最终都是转化成各种机器所能识别的二进制或者字节码,不同的编程语言具有不同的数据类型基本的也好不基本的也好、当然有不同的也就有相同的byte(字节)就是其中的一个; 2、日常开发中我们进行通信发送的内容最终都会以字节的形式进行发送,这里以JavaSocket为例,我们来看下源码

  • 创建一个socket连接,发送数据
代码语言:javascript
复制
Socket socket = new Socket(ip, port);
OutputStream outputStream = socket.getOutputStream();
//发送数据
outputStream.write("Hello World!".getBytes());
outputStream.flush();
//关闭连接
outputStream.close();
socket.close();
  • 我们来看下OutputStreamwirte(byte[] b)函数
  • OutputStream # write(byte[] b)
代码语言:javascript
复制
//1 接着又调用了write(byte b[], int off, int len)
public void write(byte b[]) throws IOException {
    write(b, 0, b.length);
}

//2 最后又调用了write(byte b)
public void write(byte b[], int off, int len) throws IOException {
    if (b == null) {
        throw new NullPointerException();
    } else if ((off < 0) || (off > b.length) || (len < 0) ||
               ((off + len) > b.length) || ((off + len) < 0)) {
        throw new IndexOutOfBoundsException();
    } else if (len == 0) {
        return;
    }
    //3 这里就是讲我们发送的一个bye[]进行for循环一个个写入了
    for (int i = 0 ; i < len ; i++) {
        write(b[off + i]);
    }
}

//4 end
public abstract void write(int b) throws IOException;

小结:无论定义的通讯格式是什么样的最终肯定要转成byte[](字节数组)进行发送,所以只要将数据转成字节数组即可,下面进入数据类型科普时间

三、Java中的数据类型所占的字节数和bit数

数据类型

所占字节数

所占bit数

取值范围

byte

1

8

-128 ~ 127

char

2

16

'\u0000' ~ '\uFFFF'

short

2

16

-2^15 ~ 2^15 - 1

int

4

32

-2^31 ~ 2^31 - 1

float

4

32

2^-149 ~ 2^128 -1

long

8

64

-2^63 ~ 2^63 - 1

double

8

64

2^-1074 ~ 2^1024 - 1

boolean

/

1

true or false

  • String在Java中不属于基本数据类型,一个汉字占2个字节,一个英文字母占1个字节
  • 小结:1 byte = 8 bit
3.1 什么是bit呢?什么又是高低位呢?在Java中又怎么写代码呢?
  • bit就是 也就是二进制数据,取值只有 0,1 - 高位在左,低位在右
    • 这里以byte 123为例:
    • byte b =123 转为bit
    • 高位在0,低位在1 0111 1011
  • 在Java中获取byte的8个bit
代码语言:javascript
复制
/**
 * byte转8 bit
 *
 * @param b byte
 * @return 高位到低位顺序, 以byte123 为例: 0111 1011
 */
public static byte[] byte2Bit(byte b) {
    byte[] arr = new byte[8];
    for (int i = 7; i >= 0; i--) {
        arr[i] = (byte) (b & 1);
        b = (byte) (b >> 1);
    }
    return arr;
}
  • 既然把byte转为了8个bit位,那我们又怎么再把bit转回为byte呢?
代码语言:javascript
复制
/**
 * 8个bit位转为byte
 */
public static byte bit2Byte(byte[] bytes) {
    if (bytes.length != 8) return 0;
    String binary = "";
    byte result;
    for (byte b : bytes) {
        binary += b;
    }
    if (bytes[0] == 0) {
        // 正数
        result = (byte) Integer.parseInt(binary, 2);
    } else {
        // 负数
        result = (byte) (Integer.parseInt(binary, 2) - 256);
    }
    return result;
}
3.2 上面已经说了byte与bit的相互转化,现在就轮到int
  • 上面已经说了一个int4个字节32bit
  • Integer类已经为我们封装好了转bit的方法,如下:
代码语言:javascript
复制
String s = Integer.toBinaryString(35235);
//输出结果
1000100110100011
  • 可以看到没有32位,这是为什么呢?这是因为高位都是为0所以就直接省略了,当然我们也可以主动补齐32位只需要在高位补0即可。
  • bit再转回为int
代码语言:javascript
复制
int result = Integer.parseInt("1000100110100011", 2);
//输出结果
35235
  • 这里需要注意的是Integer.toBinaryString()可以将负数转化为二进制,但是Integer.parseInt("", 2)不能直接将负数的二进制转为int,如下:
代码语言:javascript
复制
String radix = Integer.toBinaryString(-35235);
System.out.println(radix);
int result = Integer.parseInt(radix, 2);
System.out.println(result);

程序执行会报一个java.lang.NumberFormatException: For input string:"11111111111111110111011001011101"异常,那我们怎么将负数的转回为int呢?当然是有方法的啦,如下:

代码语言:javascript
复制
//需要借助 BigInteger类
String radix = Integer.toBinaryString(-3535);
BigInteger integer = new BigInteger(radix, 2);
System.out.println(integer.intValue());
//输出结果
-3535
3.3当然我们可以通过电脑的计算器来计算二进制
3.4 上面我们说了一个int32个字节也就是4byte,那理所当然一个int可以转成2个byte或者4byte,如下:
代码语言:javascript
复制
/**
 * 一个int转2个字节的byte数组
 * 由低位到高位的转换
 *
 * @param value
 * @return
 */
public static byte[] intTo2Bytes(int value) {
    byte[] src = new byte[2];
    src[0] = (byte) (value & 0xFF);
    src[1] = (byte) ((value >> 8) & 0xFF);
    return src;
}

/**
 * 一个int转4个字节的byte数组
 * 由低位到高位的转换
 *
 * @param value
 * @return
 */
public static byte[] intTo4Bytes(int value) {
    byte[] src = new byte[4];
    src[0] = (byte) (value & 0xFF);
    src[1] = (byte) ((value >> 8) & 0xFF);
    src[2] = (byte) ((value >> 16) & 0xFF);
    src[3] = (byte) ((value >> 24) & 0xFF);
    return src;
}

这里需要注意的是int转byte[]的时候是高位数组的0下标 还是低位数组的0下标,上面的两个方法都是低位在数组的0下标

四、上面bb了一大堆,现在我们通过一个具体的协议来深入了解这些内容

4.1 协议如下:

这里需要解释下ucharuint是什么意思?uchar = unsigned char 、uint = unsigned int,也就是无符号的数据,也就是表示了这个数据是正数

  • 1、对协议进行分析可以得知:整个数据包是由两部分组成的包头+扩展数据包,其中包头占固定的32个字节
  • 2、首先我们得分析包头里面的每一个字段所占了多少个字节
    • uchar 占1个字节
    • uint 占4个字节
  • 2、那我们重点就是得来分析包头的数据需要怎么封装,通过协议我们可以看出包头内一共包含6个字段,分别表示如下:
    • 第一个为固定的"DH",总共占2个字节
    • 第二个为版本1.0 ,总共占2个字节
    • 第三个为扩展数据长度"extlen" ,总共占4个字节
    • 第四个为扩展数据类型取值0或1 ,总共占1个字节
    • 第五个为保留字段不使用就0补齐,总共占3个字节
    • 第六个为保留字段不使用就0补齐,总共占20个字节
  • 3、通过上面一顿分析,我们就轻松的理清了每个字段所占的字节了
4.2 Talk is cheap. Show me the code.
代码语言:javascript
复制
//magic
byte[] magicB = {'D', 'H'};
//协议版本1.0转成int也就是1
byte[] versionB = {0, 1};
//扩展数据长度,这里假定扩展数据的长度为67
byte[] extLenB = intTo4Bytes(67);
//扩展数据类型 0:JSON、1:二进制数据;这里使用JSON
byte[] extType = {0};
//两个保留字段,直接0补齐,上面已经分析了两个字段一共占23个字节
byte[] reserved = new byte[23];
//这里将上面的多个数据合并至一个byte[]
byte[] data = byteMergerAll(magicB, versionB, extLenB, extType, reserved);

到这里包头的数据就已经处理好了,还可以进一步对它进行封装

  • 这里提供一个多个数据数组合并的工具方法
代码语言:javascript
复制
/**
 * 多个数组合并一个
 *
 * @return
 */
public static byte[] byteMergerAll(byte[]... bytes) {
    int allLength = 0;
    for (byte[] b : bytes) {
        allLength += b.length;
    }
    byte[] allByte = new byte[allLength];
    int countLength = 0;
    for (byte[] b : bytes) {
        System.arraycopy(b, 0, allByte, countLength, b.length);
        countLength += b.length;
    }
    return allByte;
}
4.3 封装包头数据
代码语言:javascript
复制
/**
 * 封装包头数据
 * 固定32个字节,其余的0补齐
 *
 * @param extLen 扩展数据长度
 */
public static byte[] getPkgHead(int extLen) {
    //magic
    byte[] magicB = {'D', 'H'};
    //协议版本1.0转成int也就是1
    byte[] versionB = {0, 1};
    //扩展数据长度,这里假定扩展数据的长度为67
    byte[] extLenB = intTo4Bytes(extLen);
    //扩展数据类型 0:JSON、1:二进制数据;这里使用JSON
    byte[] extType = {0};
    //两个保留字段,直接0补齐,上面已经分析了两个字段一共占23个字节
    byte[] reserved = new byte[23];
    //这里将上面的多个数据合并至一个byte[]
    return byteMergerAll(magicB, versionB, extLenB, extType, reserved);
}
4.4上面已经把包头处理好了那现在就可以发送命令了
代码语言:javascript
复制
//扩展数据:这里就需要根据实际的文档来生成了,我这里就随便写一个了
String extData = "{\"id\":12,\"cmd\":\"open\"}";
 byte[] extDataB = extData.getBytes();
 //获取包头
 byte[] pkgHead = getPkgHead(extDataB.length);
 //一个完整的数据包
 byte[] sendData = byteMergerAll(pkgHead, extDataB);

到这里一个完整的数据包就愉快的结束了也就实现了与设备的通信了;重点:以后再拿到一个协议首先研究一下由多少个部分组成,每个组成的部分占多少个字节,是高位到低位还是低位到高位

最后

如果你看到了这里,觉得文章写得不错就给个赞呗?如果你觉得那里值得改进的,请给我留言。一定会认真查询,修正不足。谢谢。

最后针对Android程序员,我这边给大家整理了一些资料,包括不限于高级UI、性能优化、移动架构师、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.06.17 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、缘起
  • 二、这里先来理理各种数据类型、所占的字节数等
  • 三、Java中的数据类型所占的字节数和bit数
    • 3.1 什么是bit呢?什么又是高低位呢?在Java中又怎么写代码呢?
      • 3.2 上面已经说了byte与bit的相互转化,现在就轮到int了
        • 3.3当然我们可以通过电脑的计算器来计算二进制
          • 3.4 上面我们说了一个int占32个字节也就是4个byte,那理所当然一个int可以转成2个byte或者4个byte,如下:
          • 四、上面bb了一大堆,现在我们通过一个具体的协议来深入了解这些内容
            • 4.1 协议如下:
              • 4.2 Talk is cheap. Show me the code.
                • 4.3 封装包头数据
                  • 4.4上面已经把包头处理好了那现在就可以发送命令了
                  • 最后
                  相关产品与服务
                  云开发 CloudBase
                  云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档