这两年最火的是什么?物联网,现在连我家的电灯泡都是连网的。大量设备连网最考验的就是我们服务器的连接数量和保持情况。 最近会陆续更新一系列的文章,使用Netty做IoT服务端的设计和技术讨论文章。

技术选型

在Java界做socket开发最好的框架就是Netty,他本身是一个基于nio的封装,并解决了在Linux环境下nio的一些已知BUG。理想情况下前置程序应该只负责终端设备的连接保持和数据的接收发送,具体的业务交由后置程序来实现处理。

先来看一下我初步设计的程序架构图:

box-server.png

  • Netty在最前端负责接收连接请求和上下行数据,实验数据使用1G内存docker容器运行,一个容器可以保持并处理5万个终端的连接。
  • 为了加快Netty的处理速度,从终端接收上来的数据会直接放到disruptor内存环形队列中。
  • disruptor的消费者会根据数据的类型来选择,注册终端或通过异步MQ向后置处理程序提交
  • 同时还需要做基本的心跳检查

通讯协议设计

通许协议的设计主要从几个方面考虑:

  1. 首先要能解决TCP的粘包、半包问题
  2. 通讯数据量要尽可能的小,终端设置的物联卡一般流量包都不会太大。
  3. 编码格式,目前一般都使用UTF8格式

为了解决第一问题,一般协议会考虑使用:

  1. 定长数据包方案优点是处理简单,缺点是为了照顾大数据包。会存在大量包里携带空数据。适合比较简单的数据/控制
  2. 特定字符分割方式。大多采用\n来分包,比第一种相对灵活。比如redis的通讯就是用的这种
  3. 首字节指定包长度方式。大量基于C开发的终端设备在使用,相对第一种更灵活不浪费流量
  4. 闭合包方式,目前互联网协议里用的最多的json。可以使用基础器来找{}的匹配,优点时通用性好,缺点是多少会浪费流量。

如果终端程序和服务端都是自行开发,推荐使用谷歌家的protobuf,Netty有良好的支持。如果双终端是第三方开发的为了降低联调难度推荐使用json。这次我们选择使用Json来进行设计我们的协议

业务 请求 应答 备注
登录 {“msgType”: 10, “devId”: “11010112345”, “version”:”1.0”, “txNo”: “1234567890123”, “sign”: “md5(devId+txNo+key)”} {“msgType”: 11, “result”: 1, “txNo”: “1234567890123”} 终端=>服务器
心跳 {“msgType”: 20, “txNo”: “1234567890123”} {“msgType”: 21, “txNo”: “1234567890123”} 双向
控制 {“msgType”: 30, “txNo”: “1234567890123”, “data”: “”} {“msgType”: 31, “txNo”: “1234567890123”, “result”:””} 服务器=>终端
数据上报 {“msgType”: 40, “txNo”: “1234567890123”, “data”: “”} {“msgType”: 41, “txNo”: “1234567890123”} 终端=>服务器
注销 {“msgType”: 50, “txNo”: “1234567890123” } {“msgType”: 51, “txNo”: “1234567890123” } 双向,主动断开链接

说明:

  1. txNo为唯一序号,使用13位时间戳即可,应答时带回同一个时间戳即可。
  2. 登录接口里的sign主要是为了防止接口泄漏后,有人恶意请求接口模拟设备踢掉真实设备
  3. 心跳包 从服务器向终端时,终端如果无法跑NTP协议可以用此包里的txno做校时
  4. 注销功能主要 是为了客户端正常下线使用。减少服务器保持连接的时间减少资源占用。


如果觉得文章内容比较实用,期望获得更新通知,请关注公众号:

guohaiqr.jpg