標籤:
首先非常感謝,上篇文章中一些前輩的指導,其中一些意見讓我獲益匪淺!
關於物聯網,我覺得靈魂還是在軟體上,前端的各種硬體連網標準一旦形成也就沒啥事了,更多的仍然是資料的儲存,分析。其實,物聯網說白了更是一種資料服務一條龍。從資料的採集到資料的傳送以及資料的儲存和處理。資料的傳送就不用說了,屬於通訊的範疇,屬於寬頻和三大電訊廠商的領地,資料的的採集屬嵌入式的範疇,資料的儲存可能一般的程式員和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.1Host: 127.0.0.1:8000User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:34.0) Gecko/20100101 Firefox/34.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3Accept-Encoding: gzip, deflateConnection: 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公裡,請你立馬工作。空調應當會有記憶功能,分別記住主人在不同時段,不同季節最喜愛的溫度,你的空調應當和你的手環相連,當你在左手跟著右手一個慢動作的時候,手環會向空調發出指令,孩子主人心跳加速,體溫上升,速度降溫,從而不會讓你大汗淋漓。
如果當這一天真的來臨,請叫他真正的物聯網時代吧!
物聯網實踐之——一步一步"徒手"建立智能傢具遠端控制系統