目 录
第一章 绪论 1
1.1. 背景意义 1
1.2. 物联网发展现现状 1
1.3. 主要工作内容 1
1.4. 论文组织 2
第二章 微信硬件平台与物联网平台演进 3
2.1. 物联网与物联设备 3
2.2. 手机直接控制物联设备架构 3
2.3. 基于独立后台服务的物联架构务的物联架构 4
2.4. 基于统一后台服务的物联架构 5
2.5. 物联网的消息传达机制 5
第三章 微信硬件平台环境搭建 8
3.1. 厂商服务器搭建 8
3.2. 微信硬件平台的配置 10
3.3. 添加设备产品 12
3.4. 测试号的菜单栏设计 15
第四章 微信硬件平台的开发和WEB设计 18
4.1. 测试号的开发 18
4.1.1. 测试号后台消息收发的原理和架构 18
4.1.2. 厂商服务器消息接收程序 19
4.1.3. 厂商服务器处理文本消息程序 21
4.1.4. 厂商服务器处理多媒体消息消息程序 22
4.1.5. 厂商服务器下载多媒体文件 25
4.1.6. access_token值的获取和保存 26
4.1.7. 微信后台的消息推送机制客服接口 29
4.2. 数据库的设计 30
4.3. WEB相关的设计和网页的开发 32
4.3.1. 查询用户绑定的设备总数 32
4.3.2. 查询用户当前选得的设备的情况 36
4.3.3. 用户选择设备 39
4.3.4. 用户管理设备 42
第五章 硬件设备跟厂商服务器联通 47
5.1. 服务器端和客户端的程序流程图 47
5.2. 关于多进程的程序设计 49
5.2.1. 服务器端程序的多进程功能 49
5.2.2. 客户端程序的多进程功能 49
5.2.3. linux的多线程 49
参考文献 58
中文摘要
互联网连接了人与人,给人们的生活和工作带来前所未有的便利和效率,如若能够将互联网进一步扩大,把物也连接进互联网,形成物联网,实现人与物,物与物的互联互通,将给我们带来前所未有的体验。因此,本次毕设通过“微信硬件平台”将硬件设备接入互联网,搭建起一个M2M的物联网平台,使得硬件设备能够联网,并通过手机里的微信软件进行控制和访问,不需要安装多余的手机APP软件。给硬件设备移植linux系统,而linux系统对网络有很好的支持,所以,硬件设备和服务器可以轻松的TCP/IP协议,以C/S模式建立和服务器的网络通信;手机微信和服务器的通信则是B/S模式,同时,微信软件自带了浏览器功能,所以通过手机上的微信软件,就可以对多个硬件设备的控制,避免了使用者安装太多手机APP的尴尬局面。
最后成功的实现了用户通过扫描一个二维码绑定设备后,服务器的后台程序会把绑定关系存储到数据库里,进而实现了用户和设备的对应关系,用户可以随时随地的通过互联网访问和控制自己绑定的设备。
论文共七章,介绍了厂商云服务器的搭建,厂商服务器与微信后台的联通,手机微信与厂商后台的B/S通信,嵌入式硬件设备与厂商后台的TCP连接通信,以及嵌入式设备平台的搭建。
关键词:物联网,微信硬件平台,微信,嵌入式硬件设备,网络通信
Abstract
Internet help us connecting each other,bring unprecedented convenience and efficiency for everyone in our lives or works. So if we can make hardware equipments working with Internet to creat a IOT net, it will give us an unprecedented experience. Thus, this graduation project is to build a M2M IOT platform by wechat.User controled and accessed hardware equipments by an APP which was insatlled in our phone in the Internet. User only have to install one APP, wechat,in their mobile. For the hardware equipments, by transplanting the linux system which have a good support on the Internet. So we can connect the hardware devices to the server by TCP/IP protocol easily.Wechat APP connect to the server with a browser, and we know wechat APP have browser function.
Finally, users scan a two-dimensional code to set up the connection with their hardware equipments. And this connection will be stored in the MYSQL databases.So users can control their hardware equipments everywhere with the Internet.
Key words: IOT, wechat platform, wechat, embedded hardware devices, network communications
第一章 绪论
1.1. 背景意义
物联网不是新的实物,早在1999年,这一概念就已经有人提出。然而当时的互联网和嵌入式技术都还没有成熟。而今天,随着互联网的迅猛发展,地球上任何人,任何地点,任何时刻都已经实现了互联互通。但这样传统的互联网已经不足以满足人们的需求,人们更希望把普通的实物硬件也加入互联网,实现人与人,人与物,物与物的互联网互通。这样,通过互联网,人们可以很方便的对硬件实物进行实时的控制和访问。(比如,远程视频监控,远程控制等)给人们带来了极大的便利,这就是物联网诞生的起因和它能够给我们带来的效益。
另一方面,得益与集成电路设计和其制造工艺水平的不断提升,嵌入式经历了一个飞速发展的时期。现在,嵌入式技术已经达到了成熟的阶段,而嵌入式和互联网两者正是物联网的两大核心支柱。因此,物联网的发展浪潮已经在在掀起了。
物联网技术涉及的产业之广泛,已经被很多国家上升到了战略发展的高度。车联网,智能家居,工业4.0等,都是物联网的组成部分。物联网实现了人对物质世界的信息获取和控制,无论是给人们的生活还是生产实践活动都带来的极大的效率。而提高效率,是人类一直梦寐以求的,所以,物联网的发展是顺应时代的发展,是信息时代的必然结果,这就是它最大的意义。
现阶段,几乎人手一部智能手机,而且手机通过移动互联网,是我们身边能够连接上互联网的最好的终端,所以,用手机来访问和控制物联网设备,是最好的也是最方便的物联网解决方案。因此,国内大大小小的物联网公司如雨后春笋般冒出来,但是这些物联网公司各自为阵,没有统一的协议,更没有统一的平台,使用者每购买一个物联网产品,就得在手机上安装一款与之匹配的APP,平台的统一性在一定程度上制约了物联网的发展。试想,如果淘宝上的卖家店铺是一家一家的各自为阵,没有马云出来统一平台,电商能有今天的辉煌吗?草根的淘宝店家之所以能够给传统的零售业带来如此大的冲击,就是因为阿里巴巴统一了中国的电商平台。所以,物联网现阶段要进阶,必须有一家大型的企业或者机构,能站出来统一物联
网这个大平台,然后让其他的小的开发商接入。这样不仅可以减少物联网产品开发商的开发成本,而且可以统一手机上的APP,不至于是用户手机屏幕布满与物联网产品互联的手机APP,而且统一了平台后的物联网将唤醒它真正的潜力。
如今,移动终端用户量最多的用户,莫非阿里巴巴的“支付宝”APP和腾讯的“微信”APP,都是有上亿用户量的重量极手机软件。而作为社交软件出身的“微信”,连接了人与人,那自然而然的可以发展为实现连接人与物,物与物的平台。因此,腾讯在2014年推出了物联网平台—微信硬件开发平台。本次毕设的主要内容就是,基于微信硬件平台,设计物联网实现方案,用手机上的“微信”软件与物联网产品交互。
1.2. 物联网发展现现状
国外现状:当今, 国际上的巨头公司,都在加紧局域网领域的布局,都想在物联网领域占有一席之地。2009年,IBM提出了智慧地球的概念,并被美国接受,进而上升到物联网国家发展战略的高度;谷歌在2014年通过收购Nest公司,开始布局物联网;苹果推出的HomeKit也是基于物联网的应用;ARM公司发布了专门为物联网设计的mbed方案;连三星都在开发一款面向物联网领域的开源系统。德国提出了工业4.0的概念;美国也已经计划把包括,交通,物流,农业,医疗,教育,能源开采等多行业加入互联网来实现智能化;日本和韩国等发达国家,也都提出了大数据和智能工业的概念。可以说物联网的发展,正在迅猛的崛起,并成为各个国家的战略产业链。
国内现状:2009年,前总理温家宝提出了“感知中国”的概念,使得中国的物联网产业进入相对快速发展阶段;2015年,国务院总理李克强提出了互联网+的概念,其实就是让各行各业都接入互联网,是一个泛物联网的概念。我们熟悉的国内互联网三巨头(腾讯,阿里,百度),无不在加紧在做物联网的布局。腾讯推出了QQ物联平台和微信硬件平台。本次毕设就是根据微信硬件平台做的物联网设计。
1.3. 主要工作内容
本文主要学习了微信硬件平台的物联网架构原理和搭建M2M物联网平台的理论知识,研究并实现了一个可以让嵌入式设备联网的物联网平台。主要内容如下:
(1)研究微信的物联网体系,并以wifi模型接入到微信的硬件平台;
(2)搭建厂商服务器,并建立起厂商服务器与微信后台的联通,用PHP语音编程实现;
(3)设计厂商服务器的数据库,保存接入的硬件和绑定该设备的用户的对应关系信息;
(4)用C/S模式实现硬件设备和厂商服务器的连接,用C语言编程实现;
(5)设计WEB网页,用于修改和查询设备的绑定关系,用HTML和PHP实现;
1.4. 论文组织
本文主要介绍了利用微信硬件平台搭建的M2M的物联网设计方案,让实物硬件接入互联网,进而用手机微信进行控制和数据访问,使硬件设备智能化。
第二章:主要介绍了物联网架构的原理和演进,进而推导出微信硬件平台的物联网架构原理和微信物联网平台的消息传递机制。
第三章:主要是介绍本人所做的工作,根据微信的物联网架构和消息传递机制,搭建所需的厂商服务器,并在微信的后台注册和授权硬件设备,设计测试号的菜单栏。
第四章:是本次毕设的工作重点内容,主要包括厂商服务器后台与微信后台联通的程序设计;保存硬件设备和用户的数据库的设计;以及WEB网页的设计。
第五章:也是本次毕设的工作重点和难点内容,主要包括厂商服务器和硬件设备之间的数据通信,涉及到多进程,多线程,网络编程等。
第二章 微信硬件平台与物联网平台演进
2.1. 物联网与物联设备
物联网说到底就是硬件设备组成的互联互通的网络,因此要想实现物联网需具备两个条件,一是设备能够联网,另一个是设备能够组网。物联网跟智能硬件是相互结合的,而为了能够方便布线和实现设备的自由移动,现在的物联网设备大多要求能够实现无限通信的特点。
因此能够实现无线、互联、组网着三个特点的通信技术就是现在我们常见的wifi和蓝牙。蓝牙是近场通信,信号有效距离十米以内,而且穿墙能力极差;wifi距离可以较远一些,而且信号可已穿墙,但其功耗较高。现在比较火的ZigBee通信技术,其通信距离比蓝牙远,功耗比wifi低,可以称得上是实现物联技术的理想通信方案了,可是ZigBee的组网能力比较差,带宽也低,传输比较慢,因此没有得到大面积的普及。ZigBee技术更多的被用在工业控制上。
蓝牙和wifi是现代智能手机的标配模块,而且手机已经逐渐成为当今社会里每一个人的一款生活必须品了,手机是现阶段最大的物联网上的智能设备。除此之外,物联网是已人为核心的应用技术,直接受益者是广大的普通用户,所以,手机做为物联网设备的控制终端,可以极大的方便用户对互联网设备的控制和访问。
2.2. 手机直接控制物联设备架构
但是这种物联网方案一般只能作为开发的模型或样机,没有使用价值,因为它的处在一个致命的缺点,TCP/IP通信协议需要知道通信双方的的IP地址,而第一种方式的IP地址一般是动态获取得到的,所以还需要用户自己通过路由器的web控制界面去查看硬件设备的IP地址,很显然,这种方案在商用应用中是根本不可能出现的。手机和硬件设备消息的通信是物联网应用的核心技术,图2-1中第一种架构模式是手机和硬件设备跟同一个路由器连接,通过这种方式,手机和硬件设备各自都有一个IP地址,手机可以通过TCP/IP协议来与硬件设备通信并达到控制硬件设备的最终目的。第二种方式是硬件设备自带wifi AP热点,手机通过wifi 连接上硬件设备,因为wifi热点的IP可以设置成固定的,因此手机能方便的连接上硬件设备并对硬件设备进行控制和访问。
第二种方式也需要手机APP输入硬件设备固定的IP地址,所以用户控制不同的硬件设备就得输入跟设备对用的IP地址,用户体验度肯定很不好。而且这种设计方案本质上跟遥控没有什么区别,不利于用户获取硬件设备的信息。而给用户提供优质服务和便捷的方式正是物联网的核心价值所在。所以以上两种模式,只能是实验室研发样机用的模型方案,基本没有商业价值可言。
2.3.
这种物联网设计方案中的独立服务器是IP地址的是固定的,这样可以方便的实现TCP/IP的通信协议。这种物联网设计方案中手机和硬件设备都需要以客户端的方式登录到服务器上,并由服务器通过发送心跳包技术来确认手机和硬件设备是否在线状态。手机和硬件设备在服务器看来都是普通客户端用户,它们在服务器上都具有唯一的用户ID,硬件设备登陆服务器时会把获取到IP地址和自己的设备ID告知服务器,服务器记录在数据库上面。而手机要跟硬件设备通信,首先也需要登录到服务器上,然后服务器根据手机的ID识别其对应的硬件设备的ID,并将对应的硬件设目前登录的IP地址告知手机,其后手机可以根据IP地址跟硬件设备建立其TCP/IP通信链路,后续手机跟硬件设备的通信可以通过服务器,也可以绕过服务器直接通过IP地址进行通信。这种设计思想跟腾讯的QQ的设计很类视,比如,手机或者电脑端的QQ软件启动时,先要登录到QQ的后台上,然后在后台登记自己的IP地址和端口号,然后从后台中获取对应好友的IP地址和端口号,之后跟好友的通信就可以绕过QQ的后台了,直接通过UDP或者TCP进行通信。基于独立后台服务的物联架构务的物联架构
这种互联网架构虽然能够实现,但是他要求硬件设备开发商必须独立开发和维护后台的服务器。另外其还需要向购买硬件设备的用户提供手机APP,用户才能够进行远端的硬件控制。如家里的摄像头,厂商需要开发手机APP给用户安装使用。这样,用户每购买一款物联网设备,就需要在自己的手机上安装一款新的APP,容易造成手机上满屏都是APP,从而给用户造成麻烦。而且,各个硬件厂商的后台都是独立的,很难自持第三方的设备接入。
2.4. 基于统一后台服务的物联架构
由2.3基于独立后台服务的物联架构可以联系到,如果有一家大公司或者机构出来统一后台服务器,并被广大用户所接受和认可,然后硬件设备生产商按照一定的协议和接口接入这个平台,那物联网将有一个相对统一的平台。微信的用户基数相当的庞大,而且微信在实现了人与人的通信后,自然会发展到实现人与物,物与物的互联互通。可以相信,微信硬件平台,之后将会是一个很不错的物联网公众平台。
在移动互联网这个独特的领域,用户基数是非常核心的要素,涉及平台相关的服务,没有超大型体量的企业很难快速构建并得到市场和用户的认可。微信公众平台提供的最核心服务便是给各种不同的硬件设备分配唯一的设备ID。微信智能硬件平台的设备ID
手机微信用户需要扫描厂商提供个设备二维码,实现对设备的绑定关系,才能通过分配策略包括公众号ID和设备ID两个部分。设备ID在同一个公众号里面是唯一的。该公众号发出对设备的控制指令和消息。消息经过微信后台后转发给厂商服务器,厂商服务器进行判定和处理后发送给对应的硬件设备。微信公众平台是开放平台,支持第三方服务接入,同时提供微信支付、客服接口、用户管理等九大接口供第三方调用。
由于蓝牙和wifi设备的连接差异,它们在物联网上的架构也有明显的区别。
下图分别是wifi和蓝牙接入微信的框架图:
2.5. 物联网的消息传达机制
基于IP的互联架构已经成为物联网的事实标准,物联网是建立在TCP/IP层之上的,位于OSI五层架构的第五层—应用层。因此可以把基于IP的物联网架构抽象成这样的架构模型:
从应用场景角度看,物联网的最终服务对象是人,而人最直接的与物联网通信的终端就是手机,因此,可以再抽象出这样的模型:物联网设备—云端—手机。其中包括手机和云服务器的双向通信,物联网设备和云服务器的双向通信。
互联网最经典的两种通信模式,无非就是C/S和B/S了,以C/S模式来说,通信前要先建立起TCP连接,即端到端的连接,而且发起连接的必须是客户端,服务器不会主动发起TCP连接。C/S 通信模式,客户端要知道服务器的IP地址和端口号,然后进行三次握手之后才能够建立起连接。一旦连接起立起来后,服务器和客户端的通信就是全双工的双向通信,服务器和客户端可以实现消息的互传,直到这个连接断开之前,都是可以实现双向通信的。所以,可以设想,如果物联网设备能够跟服务器建立起不断开的TCP长连接,那么,物联网硬件设备和服务器就能够实现消息的互传。所以说,C/S模式的架构用在物联网硬件设备和云服务器之间的通信是行得通的,让设备一上电就跟云服务器建立其长连接,这样硬件设备和云服务器就可以实现消息的联通了,无论是服务器推送消息给客户端,还是客户端发送消息给服务器,都可以简单的实现。但是建立长连接对服务器的消耗特别大,如果建立太多长连接,甚至可以把服务器给拖垮,所以建立长连接不是互联网的明智之举,但却又是物联网所需要的。因此,能够避免长连接,就尽量避免,如果真实需求,那就要对服务器加大投入,实现服务器集群功能,对服务器群进行负载均衡策略。这也是为什么微信物联网架构中,要求厂商需要具备自己的厂商云服务器,这样,就不会给微信的后台造成太大的负担。而且虽然C/S模式通过建立TCP长连接能够实现双向通信,但是却需要用户手机上安装一款APP来实现的,试想,不同的厂家各自开发各自的APP,那用户购买不同厂家的产品,必将在手机上安装很多APP,极大的降低了用户的体验度。
而B/S模式,说到底其实也就是C/S模式的一种特例,B/S模式下,客户端不需要安装客户端程序,只需要一个浏览器就可以。最典型的就是HTTP协议了,客户通过浏览器请求服务器,服务器跟客户端建立起TCP连接,服务器根据客户端的请求,返回对应的HTML网页,然后双方就断开TCP连接。这种模式,是当今互联网的主流模式。因为它有效的避免了服务器因为跟客户端建立长连接而给服务器带来的负荷,减轻了服务器的压力。但是,这种模式是单向的,也就是说,服务器要想给客户端发消息,必须得客户端先向服务器请求服务,否则服务器不会任何消息给客户端。所以,在HTTP协议下,要想实现服务器与客户端的双工通信,那必须客户端时时刻刻地去向服务器请求服务,但这样做会导致网页不停的在刷新和闪动。不仅严重影响了物联网的实时性,同时给服务器带来了较大的负担,如果请求的次数过于频繁,量过于多,也会直接把服务器给拖垮掉。很明显,基于HTTP协议的B/S不适合作为物联网的框架。因为B/S模式本质上是单向通信的。
虽然B/S不适合用在物联网框架,但B/S模式有一个优点,那就是用户不需要在手机上安装太多APP,只需要安装一个内置了览器的APP就可以,就相当于我们只在手机上需要安装“淘宝”APP,就可以通过它跟不同的店家购物。同样的思想,如果我们可以只安装一个APP就可以控制和访问各自物联网设备,这将给用户的使用带来极大的便利性,也符合物联网的核心价值。所以B/S模式如果能够融合C/S模式这种能够实现双向通信的方式,那必将给物联网带新的技术体验。这种模式就是websocket。
Websocket 是基于HTML的网页应用层的协议,是能够真正的实现web网页上服务器和客户端浏览器的双向通信的解决方法,因此,websocket是可以实现及时双向通信的模式。其原理也是最后也是基于C/S模式的思想,在实现websocket的连接的时候,客户端浏览器通过发送websocket的连接请求,请求跟服务器建立连接,然后服务器同意连接,这个过程其实就跟建立TCP连接时的三次握手一样。一旦连接建立起来,客户端浏览器和服务器的通信将不再是通过HTTP协议,而是通过websocket协议进行数据的传输。而“微信”APP是内置了支持HTML5的网页的,所以“微信”自然可以承载其作为物联网公众平台的重任。本来这个平台又“百度”来做是最合适不过的了,可是“百度”近几年来的所作所为,没有得到用户的认可,而且百度的APP的用户数量也没有微信的大。
在美国,早在1999年,IBM公司就开发出了能够实现双向传输的消息队列遥测传输技术(MQTT)。MQTT是专门为那些资源和计算能力有限的,其工作在带宽底、不可靠的网络上的传感器及嵌入式设备而设计的。MQTT是建立在TCP/IP连接之上的,有数据丢失重转机制的轻量级的通信协议,已经被许多物联网平台所接纳,已经成为物联网平台的事实上的标准协议了。虽然MQTT跟家适合与独立的开发APP使用,但是,它也支持了浏览器模式。MQTT支持浏览器的方式是通过让websocket通过加载类包的方式实现的,这是,MQTT可以在浏览器端通过JS接口被调用,实现服务器时时的消息推送的功能存在。
而微信硬件开发平台,正是利用MQTT这种支持浏览器的模式来实现物联网平台的大架构的。这样,用户只需要通过安装“微信”这款手机软件,就可以实现对接入微信硬件开发平台的访问和控制了。微信硬件平台,在物联网领域以后可能起着淘宝在电商领域的作用,一统物联网的江湖。
第三章 微信硬件平台环境搭建
3.1. 厂商服务器搭建
根据前面所讲,这里厂商服务器和硬件设备的通信模式是基于C/S架构的,也就是说硬件设备通过跟厂商服务器建立起TCP长连接来实现厂商服务器和硬件设备的双向通信。所以,接入微信硬件平台,开发者需要有自己的服务器,同时厂商服务器需要跟微信硬件平台进行通信,所以要求厂商服务器具备云功能,所谓云功能,就是指厂商服务器必须有一个公网的IP地址和解析这个IP地址的域名。另外,由于手机微信内置了浏览器,所以可以直接通过HTML和JS跟厂商服务器进行双向通信。第一章时候已经介绍了,为什么微信硬件平台需要接入商拥有自己的厂商服务器,目的是为了降低微信后台的直接呀。厂商接入微信硬件平台的架构如图3-1所示:
为了减少开发的难度和开发的周期,这里的厂商云服务器是直接通过购买阿里云服务器实现的。阿里云服务器本身已经具备了云的功能,有一个公网的IP,本次购买的阿里云的IP地址是:114.215.102.241。然后是注册域名,注册到的域名要进行备案,否则被工信部查到,就会被封掉。备案需要花半个月甚至更长的时间,备案后,再用注册的域名解析购买的云服务器的公网IP。这里本来可以不需要用到域名的,但是腾讯公司硬要求开发者必须有域名,否则不可以调用微信硬件平台提供的JSAPI接口。
购买来的云服务器只安装了一个linux操作系统(Ubuntu系统)而且,其他的都需要开发者自己配置。购买到云服务器后,要想操作该服务器,需要远程登录到云服务器上去,然后通过命令行进行操作。我通过securtCRT软件,采用SSH2的协议,登录到云服务器上。如下图3-2所示,是登录界面:
图3-2 登录界面
图3-3是登录后出来的命令行控制界面:
图3-3 登录后的命令控制界面
为了降低开发难度,选择搭建比较简单的LAMP(Linux+Apache+Mysql+PHP)服务器架构。由于Ubuntu系统是自带支持LAMP服务器的,所以只需要通过命令行,就可以安装和配置LAMP服务器。
配置和安装服务器的过程参考《鸟哥的linux私房菜》书的过程。[1]、[2]
3.2. 微信硬件平台的配置
第一步:要在微信硬件平台上申请并注册一个测试号,如图3-4所示,为申请到的测试号:
图3-4 申请到的测试号示意图
其中appID和appsecret是微信后台给申请的测试号分配的ID帐号,后面在申请设备ID和获取系统全局票据access_token的时候需要用到这两个测试号帐号ID。
图3-5 配置接口信息示意图
第二步:配置接口信息,如图3-5所示:
图3-5中的URL指的是:厂商服务器上的存放给浏览器访问的文件地址,比如这里的http://chencanjian.cn/weixin/,这个URL对应到云服务器上的/var/www/html/weixin这个目录下。也就是说微信后台会把从手机微信接受到的信息统统转发到厂商服务器的/var/www/html/weixin文件目录下面,因此,厂商云服务器在该目录下必须要有个后台程序,这个程序的功能就是接收从微信后台转发过来的消息,然后厂商云再把接收到的消息进行处理,判断,进而转发给硬件设备或者返回给微信后台。而这里的Token,类是与一个验证码,由用户自己设定,可以使任何字符,我这里设为:weixin。
在开发者首次提交验证申请时,微信后台将发送GET请求到测试号页面配置的URL上(也就是厂商服务器的/var/www/html/weixin文件目录下),同时带上四个参数(signature、timestamp、nonce、echostr),厂商服务器的后台程序通过对signature参数来确定此条消息的真实性。开发者首次提交申请时,微信后会对“token”、“timestamp”、“nonce”这三个参数按字典顺序进行排序,然后把排序后的字符串赋值给“signature”。
表3-1 参数与描述
参数 |
描述 |
signature |
微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。 |
timestamp |
时间戳,系统自动生产 |
nonce |
随机数,系统自动生产 |
echostr |
随机字符串,系统自动生产 |
厂商云接受到微信后台发过来的这个四个参数后,要进行确认和匹配,匹配通过后,才能够和微信后台建立起联通。厂商云在/var/www/html/weixin文件目录下匹配程序如下所示:
public function valid()
{
$echoStr = $_GET["echostr"];//通过GET获取传递过来的四个参数
$signature = $_GET["signature"];
$timestamp = $_GET["timestamp"];
$nonce = $_GET["nonce"];
$token = TOKEN; //这里是“weixin”
$tmpArr = array($token, $timestamp, $nonce);
sort($tmpArr); //对三个参数安字典顺序排序
$tmpStr = implode($tmpArr);
$tmpStr = sha1($tmpStr);
if($tmpStr == $signature)
{
header('content-type:text');
echo $echoStr;
exit;
}
}
3.3. 添加设备产品
(1)要添加设备产品,需要先开通测试号的设备功能接口,如图3-6所示:
图3-6 设备功能借口示意图
(2)开启设备功能接口后,就可以添加设备产品了,如图3-7所示:
图3-7 添加设备产品示意图
表3-2 产品参数
参数 |
描述 |
产品类型 |
可以根据情况选择 |
连接类型 |
有wifi,蓝牙,移动蜂窝网络,有线,其他网关等 |
产品添加方式 |
有每个设备一个二维码和每种设备一个二维码 |
产品配网 |
Wifi设备选择微信配网,蓝牙设备选择蓝牙发现 |
添加后就可以在首页看到已经添加了的产品的编号,这里的产品编号是“9100”,如图3-8所示:
图3-8 添加产品编号示意图
(3)设备授权
微信硬件平台提供的核心服务就是统一管理接入的硬件设备。因此,通过第2步添加的设备产品,必须向微信后台注册,以得到微信后台的授权。注册时微信后台会给该设备分配一个独一无二的设备ID(设备ID在微信的后台是独一无二的,相当于设备的身份证)。既然设备的ID是代表一个设备的身份,那么设备在微信后台注册的时候就有必要告知微信后台能代表自己的独一无二的信息(设备的MAC地址)。这样,微信后台会把设备的ID号和设备的MAC地址关联起来,以实现设备ID号和设备产品的一一映射关系。
设备授权: 第三方公众账号将设备id及其属性信息提交公众平台进行授权。
接口请求说明:
http请求方式: POST
https://api.weixin.qq.com/device/authorize_device?access_token=ACCESS_TOKEN
POST数据示例如下:
{
"device_num":"1",
"device_list":[
{
"id":"dev1",
"mac":"123456789ABC",
"connect_protocol":"3",
"auth_key":"",
"close_strategy":"1",
"conn_strategy":"1",
"crypt_method":"0",
"auth_ver":"1",
"manu_mac_pos":"-1",
"ser_mac_pos":"-2",
}],
"op_type":"0",
"product_id": "9100"
}
表3-3 设备授权JSON字段与描述
字段 |
必须 |
描述 |
access_token |
是 |
调用接口凭证 |
device_num |
是 |
设备id的个数 |
device_list |
是 |
设备id的列表,json的array格式,其size必须等于device_num |
id |
是 |
设备的deviceid |
mac |
是 |
设备的mac地址 |
connect_protocol |
是 |
支持以下四种连接协议: ios classic bluetooth – 2 ble – 3 wifi -- 4 |
auth_key |
是 |
auth及通信的加密key |
close_strategy |
是 |
断开策略配置 |
conn_strategy |
是 |
连接策略配置 |
crypt_method |
是 |
auth加密方法配置 |
manu_mac_pos |
是 |
表示mac地址在厂商广播manufature data里含有mac地址的偏移 |
ser_mac_pos |
是 |
表示mac地址在厂商serial number里含有mac地址的偏移 |
op_type |
否 |
请求操作的类型 |
product_id |
否 |
设备的产品编号,当 op_type 为‘0’,product_id 为‘1’时,不要填写 product_id 字段(会引起不必要错误); |
如果授权成功,则微信后台会返回一个JSON包,
{
"base_resp":
{"errcode":0,"errmsg":"ok"},
"deviceid":"gh_e2f2b5dbd590_de17a0bc80245f0a",
"qrticket":"http://we.qq.com/d/AQAsDAqzM-SP_YZYmXKDUjC05SBaOFwiCJibu2X0"
}
其中,deviceid是该设备授权得到的设备ID,在微信后台是独一无二的;qrticket字段是该设备的二维码。通过二维码生产器,可以生产一个唯一的二维码,用户只需要用微信的扫一扫功能扫一下这个二维码,就可以实现对设备的绑定了。上面的qrticket字段生产的二维码如图3-9所示:
图3-9 二维码
3.4. 测试号的菜单栏设计
(1)菜单的设计
菜单的设计如图3-10所示,其中,一级菜单三个,分别是“操作”,“设备选择”和“查询设备”;一级菜单下面有二级菜单,(二级菜单最多只能有5个)比如上图所示的二级菜单有“总设备数”, “总设备数”, “目前选定”, “设备状态”, “设备管理”, “设备1”, “设备2”, “设备3”, “设备4”, “设备5”。设定菜单的时候,需要条用微信硬件平台创建菜单的API接口:
https://api.weixin.qq.com/cgibin/menu/get?access_token=ACCESS_TOKEN
图3-10 菜单设计示意图
(2)设置菜单的JSON代码:
{
"button": [{
"name": "操作",
"sub_button": [{
"type": "click",
"name": "启动",
"key": "open"
},{
"type": "click",
"name": "关闭",
"key": "close"
}] },
{
"name": "设备选择",
"sub_button": [{
"type": "click",
"name": "设备1",
"key": "dev1"
}, {
"type": "click",
"name": "设备2",
"key": "dev2"
},{
"type": "click",
"name": "设备3",
"key": "dev3"
}, {
"type": "click",
"name": "设备4",
"key": "dev4"
},{
"type": "click",
"name": "设备5",
"key": "dev5"
}]},
{
"name": "查询设备",
"sub_button": [{
"type": "click",
"name": "总设备数",
"key": "devnum"
},{
"type": "click",
"name": "目前选定",
"key": "usenum"
}, {
"type": "click",
"name": "设备状态",
"key": "stat"
},{
"type": "view",
"name": "设备查询",
"url": "http://chencanjian.cn/php/index.php"
}]}]}
表3-4 设置菜单JSON字段与描述
参数 |
是否必须 |
描述 |
button |
是 |
一级菜单,个数最多三个 |
sub_button |
否 |
二级菜单,个数最多5个 |
type |
是 |
菜单的相应类型 |
name |
是 |
菜单的标题 |
key |
Click点击必备 |
菜单的KEY值,用于消息接口 |
url |
View类型必备 |
网页连接,用户指定url网页 |
media_id |
Media类型必备 |
获取多媒体材料的media_id |
本章总结:
本章通过研究微信硬件平台的架构,搭建出了厂商服务器,并在微信的后台对设备进行注册和授权。用户只需要打开手机的微信扫一扫设备的二维码,即可跟设备实现绑定的关系,进而可以通过微信的公众号对设备进行控制和访问。
第四章 微信硬件平台的开发和WEB设计
4.1. 测试号的开发
4.1.1. 测试号后台消息收发的原理和架构
根据第三章的“微信硬件平台的配置”,我们知道,当微信后台接收到测试号发来的任何消息的时候,都会无条件的将这信息转发给厂商云服务器的URL目录下。当厂商服务器接收到微信后台转发过来的消息后,接受下来,并进行处理,然后返回一个结果微信后台,微信后台再转发到手机微信上。数据的传输如图4-2所示:
从图可以直观的看出来,当手机微信测试号发送了一个“?”的时候,微信后台服务器接受到这个消息“?”,然后组织一段XML数据转发给厂商服务器,厂商服务器接收到这段XML数据后,从中提取出有用的消息,然后对该消息进行处理。处理完后把结果也组菜单的设计织成XML数据包,回复给微信后台服务器,微信后台接收到这可XML数据包后,从中提取出有用的消息,再推送给手机微信测试号。如图4-1所示:
图4-1 收发数据示意图
4.1.2. 厂商服务器消息接收程序
由4.1.1可知,微信后台将手机微信发送的消息组成成XML包,然后POST给厂商服务器。而XML包,有<MsgType><![CDATA[text]]></MsgType>这样一条记录元素,用来描述此数据包的消息类型,微信总共定义了9条消息类型:
表4-1 9种消息类型
消息类型 |
XML参数 |
描述 |
文本消息 |
text |
表明此条消息是文本,字符或者表情 |
图片消息 |
image |
表明此条消息是一张图片 |
语音消息 |
voice |
表明此条消息是语音 |
视频消息 |
video |
表明此条消息是视频 |
事件消息 |
event |
表明此条消息是菜单栏的按键 |
地理位置消息 |
location |
表明此条消息是位置坐标 |
连接消息 |
link |
表明此条消息是一个链接 |
设备文本消息 |
device_test |
表明此条消息是通过硬件设备发过来的文本消息,用于蓝牙设备 |
设备事件消息 |
device_ event |
表明此条消息是通过硬件设备发过来的事件消息,用于蓝牙设备 |
这样,厂商服务器根据微信后台转发过来的消息先进性分类,然后针对不同的消息类型,设计不同的处理算法出去处理这些消息。下面给出消息分类处理的算法程序:
public function responseMsg()
{
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
if (!empty($postStr))
{
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$RX_TYPE = trim($postObj->MsgType);
//消息类型分离
switch ($RX_TYPE)
{
case "event":
$result=$this->receiveEvent($postObj);//处理事件消息的模块
break;
case "text":
$result = $this->receiveText($postObj); //处理文本消息的模块
break;
case "image":
$result = $this->receiveImage($postObj); //处理图片消息的模块
break;
case "location":
$result=$this->receiveLocation($postObj); //处理位置消息的模块
break;
case "voice":
$result = $this->receiveVoice($postObj); //处理语音消息的模块
break;
case "video":
$result = $this->receiveVideo($postObj); //处理视频消息的模块
break;
case "link":
$result = $this->receiveLink($postObj); //处理连接消息的模块
break;
case "device_test":
$result = $this->receiveDevice_test ($postObj); //处理设备文本消息的模块
break;
case "device_event":
$result = $this->receiveDevice_event ($postObj); //处理设备事件消息的模块
break;
default:
$result = "unknown ms0g type: ".$RX_TYPE;//处理未知消息
break;
}
echo $result; //在控制台答应result的值
echo $xmlTpl; //在控制台答应xmlTpl的值
}else{
echo "";
exit;
}}
4.1.3. 厂商服务器处理文本消息程序
根据4.1.1的内容,手机微信发送“?”,经过微信后台转发到厂商服务器后,厂商服务器对这个消息进行分类,这里是文本消息,所以选择文本处理程序对这个文本消息进行处理。那么厂商服务器是怎么处理这个“?”文本消息的呢?如下面的程序所示:
private function receiveText($object)
{
$keyword = trim($object->Content);
if (strstr($keyword, "?"))
{
$content = "你发的是:?";
}
$result = $this->transmitText($object, $content);
return $result;
}
上面的程序中的receiveText函数的参数object,其实就是微信后台转发过来的XML包。这个XML包里面包含<ToUserName>(这里的ToUserName指的是我的测试号),<FromUserName>(这里的FromUserName指的是来用户的OpenID),<Content >(这里的Content指的是所发送过来的文本信息内容)。厂商服务器对这个文本消息处理后,通过transmitText函数,把处理得到的结果返回给微信后台。
transmitTex函数的源代码如下所示:
private function transmitText($object, $content)
{
$xmlTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
$result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time(), $content);
return $result;
}
transmitText函数的参数,一个是微信后台转发过来的XML包,一个是文本处理程序处理后得到的结果。从上面的程序,可以看出,厂商服务器也是把返回消息组织成XML包发给微信后台的。只不过这个时候,FromUserName,和ToUserName发送了互换,原来的接受者变成了发送者,原来的发送方变成了接受方。所以,本质上微信硬件平台的消息互动也就是一个B/S模式的通信,即客户端(手机微信)发起请求,厂商服务器返回一条相应该请求的消息。而我们在第一章就提过,B/S模式用在物联网架构里,可以减少用户安装手机APP的数量,甚至只需要安装一个手机APP,就能实现跟多个物联设备的交互。这也是微信微信硬件平台统一整个物联网大平台的原理基础。
4.1.4. 厂商服务器处理多媒体消息消息程序
多媒体消息的主要特点就是,相比与文本消息,它们的信息量和数据数据量都很庞大,多媒体消息包括语音,图像,视频等。虽然它们各自有对应的处理程序,但是微信后台对他们的转发机制几乎是相同的,所以在这里把它们统一的归类为多媒体消息的处理。 微信后台对多媒体文件的处理是这样的,微信后台会把用户发送的语音,视频,图片等多媒体先存储在微信后台上,然后给这些多媒体文件分配一个在后台独一无二的消息ID号。这样,当微信用户甲给微信用户乙发一个多媒体消息时,甲的消息先存储在微信的后台上,然后后台再把这个消息ID号发送给用户乙。如果用户乙想看这个多媒体文件,那么他就要根据这个消息ID从微信后台下载这个多媒体文件到自己的手机上。这样实现的好处就是,当用户不想看这个多媒体文件时,就不需要去下载,可以节省用户的流量;另一方面,微信后台只要转发这个多媒体文件的消息ID给用户即可,因为多媒体文件一般都是比较大,转发一个大文件,对后台的消耗是很大的,而这种先存储下来,再转发数据量非常少的消息ID,可以大大的降低微信后台的负担。不过,微信后台对这中临时存储的多媒体的时间是有期限的,只有3天,也就是说,3天内不下载下来,微信后台就会这个多媒体文件给删除掉,以腾出更多的空间来存储其他的多媒体文件。
有了上面的介绍,接着讲微信后台转发这些多媒体消息到厂商服务器就比较容易了。当用户给测试号发送图片时,微信后台会先把这张图片保存起来,然后再把消息ID转发给厂商服务器。厂商服务器收到微信后台转发过来的这个关于图片消息的XML数据包后,从中攫取出图片的消息ID,然后判断该用户所绑定的设备是否在线,若设备在线,则厂商服务器先把这张图片下载到厂商服务器上,然后再通过TCP/IP协议把图片消息发送给物联设备。这样就实现了用户把图片,语音,视频发给硬件设备的功能了。
下面是厂商服务器处理图片消息和下载存储图片消息的源程序:
private function receiveImage($object)
{
$content = array("MediaId"=>$object->MediaId);
$result = $this->transmitImage($object, $content);
return $result;
}
private function transmitImage($object, $imageArray)
{
$who = $object->FromUserName;
$con=mysqli_connect("localhost","root","051230","weixin");
$str_con = "SELECT * FROM table1 WHERE use_name='$who'";
$result = mysqli_query($con,$str_con);
while($row = mysqli_fetch_array($result))
{$device_id = $row['device_id'];}
$con=mysqli_connect("localhost","root","051230","weixin");
$str_con = "SELECT * FROM table2 WHERE dev_name='$device_id'";
$result = mysqli_query($con,$str_con);
while($row = mysqli_fetch_array($result))
{$server_root = $row['server_root'];}
mysqli_close($con);
$trace_of_picture_id = "/var/www/html/weixin/voice/device".$server_root."/media_id_picture.txt";
$file=fopen($trace_of_picture_id,"w+");
fwrite($file,$imageArray['MediaId']);
fclose($file);
$itemTpl = "<Image><MediaId><![CDATA[%s]]></MediaId></Image>";
$item_str = sprintf($itemTpl, $imageArray['MediaId']);
$xmlTpl = "<xml> <ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
$item_str</xml>";
$result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time());
$trace_save_picture = "114.215.102.241/weixin/voice/device".$server_root."/save_picture.php";
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL,$trace_save_picture);
curl_setopt($curl, CURLOPT_HEADER, 1);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$data = curl_exec($curl);
curl_close($curl);
$trace_of_what_media = "/var/www/html/weixin/voice/device".$server_root."/what_media.txt";
}
从上面的源程序可以看出receiveImage函数先把图片消息XML包中消息ID截取出来,然后转交给transmitImage函数进行处理。transmitImage函数处理的内容包括,从XML包中截取出FromUserName,根据FromUserName可以知道本条消息是哪个用户发送过来的。接着以FromUserName为主键在本地数据库(厂商云上的数据库,这里先不介绍数据库的设计,下面再具体的解释)中查找这个用户所绑定的设备号,然后根据设备号在数据库中查找出其对应的设备文件存储地址:这里的设备文件地址是这个:/var/www/html/weixin/voice/device".$server_root."/media_id_picture.txt,其中每个设备对应一个server_root(server_root是一个整形变量)。然后把消息的消息ID保存到这个目录下面的media_id_picture.txt文件中。而且,这里我给测试号返回的消息也是这哥图片的消息ID,当手机微信接收到这个消息ID后,就会显示有图片信息过来,然后点击该图片信息,就可以对该图片进行下载。紧接着是调用下载图片数据的PHP程序,PHP程序调用PHP程序的原理就是通过模拟客户端的请求,这里我通过curl_init()函数来模拟这个请求过程。最后,告知设备的服务器端程序,表示有消息需要传递。厂商服务器和设备的消息传递我在第四章会进行更加详细地介绍。
4.1.5. 厂商服务器下载多媒体文件
通过上面4.1.4的介绍,我们知道厂商服务器要下载多媒体文件,只需要知道这个多媒体文件在微信后台的消息ID号就可以下载。在微信后台下载多媒体文件是通过HTTP协议的GET方式进行请求下载的,下载的连接是:"http://file.api.weixin.qq.com/cgibin/media/get?access_token=".$access_token."&media_id=".$mediaid”。下载链接里面包含了两个参数,分别是access_token和media_id。这两个参数的说明如下表格所示:
表4-2 下载多媒体的链接地址参数
参数 |
是否必须 |
说明 |
access_token |
是 |
调用接口的凭证 |
media_id |
是 |
多媒体文件消息ID |
下面是下载多媒体文件消息的源程序:
$url = "http://file.api.weixin.qq.com/cgibin/media/get?access_token=".$access_token."&media_id=".$mediaid;
$fileInfo = downloadWeixinFile($url);
$filename = "my.jpg";
saveWeixinFile($filename, $fileInfo["body"]);
function downloadWeixinFile($url)
{
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_NOBODY, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$package = curl_exec($ch);
$httpinfo = curl_getinfo($ch);
curl_close($ch);
$imageAll = array_merge(array('header' => $httpinfo), array('body' => $package));
return $imageAll;
}
function saveWeixinFile($filename, $filecontent)
{
$local_file = fopen($filename, 'w+');
if (false !== $local_file){
if (false !== fwrite($local_file, $filecontent))
{fclose($local_file);}
}
}
从上面的源程序,可以看出,从微信后台下载多媒体消息文件的方式也是通过用curl_init函数来模拟的HTTP请求。通过downloadWeixinFile函数下载图片的内容,包括http的头信息(不是我们需要的,但确实应用层http协议所必须的),还有http获得的body,这部门就是我们所需要的图片信息数据。接着调用saveWeixinFile函数把这个body保存到指定的文件中。这样就完成了厂商服务器下载多媒体文件消息的功能了。
4.1.6. access_token值的获取和保存
通过前面的介绍,我们知道,无论是要创建菜单栏,设备的授权,还是上传和下载图片消息,都需要用到access_token,究竟access_token是什么呢?为何如此的重要?所以介绍一下access_token还是相当有必要的。
根据微信官方的介绍,设置这个access_token值的目的是为了保密appserect,增强测试号的保密性和安全性。access_token值跟appserect是有有关系,因此,获取access_token值的时候,就需要调用到appid和appserect。而appid和appserect,正是一个测试号的帐号和密码,在前面已经讲过了。access_token是整个微信硬件平台的全局唯一票据,测试号调用很多接口都需要用到这个access_token值。但是微信后台对access_token值的获取是有限制的,每个测试号每天最多只能够获取2000次,每次获取到的access_token的有效持续时间是7200秒。如果每次调用各自接口的时候都要重新获取access_token值,那显然每天2000次的获取次数是远远不够的。所以要把每次获取到的access_token值先保存起来,然后每隔最多不超过7200秒重新获取access_token的值,替换掉原来旧的access_token值是很有必要的。
access_token值的获取是通过http的GET的请求方式向微信后台获取的,请求的链接地址是:https://api.weixin.qq.com/cgibin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
表4-3 获取access_token连接的参数
参数 |
是否必须 |
参数说明 |
grant_type |
是 |
获取access_token填写client_credential |
appid |
是 |
第三方用户唯一凭证 |
secret |
是 |
第三方用户唯一凭证密钥,既appsecret |
如果获取成功,微信后台会返回一个JSON数据包回来:{"access_token":"ACCESS_TOKEN","expires_in":7200}
表4-4 返回参数说明
参数 |
描述说明 |
access_token |
获取到的凭证 |
expires_in |
凭证有效时间,单位:秒 |
获取和保存access_token值的源程序如下所示:
public function token()
{
$servername = "localhost";
$username = "root";
$password = "051230";
$dbname = "weixin";
$conn = new mysqli($servername, $username, $password, $dbname); // 创建连接
$sql = "SELECT * FROM wx_token";/*选择数据库的表*/
$result = $conn->query($sql);
if ($result->num_rows > 0)
{
while($row = $result->fetch_assoc())
{
$access_token = $row['value'];
$expires_time = $row['expire'];
}
}
if (time() > ($expires_time + 3600))
{
$appid = "wx0144ee4e584f26c0";
$appsecret = "d4624c36b6795d1d99dcf0547af5443d"; $url="https://api.weixin.qq.com/cgibin/token?grant_type=client_credential&appid=$appid&secret=$appsecret";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
curl_close($ch);
$jsoninfo = json_decode($output, true);
$access_token = $jsoninfo["access_token"];
$expires_time = time();
$conn->query("UPDATE wx_token SET expire = '$expires_time',value = '$access_token' WHERE type='access_token'");
mysqli_close($conn);
}
}
上面的源程,每3600秒从微信后台获取一个access_token值,然后把获取到的新access_token值替换掉数据库里面的旧的access_token值。这样,当测试号程序在接口调用时需要用到这个access_token值,就直接从数据库里面获取。
4.1.7. 微信后台的消息推送机制客服接口
微信后台的消息推送做的不是很好,根据微信官方的说辞,是为了怕对用户造成骚扰,所以限制了测试号的消息推送,比如,微信的公众号平台,先知开发者一天只能够群发一条消息。微信后台的消息推送有两种,一种是模版消息推送,另一种是客服接口消息推送。两种各有优缺点,相辅相成。本次开发主要用的是客服接口的消息推送机制,所以这里重点介绍的是客服接口的消息推送。
当用户给微信测试号发送任何消息时,包括文本,多媒体,连接等,那开发者在48小时内可以通过调用客服接口,给该用户发送任何消息。但前提是用户在48小时内有过一次消息发送操作。而消息模版着没有48小时这个限制,所以一般开发时都是先发送消息模版通知用户,硬件设备有消息要发送过来,请输入任何消息进行确认。待用户确认后,厂商服务器就可以将硬件设备要发送给手机微信用户的消息通过调用客服接口发送出去了。所以消息模版起到其实用户接收消息的作用,而客服接口起到推送消息的作用,是相辅相成的。
客服接口的链接地址是:https://api.weixin.qq.com/cgibin/message/custom/send?access_token=ACCESS_TOKEN
客服接口可以发送的消息类型有:文本消息,图片消息,语音消息,视频消息,音乐消息,图文消息,几乎涵盖了所有的消息类型了,不够的话可以自己进行组成。其中发送文本消息和其他多媒体消息之间有点区别,跟前面说过的手机微信发送文本消息和多媒体消息给厂商服务器的区别一样,只不过这里是手机微信到厂商服务器的逆过程而已。
客服接口发送数据是封装成JSON包的,然后通过POST请求,发送给微信后台,微信后台再推送给手机微信。当要推送消息是文本消息时,直接把文本消息的内容包含进JSON包。而如果要推送的消息是多媒体消息时,则要先把该多媒体文件上传到微信的后台服务器上,并从微信后台获取该多媒体消息的消息ID,厂商服务器只需要把这个消息ID包含进JSON包,然后调用微信后台的客服接口,微信后台就会把这个消息ID推送给手机微信。
下面介绍一下文本消息和图片消息的JSON包的组织:
文本消息JSON包:
{
"touser":"OPENID",
"msgtype":"text",
"text":
{"content":"这是一个文本消息"}
}
表4-5 客服接口文本消息JSON字段与说明
字段 |
是否必须 |
说明 |
access_token |
是 |
调用接口凭证 |
touser |
是 |
普通用户openid |
msgtype |
是 |
消息类型,text |
content |
是 |
文本消息内容 |
图片消息JSON包:
{
"touser":"OPENID",
"msgtype":"image",
"image":
{"media_id":"MEDIA_ID"}
}
表3-6 客服接口图片消息JSON字段与说明
参数 |
是否必须 |
说明 |
access_token |
是 |
调用接口凭证 |
touser |
是 |
普通用户openid |
msgtype |
是 |
消息类型,image |
media_id |
是 |
发送的图片的媒体ID |
4.2. 数据库的设计
本次开发使用的数据库是MYSQL,一款轻量级的关系型数据库。前面在搭建厂商云服务器的时候已经介绍过了,mysql数据库在Ubuntu系统上的安装。在安装过程中,mysql会要求你输入root(mysql数据库的root用户,跟linux的root用户不是同一个概念)用户的密码。而且只有root用户才能够在mysql数据库里创建数据库和数据表。Ubuntu上面登录到mysql的命令是:mysql –uroot –p051230 这里我的数据库的密码是051230。
先在mysql里创建一个数据库,创建命令是:create database weixin;如图4-3所示,这里的weixin数据库就是刚刚通过这条创建命令创建出来的。
图4-3 数据库
接着进入weixin数据库,在这个数据库下面创建本次项目需要的用的3个表格。第一个表是用来存放获取到的access_token值的表;第二个表用来几乎关注该测试号的用户信息;第三个表用来记录硬件设备的ID号和设备登录的帐号跟密码。三个数据表的设计分别如下所示。
第一个表wx_token创建命令:
create table wx_token
(
expir varchar(255);
value varchar(255);
);
这里,expire用来存储获取access_token时的时间,value列用来存储获取到的access_token值。这样,当调用接口需要使用到access_token的值的时候,就从weixin这个数据库的wx_token表中获取value的值。
第二个表用table1创建命令:
create table table1
(
use_name NOT NULL PRIMARY KEY varchar(255);
select_dev int;
hei_ming_dan char;
device_id varchar(255);
);
这里,use_name就是关注该测试号的所有的用户的opneid; select_dev是根据用户具体绑定的设备数量,然后选择当前想要控制的是自己绑定的第几台设备,这里是一个整形值,当用户没有绑定任何设备时,这个值为0;device_id 是该用户目前想要控制的硬件设备的设备号ID;hei_ming_dan是表示该用户是否被设备的主人(超级用户)拉黑,若拉黑,这里的值为1,否则为0。
第三个表table2创建命令:
create table table2
(
dev_name NOT NULL PRIMARY KEY varchar(255);
zhanghao NOT NULL varchar(255);
mm NOT NULL varchar(255);
main_use NOT NULL varchar(255);
server_root NOT NULL varchar(8);
);
这里,dev_name就是授权后得到设备ID号,每授权一个设备,就把得到的设备ID保存在这里;zhanghao和mm是这个设备的管理帐号和密码,用来删除和拉黑绑定该设备用的;main_use指的是这个设备的主人,拥有比其他普通用户更多的控制设备的权利,也就是超级用户,但通过登录帐号和密码,可以修改这个主用户;server_root是存放该设备的收发的消息的文件夹,每一个设备都拥有自己独立的设备文件夹,文件里缓存用户的操作和发送给这个设备的消息。
4.3. WEB相关的设计和网页的开发
有了4.2数据库的介绍,下面介绍WEB相关的开发就容易多了,因为WEB相关的部分很多都要设计到数据库和对数据库的操作。
前面讲过,测试号的菜单栏上有这样四个二级菜单:“总设备数”,“目前选定”,“设备状态”,“设备管理”。其中,“总设备数”实现的功能是查询用户所绑定的所有设备和设备数;“目前选定”是查询用户当前选择操作的设备号,就是前面数据库里面table1表的select_dev的值;“设备状态”用于查询选中的该设备是否在线;“设备管理”实现的功能是切换到一个指定的网页上,用户输入设备的帐号和密码,就可以实现对设备的配置(接触绑定该设备的用户,拉黑操作等)。
4.3.1. 查询用户绑定的设备总数
查询用户绑定的设备数,可以调用微信后台提供的接口:
调用接口说明:
http请求方式: GET
https://api.weixin.qq.com/device/get_bind_device?access_token=ACCESS_TOKEN&openid=OPENID
请求的GET参数如表4-7所示:
表4-7 查询用户绑定情况的链接参数
参数 |
是否必须 |
描述 |
access_token |
是 |
调用接口凭证 |
opened |
是 |
需要查询的用户的openid |
返回结果如下所示:
{
"resp_msg": {
"ret_code": 0,
"error_info": "ok"
}, "openid": "oLAwKs5YWG77oYXu2jt24KQfK7Mo",
"device_list": [{
"device_type": "gh_e2f2b5dbd590",
"device_id": "gh_e2f2b5dbd590_7b4e6f8b9ded723c",
"sub_device_list": [ ]}, {
"device_type": "gh_e2f2b5dbd590",
"device_id": "gh_e2f2b5dbd590_4356c6614a2ad359",
"sub_device_list": [ ]
}]
}
从上面返回回来的JSON device_list字段可以看出,给用户目前绑定了两个设备,分别是:"gh_e2f2b5dbd590_7b4e6f8b9ded723c"和"gh_e2f2b5dbd590_4356c6614a2ad359"。所以,只要判断返回的device_list里面包含的设备,就可以得出该用户所绑定的设备数量了。
用户只要点击测试号菜单栏里的“总设备数”,微信后台就会根据该用户,并调用获取用户绑定设备情况的后台接口,查询用户所绑定的设备情况,并把结果返回给手机微信。如图3-4所示,是用户查询绑定的设备数后所返回的结果:
图4-4 查询用户绑定设备界面
图4-4表示这个用户只绑定了一个设备,这个设备的设备号是:gh_e2f2b5dbd590_7b4e6f8b9ded723c。
实现上面的功能的代码如下所示:
case "devnum":
$conn = new mysqli("localhost","root", "051230", "weixin");// 创建连接
$sql = "SELECT * FROM wx_token";/*选择数据库的表*/
$result = $conn->query($sql);
if ($result->num_rows > 0)
{
while($row = $result->fetch_assoc())
{
$access_token = $row['value'];
$expires_time = $row['expire'];
}
}
$user=$who;
$curl = curl_init();
curl_setopt ($curl, CURLOPT_URL, 'https://api.weixin.qq.com/device/get_bind_device?access_token='.$access_token.'&openid='.$user);
curl_setopt ($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
$re = curl_exec($curl);
curl_close($curl);
$jsoninfo = json_decode($re, true);
$nn = $jsoninfo["device_list"];
$count_dev = count($nn);
$tmp = 0;
$content = "您绑定的设备总共有".$count_dev."台 ";
for(;$tmp<$count_dev;$tmp++)
{
$tt = $tmp+1;
$content = $content."设备$tt : ".$nn[$tmp]["device_id"]." ";
}
$content = $content."请选择您想连接的设备号。";
if(!$count_dev)
{$content = "你还没绑定设备哦";}
/*如果没有表2中没有这个设备号,那就插入这个设备号,并且默认的设备主人是我自己的微信号*/
$sql = "SELECT * FROM table1 where use_name='$who'";
$result = $conn->query($sql);
/*输出表的数据*/
if ($result->num_rows > 0)
// 输出每行数据
{
while($row = $result->fetch_assoc())
{$device_id = $row['device_id'];}
}
$sql = "SELECT * FROM table2 where dev_name='$device_id'";
$result = $conn->query($sql);
/*输出表的数据*/
if ($result->num_rows > 0)
{
while($row = $result->fetch_assoc())
{$main_use = $row['main_use'];}
}
if($main_use==null)
{
$sql = "insert into table2(dev_name,zhanghao,mm,main_use,server_root) values('$device_id','$device_id','123456','oLAwKsyOg8jIdzG9oL5u8oVs1KNc',2)";
$result = $conn->query($sql);
$content ="正在插入设备!";
}
break;
从上面的源程序可以看出,要调用查询用户绑定设备情况的接口,需要从数据库里取出access_token的值。根据返回的JSON包的device_list字段,得知用户绑定的设备数和绑定的设备ID,以文本消息发送回给手机微信。如果没用没有绑定任何设备,则返回“你没有绑定设备哦”的文本给用户。如果这个设备的设备号还有没有记录在table2表中,那么调用数据库的插入语句,把这个设备的设备号插入到数据库中。
4.3.2. 查询用户当前选得的设备的情况
查询设备的情况,可以调用微信后台提供的接口:
调用接口说明:
http请求方式: GET
请求的GET参数如表4-8所示:
表4-8 查询设备的绑定情况链接参数
参数 |
是否必须 |
描述 |
access_token |
是 |
调用接口凭证 |
device_type |
是 |
设备类型,目前为测试号的原始ID |
device_id |
是 |
设备的deviceid |
返回JSON包如下所示:
{
"open_id":["omN7ljrpaxQgK4NW4H5cRzFRtfa8","omN7ljtqrTZuvYLkjPEX_t_Pmmlg",],
"resp_msg":{"ret_code":0,"error_info":"get open id list OK!"}
JSON包中的open_id字段,包含了绑定该设备的所有用户的openid,所以只要查询该字段里面的用户数量,就可以知道目前该设备被多少个用户所绑定。}
图4-5 设备的绑定情况界面
用户只要点击测试号菜单栏里的“目前选定”按钮,厂商服务器会根据数据库里的table1表查看目前该用户选定的是哪一个设备,然后得到这个设备的设备ID号,从wx_token表中取出access_token,然后调用微信后台获取设备绑定情况的接口,就可以得到绑定该设备的所有用户和用户的数量,并把结果以文本的形式组织起来,返回给手机微信。如图4-5所示,是用户查询目前选定下的设备绑定情况所返回的结果:
返回的消息有:目前用户所选得的设备号,和该设备号的设备ID,同时可以看到该设备目前被三个用户所绑定,和主用户。
实现上面的功能的代码如下所示:
case "usenum":
$conn = new mysqli("localhost","root", "051230", "weixin");// 创建连接
$sql = "SELECT * FROM wx_token";/*选择数据库的表*/
$result = $conn->query($sql);
if ($result->num_rows > 0)
{
while($row = $result->fetch_assoc())
{
$access_token = $row['value'];
$expires_time = $row['expire'];
}
}
$user=$who;
$sql = "SELECT * FROM table1 where use_name='$who'";
$result = $conn->query($sql);
if ($result->num_rows > 0)
{
while($row = $result->fetch_assoc())
{
$device_id = $row['device_id'];
$select_dev = $row['select_dev'];
}
}
$curl = curl_init();
curl_setopt ($curl, CURLOPT_URL, 'https://api.weixin.qq.com/device/get_openid?access_token='.$access_token.'&device_type=gh_e2f2b5dbd590&device_id='.$device_id);
curl_setopt ($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
$re = curl_exec($curl);
curl_close($curl);
$jsoninfo = json_decode($re, true);
$use_num= count($jsoninfo["open_id"]);
$tmp = 0;
$content = "您选择的设备号为:".$select_dev." 设备的ID号是:".$device_id." 总共被". $use_num."人绑定着 ";
for(;$tmp<$use_num;$tmp++)
{
$tt = $tmp+1;
$content = $content."用户$tt : ".$jsoninfo["open_id"]["$tmp"]." ";
}
$nn = $jsoninfo["open_id"]["0"];
$nn1 = $jsoninfo["open_id"]["1"];
$sql = "SELECT * FROM table2 where dev_name='$device_id'";
$result = $conn->query($sql);
if ($result->num_rows > 0)
{
while($row = $result->fetch_assoc())
{$main_use = $row['main_use'];}
}
$content = $content."主用户是: ".$main_use;
break;
从上面的源程序可以看出来,调用接口前也是需要先从数据库中获取到access_token值,然后根据用户目前选得的设备ID和测试号的原始ID。把调用接口后返回的接口组织成文本的信息返回给手机微信。
4.3.3. 用户选择设备
用户根据绑定的设备数,可以选择自己绑定的任意一个设备。如图4-6所示:
图4-6 选择设备界面
图4-6的用户绑定这着两个设备,设备1是:gh_e2f2b5dbd590_7b4e6f8b9ded723c,设备2是:gh_e2f2b5dbd590_19d93a3f9f7aac17。当用户选择设备1和设备2的时候都可以成功的选定,但是选择设备3的时候,后台会告诉用户,您没有设备3这个设备,所以选定失败。
图4-7 厂商服务器后台数据库table1表
从数据库的table1中可以看出,当前oLAwKsyOg8jIdzG9oL5u8oVs1KNc用户选择的是设备2,设备号是:gh_e2f2b5dbd590_19d93a3f9f7aac17。
那么选择后台的源程序所完成的功能也就是先查询该用户所绑定的所以设备,然后根据用户先要选择的设备号,在数据库中的table1表中记录下来。只有用户对测试号发送的任何消息,厂商服务器后台都会默认的把这个消息发送给用户当前所选择的设备号的设备ID。这也是本次项目实现一个用户控制多个物联设备的原理。当然,不同的用户可以同时选择相同的设备,对同一个设备进行控制和操作。下面是厂商服务器后台用户选择设备的源程序。
case "dev2":
// 创建连接
$conn = new mysqli("localhost","root", "051230", "weixin");
/*选择数据库的表*/
$sql = "SELECT * FROM wx_token";
$result = $conn->query($sql);
/*输出表的数据*/
if ($result->num_rows > 0)
{
// 输出每行数据
while($row = $result->fetch_assoc())
{
$access_token = $row['value'];
$expires_time = $row['expire'];
}
}
$user=$who;
$curl = curl_init();
curl_setopt ($curl, CURLOPT_URL, 'https://api.weixin.qq.com/device/get_bind_device?access_token='.$access_token.'&openid='.$user);
curl_setopt ($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
$re = curl_exec($curl);
curl_close($curl);
$jsoninfo = json_decode($re, true);
$nn = $jsoninfo["device_list"];
$count_dev = count($nn);
if($count_dev>=2)
{
$nn = $jsoninfo["device_list"];
$id=$nn["1"]["device_id"] ;
$con=mysqli_connect("localhost","root","051230","weixin");
$str_con = "SELECT * FROM table1 WHERE use_name='$who'";
$result = mysqli_query($con,$str_con);
$str_con = "UPDATE table1 SET select_dev=2,device_id='$id' WHERE use_name='$who'";
$result = mysqli_query($con,$str_con);
mysql_close($con);
$content = "成功选择设备2";
}else
{
$content = "选择失败 "."您没有设备2!" ;
}
break;
以上源程序实现的功能是,先调用微信后台的接口查询用户所绑定的用户数量,如果用户绑定的数量小于用户当前想要选择的设备号。比如用户只绑定两个设备,但是确想选择设备3,那肯定就会选择失败,但是用户可以选择设备1和设备2。也就是说选择的设备号数要小与或等于用户所绑定的设备数量。否则无法选中和切换。如果选择成功,那么厂商服务器后台的数据库会记录下该用户当前切换的 设备号和设备ID,之后用户的任何操作,厂商服务器后台都会默认用户是对他当前选得的设备的操作。
4.3.4. 用户管理设备
测试号菜单栏中有这样一个按钮,是“设备管理”,当用户点击该按钮是,测试号会跳转到一个指定的网址上。这里,指定的网址是http://chencanjian.cn/lianxi/weixin/denglu.php。因为微信内嵌了支持HTML5的浏览器,所以,点击这个按钮,就相当于浏览器访问指定的网址。
点击该按钮后,会跳转到这样一个页面,如图4-8所示:
用户输入设备的帐号和密码,就可以登录进对设备进行管理的网页。这里的设备帐号和密码,指的是前面介绍过的数据库table2表中的zhanghao和mm。当用户输入了正确的帐号和密码,该网页的后台程序会把用户输入的帐号和密码通过表单的形式POST到下一张网页的程序。登录后的网页如图4-9所示:
看以看出,该设备在厂商服务器的server_root号是2,也就是表格的第一行数据,还有绑定该设备的用户数,和每一个用户的OpenID与他们的微信名。如果点击踢出按钮,则该程序会调用微信后台的接触绑定的接口,将设备和该用户接触绑定。WEB的程序详细的请见附录,这里不再做介绍。这里以踢出用户1“火山”为例。提出后会跳转到另一个网页,告诉用户踢出是否成功,如图4-10所示。
提交成功后通过返回按钮,返回到首页,如图4-11所示:
图4-11 接触绑定关系后返回的界面
提出了用户“火山”后,设备的设备用户数从3变成2,并且之前的用户2会上升成为用户1。还可以看到,有一个可以修改帐号密码的按钮,点击这个按钮,会跳转到如图4-12所示的界面。
图4-12 修改登录密码
该网页的功能就是修改设备的设备帐号的密码,修改的办法就是调用数据库的修改语句,修改数据库中table2中的设备的帐号密码。修改密码后返回首页,如图4-13所示。
可以到,修改后密码由之前的123456变成现在的chencanjian了。从数据库的table2中可以看到,table2中,gh_e2f2b5dbd590_7b4e6f8b9ded723c对应的变成了chencanjian,如图4-14所示。
图4-14 厂商服务器后台数据库数据
本章总结:
本章主要是搭建厂商服务器的后台,设计接受程序,接受来至手机微信的消息,然后对消息进行处理和转发,实现用户需要的功能。并通过设计数据库,保存设备ID号和用户ID的一一对应关系,通过扫描二维码绑定设备的用户的信息会被记录在数据库里。同时,设计WEB网页,让用户能够登录网页修改设备的绑定关系,可以在通过WEB网页剔除其他绑定该设备的用户,甚至是加入黑名单。
第五章 硬件设备跟厂商服务器联通
5.1. 服务器端和客户端的程序流程图
这里的服务器端的程序指的是设备和厂商服务器之间建立的基于TCP/IP连接的服务器端的程序,后面说的客户端程序指的也是基于TCP/IP协议的程序。由于厂商服务器和硬件设备建立的通信架构是基于经典的C/S模式的,所以纯粹就是网络的编程。鉴于客户端程序要放到潜入设备上运行的(基于linux系统的嵌入式设备),所以这里采用C语音来开发服务器端可设备的程序。而且服务器是跑的linux系统,所以采用C语音做服务器端的开发的效率要比用java开发的高。
图5-1是客户端的程序的程序流程图:
图5-2是服务器端的程序的程序流程图:
5.2. 关于多进程的程序设计从图5-2的程序流程图可以看出,客户端要想跟服务器建立连接,必须先获取到三个空闲的端口,然后用其中的一个跟服务器指定的端口(这里是9999号端口)建立起连接。第一次建立其连接之后,服务器端(厂商服务器)获取两个空闲的端口号,并把这两个空闲的端口号发送客户端程序,发送出了两个新端口后,服务器断开第一次建立的连接,并接收第二个设备客户端的连接请求,这样,实现了多个客户端同时连接服务器的功能。客户端根据服务器发送过来的两个新端口号,重新去连接服务器。一旦这两个新连接被建立起来,那么服务器就不会去主动端口,断开的主动方在客户端,要么是硬件设备掉电或着是硬件设备网络掉线。
5.2.1. 服务器端程序的多进程功能
以上的两个程序流程图是厂商服务器跟多个硬件设备同时建立起TCP长连接的程序架构框图。架构框图中,服务器端创建了三个子进程,通过fork进行子进程的创建。
第一次创建子进程是在第一次连接成功后,这时候创建子进程的目的为了空出父进程,好让父进程可以接受第二个客户端的连接,而子进程则负责起了对该客户端的一起服务,包括从服务器获取两个空闲的端口,然后用这两个空闲的端口跟客户端建立起另外两个连接,其中一个用于收发文件消息(包括图像,语音,视频等大文件消息),另一个用户收发微信用户对设备的控制信息。
第二次和第三次创建子进程是在第一次连接断开之后,经过两次子进程的创建过程,可以得到三个进程。其中三个进程各有各需要完成的功能。第一个子进程完成对手机微信用户操作消息的转发;第二个进程完成对设备心跳包的通信机制,以确定设备是否在线;第三个进程完成大文件消息的收发功能。
具体的源程序见附录。
5.2.2. 客户端程序的多进程功能
从5.1的程序流程框图可以看到,客户端只进行了一次子进程的创建过程,创建的时机是在客户端用两个新端口跟服务器重新建立起连接之后。很显然,这里的两个进程,所完成的功能是跟服务器端所要完成的功能相对应的。客户端的一个进程负责收发设备的操作消息和心跳包,第二个程序则负责文件消息的收发功能。
5.2.3. linux的多线程
操作系统对进程的切换的开销是非常的大,需用从用户态到内核态,再从内核态到用户态的系统切换。而线程的切换的开销则小的多,因为同个进程内的线程共享一块地址空间,切换线程时不需要切换地址空间,因为切换速度较快,开销较小。线程之间的切换只需要切换用户栈和核心栈就可以,其他的地址空间都是线程之间共享的。
线程通常来讲有三种:用户级线程,内核级线程跟混合级线程。
用户级的线程之间的切换不需要经过内核态,切换是在用户态进行的,因此切换的速度快,开销小,但是如果有一个线程被阻塞了,就会造成整个进程的阻塞。而且纯用户级别的多线程,不能很好的利用处理器的多核技术。Java使用的是用户级线程。
内核级线程解决了纯用户级线程的两个问题,即不能很好的利用处理器的多核技术的问题和因为一个线程阻塞造成的整个进程阻塞的问题。但是内核及线程的开销也比较大,因为线程之间的切换也是需要经过内核态的。
混合式线程,在混合式线程中,一个应用程序的多个线程可以在处理器上并行运行,可以很好的利用处理器的多核技术,而且也不会因为一个线程阻塞带来的整个进程的阻塞。因为混合式线程采用的是把多个用户级线程映射到内核级的进程上,这样,同一进程内的多个线程之间的切换就不需要切换上下文,但是还是得经过内核态。
Linux采用的就是类是于混合式线程的解决方案,但是linux对该方案进行了优化。Linux处理用户线程的方法是,通过把用户线程映射到内核级的进程上。组成一个用户进程的多个用户级线程被映射到共享一个组ID的多个linux内核进程上。这使得这些进程可以共享文件和内存资源,同一个组中的进程切换时不需要切换上下文环境,因此减少了开销。
通过5.1的介绍,知道服务器是同时跟多个设备建立其TCP长连接的,而且每个设备的连接,服务器端都需要创建出三个进程来服务客户端,这样,进程之间的切换将会很频繁。所以,厂商服务器和硬件设备连接所需要创建的进程,最好是通过创建用户级线程得到比较好,这样线程之间的切换开销将大大减少。而且线程之间的通信将变得更加容易。
本章总结:
本章主要是根据TCP/IP协议,进行网络编程,利用经典的C/S模式,使得服务器能够同时跟多个客户端的硬件设备进行连接和通信。当手机微信发送消息给厂商服务器时,服务器进行处理和判断,进而把消息通过TCP/IP协议,发送给对应的嵌入式硬件设备,实现了手机微信到厂商服务器再到嵌入式设备的通信链路。