首先非常感谢,上篇文章中一些前辈的指导,其中一些意见让我获益匪浅!
关于物联网,我觉得灵魂还是在软件上,前端的各种硬件联网标准一旦形成也就没啥事了,更多的仍然是数据的存储,分析。其实,物联网说白了更是一种数据服务一条龙。从数据的采集到数据的传送以及数据的存储和处理。数据的传送就不用说了,属于通信的范畴,属于宽带和三大运营商的领地,数据的的采集属嵌入式的范畴,数据的存储可能一般的程序员和DBA就可以搞定,最有核心的部分就是数据的分析了,只可惜做数据挖掘和大数据处理的,大都是博士和硕士级别的吧!所以做为一名普通的二本毕业生,我准备将目标锁定在嵌入式的方向,准确的说是嵌入式软件开发工程师。
一直以来常常张口物联网,闭口智能家具,终于在最后的时间里,付出了实践,做了一个基于嵌入式Linux的智能家具远程控制系统,当然系统在不断的完善,目前已经实现了远程控制和环境信息实时上传的功能。希望各路大牛,多拍板砖,多提指导性意见。
本文的主要目标是展示系统的服务器,关于嵌入式环境搭建/驱动的编写,不详细说明。
在实现智能家居控制系统之前,我们需要搭建一个人机交互界面,这里我主要采用了HTML页面,也就是最终实现的目标是,人们可以在有网络的地方登陆位于家里的嵌入式WEB服务器,然后通过这些网页来进行用电器的操控,同时,也可以将家里的实时环境值传送到HTML页面,你可以远程查看居室内的环境信息,远程为家人打开空气净化器或者是空调。
STEP 0:开发准备
宿主机:Ubuntu操作系统
开发板:FriendlyARM mini2440
驱动程序:LED驱动,温度传感器驱动
相关技术准备:Socket编程/HTTP协议/JavaScript
STEP 1:实现WEB服务器
嵌入式虽然小,但还是有一批开源的服务器是可供选择的,比如大名鼎鼎的boa,小巧强悍。我在最开始的时候也是选择移植boa服务器作为智能家具的服务器,但是后来在添加家具控制模块和温度传输模块的时候觉得很不方便,于是呼就决定手动打造一个服务器,虽然和boa相差十万里,但是学到的东西也更多,而且对web的机理有了更深刻的认识,觉的作为一个学习者,值了。
在徒手开发服务器之前,你必须要知道,web底层的工作机理,说到这里有一个段子,有一次我去面试,岗位是java web,boss问我你对web有什么认识,我随口一说:“其实web说到底就是socket和http”,后来在一次聚餐的时候boss给我说:“当听到一个还未毕业的学生对web能有如此认识,感到很意外,所以即使你没有经验我也还是会雇佣的。”看来,有时候吹牛逼真的很管用,哈哈。
虽然是吹牛逼,但web的实质的确是socket和http协议,浏览器端我不清楚也就不乱说了,但是我擦浏览器里面一定有个socket来和我们的服务器进行通信。接下来详细说说我们的服务器端,服务器要想和浏览器取得通信,首先需要建立一个socket,然后就是传统的网络编程,但是要注意,服务器和浏览器进行“对话时”,使用的是“HTTP”语言。也就是说web的实质是HTML+SOCKET+浏览器。然而socket又是tcp/ip协议的程序实现层,因此web的实质就是html+TCP/IP+浏览器。然而HTML的实质又是文件,因此web的实质又是 文件+TCP/IP+浏览器(文件翻译器(特殊文件翻译器))。关于浏览器我是在研究的不多,不敢乱说。
因此,总结成一句话就是:“WEB就是向一台被称为服务器的计算机上请求文件,服务器将指定文件发送到浏览器,然后浏览器解析文件并展示的一个过程”。
server_sockfd=socket(AF_INET,SOCK_STREAM,0); if(server_sockfd<0) { printf("create socket failed!/n"); exit(EXIT_FAILURE); } memset(&server_addr,0,sizeof(server_addr)); server_addr.sin_family=AF_INET; server_addr.sin_port=htons(PORT); server_addr.sin_addr.s_addr=INADDR_ANY; if(bind(server_sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr))!=0){ printf("bind error!/n"); exit(EXIT_FAILURE); }
经过上面的操作,已经为服务器创建了一个socket,也为socket绑定ip地址和端口,这样一来,就为我们的服务器在茫茫的网络海洋中有了准确的定位。
关于socket和sockaddr_in,我一直是这样理解的,一个socket相当于一部手机,如果你想别人能够打通你的手机,首先你要有一个SIM卡,而这个sockaddr_in则相当于sim卡,一旦和你手机绑定后,别人(客户端)就可以向你发起呼叫。
接下来就是socket编程的一般步骤,Listen和accpect,相当于你的手机装上了SIM卡并且打开了手机,等待别人的呼叫。
client_sockfd=accept(server_sockfd,(struct sockaddr*)&client_addr,&addr_len);
accpect函数实现阻塞程序的继续进行,直到有客户端发起请求,当有客户端发起请求的话,accpect函数返回这个链接的描述符号。返回的结果代表客户端与服务器的链接描述,下面可以直接用这个描述符来代表已经建立的链接关系。
进行到此时,好比一个人拨通了你的电话并且你接听了电话,此刻你们的链接建立了。你可以用耳朵贴在话筒上听那人说了些什么,在我们的程序里你同样可以用recv来接听客户端都发送了那些请求。
int recv_len=recv(client_sockfd,buffer,sizeof(buffer),0);
其中,buffer代表接收到客户端请求信息以及该客户端的相关信息。仿佛那人给你说的那些话。
关于buffer会是什么内容,相信没有接触过的人都很好奇,我也一样,于是乎打印了出来(前提是我在浏览器地址栏输入了http:127.0.0.1:8000/main.html):
GET /main.html HTTP/1.1 Host: 127.0.0.1:8000 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:34.0) Gecko/20100101 Firefox/34.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Connection: keep-alive
接下来就发现了这些有意思的东西(不要笑我,我真的是小白),第一次看见这东西真的很惊奇。看到了这里我瞬间明白了很多东西:
1 如果我又一个服务器,我能知道,那些ip访问了我的服务器,访问了多少次,地理位置在哪里。
2 我知道了他用的什么浏览器
3 我知道了他的主机是什么系统,还有有关本次链接使用的语言/编码方式/链接类型。。。
其实,我们最关心的就是第一句,第一句是它(客户端)想GET main.html;意思是浏览器想向服务器请求main.html。
好了,如果你想在浏览器成功展示出main.html,你需要将main.html整个文件发送给客户端,但是请注意第一句“GET /main.html HTTP/1.1”,有没有发现它们有着特殊的形式,这就是WEB的语言吧,暂且这样称呼它。如果我们直接调用write函数将main.html发送给客户端,客户端会不会觉得太迷茫,它会觉得发了一坨什么东西,因此在这里服务器也要以类似的形式首先给浏览器发送一段类似的文字然后将整个main.html文件发送过去:
HTTP/1.1 200 OK/r/n
Conten-Type:html/r/n
发送main.html的完成代码如下:
1 sprintf(buffer,"HTTP/1.1 200 OK/r/n"/ 2 "Conten-Type:%s/r/n"/ 3 "/r/n",mine_type); 4 int file_length=strlen(buffer); 5 do{ 6 if(write(socket_fd,buffer,file_length)<0){ 7 close(fd); 8 break; 9 } 10 }while((file_length=read(fd,buffer,sizeof(buffer)))>0);
其中mine_type为文件的类型,比如jif,png,html等等。
至此,一个完整的会话就完成了,一个超级无敌简易的网页浏览器也就搞定了。
STEP2:智能家具控制模块
严格的说,这是web服务器的扩展模块,就是这个服务器不仅能够提供网页的文件资源,还可以调用驱动来进行硬件的操作。
比如要进行灯光控制,在html页面里有一个灯泡的图片按钮,当点击按钮的时候,用JavaScript想后台发送制定的请求内容,比如发送请求内容为:“myled.cgi”,注意这里的后缀不代表请求一个cgi的文件,因为服务器是自己的写的自己解析的,想代表什么自己说了算,就tm这么任性和这么爽!这里我指定它代表灯光控制部分。
1 int recv_len=recv(client_sockfd,buffer,sizeof(buffer),0); 2 printf("*****%d bytes recved!***********/n",recv_len); 3 p_buffer=buffer; 4 if(0==strncmp("GET /myled.cgi",buffer,14)) 5 { 6 printf("hello,heat nan!/n"); 7 send_light_cmd(p_buffer,client_sockfd); 8 9 }
以上的代码,我首先判断它请求的操作是否为灯光操作,如果是则将这些信息作为参数传递给灯光模块处理。
关于灯光模块分为两个部分,一个部分是确定对那个灯进行操作,第二个部分是执行硬件操作,如果是用电器的开关 ,则主要是设置与用电器绑定的IO口电平。
STEP3:实时环境信息模块:
关于实时环境信息模块和智能家具控制模块如出一辙,首先当用户进入环境信息界面,ajax主动向服务器每10s发送一次温度请求,服务器接受到指令后,马上调用温度传感器驱动采集一次温度,然后将温度传递到前端的html页面,如此让用户每隔10ms看到家里的温度一次,也算实时吧!
至此,一个家居远程控制系统就算完成了,不能叫系统吧!此时感觉如此之小 ,叫个小demo吧!
此时此刻,家里的电器确实是连上网了,应该可以叫做“物联网了吧!”
如果将采集的温度值不断的和设定喜好温度值作比较从而让程序自动控制空调和地暖的开关,这应该叫“智能家居了吧!”。
然而,这应该是现实的物联网;
理想的物联网应该是这样:
你的空调会受到一个巨大的数据平台做支持,这个数据平台分别连接了最权威的健康机构,可以提供不同时节/不同时间段最健康的温度,你的空调会和你的手机相互通信,手机会告诉空调,孩子主人距离家里10公里,请你立马工作。空调应当会有记忆功能,分别记住主人在不同时段,不同季节最喜爱的温度,你的空调应当和你的手环相连,当你在左手跟着右手一个慢动作的时候,手环会向空调发出指令,孩子主人心跳加速,体温上升,速度降温,从而不会让你大汗淋漓。
如果当这一天真的来临,请叫他真正的物联网时代吧!