1. 背景介绍 朋友公司要做一个智能柜项目,他们有一批医院的智能柜,然后有一个平台,他们想把这批智能柜和平台连接起来,而目前的技术力量只有硬件端和软件端,连接部分缺人。
2. 初步分析 软件端是用jfinal编写的一个web平台,对外提供http访问。而硬件端只能使用tcp长连接进行通信。中间需要一个中间件来打通硬件端和软件端。
具体的架构图如下:
3. 基本方案 开发一个中间件,既能提供http访问,也能提供tcp长连接通信。开发框架选择的是spring boot+netty。 spring boot提供web服务(http服务),同时开启netty服务端(tcp长连接)。 netty部分处理与智能柜的通信,spring boot部分处理与平台的通信。
4. 项目细节 智能柜能主动向平台发起请求 平台也能主动向智能柜发起请求 智能柜与中间件之间的通信报文以%start%开始,以%end%结尾,中间是json字符串
5. 项目难点 与智能柜这边的通信是难点,因为tcp通信是异步的,请求和响应不一定在一个线程完成。而http通信是同步的,请求和响应在一个线程完成。不同的通信模型在整合的时候会有区别。
智能柜主动发起的请求这个简单,中间件收到智能柜的报文以后,请求平台获取响应,然后直接把响应回传给智能柜。
但是从平台发起的请求不好实现。中间件收到平台的请求以后需要发给对应的智能柜,但是智能柜的响应并非在一个线程里回传的,因为它是异步的。所以怎么同步等待智能柜的响应把结果返回给平台是项目的难点。(除非平台也做成异步接口,请求是一个接口,响应是另一个接口,这样多写一个接口也可以,但是要改动平台)
6. 问题解答 平台发起的请求,中间件在请求发给智能柜以后,这里需要一个阻塞过程,等待智能柜的响应,可以设置超时时间,当超过1秒钟直接抛出异常。如果收到结果则返回给平台。
具体请求模型如下:
从图中可以看出这里响应容器是最最关键的地方。java并发包提供的响应容器有阻塞队列,但是这里不适用,因为请求和响应需要一一对应,我不能获取到别的请求的响应。
我需要的其实是一个阻塞map,每一次请求我都生成一个唯一标识,这个标识我会传给智能柜,而智能柜也会返回我这个标识。map里面的key就是这个唯一标识,当我根据key去取值的时候如果有说明有响应了,如果没有我阻塞等待,当超时了则直接抛出异常。
这个阻塞map模型能很好的实现我的功能,但是很抱歉jdk并没有现成的工具。后来还是求助github找到了一个解决方案,我试用了一番暂时没有发现问题。至于它具体的实现我还没有去深究,底层也是有理解难度的。
7. 项目总结 第一次使用netty做项目开发,从学习netty的入门demo到把框架搭建起来项目开发完毕花了2个晚上,也算是一次成功的开发学习经历。平常学习新技术没啥动力,但是工作中需要用到的时候往往会有一股力量使得自己更加专注。
经过这个项目的历练,后面再有物联网相关项目的开发也能知道怎么上手了。