本文是基于嵌入式物聯(lián)網(wǎng)研發(fā)工程師的視覺(jué)對(duì)網(wǎng)絡(luò)編程和web編程進(jìn)行闡述。對(duì)于專注J2EE后端服務(wù)開(kāi)發(fā)的童鞋們來(lái)說(shuō),這篇文章可能稍顯簡(jiǎn)單。但是網(wǎng)絡(luò)編程和web編程對(duì)于絕大部分嵌入式物聯(lián)網(wǎng)工程師來(lái)說(shuō)是一塊真空領(lǐng)域。
的確,物聯(lián)網(wǎng)研發(fā)應(yīng)該以團(tuán)隊(duì)協(xié)作分工的方式進(jìn)行,所以有嵌入式設(shè)備端、網(wǎng)關(guān)、web前端、APP、后端開(kāi)發(fā)等專屬崗位。作為系統(tǒng)架構(gòu)師,自然需要掌握各種崗位的關(guān)鍵技術(shù)。作為嵌入式工程師,掌握網(wǎng)絡(luò)編程、web編程,能夠極大地拓展自己的視野和架構(gòu)思維,能夠主動(dòng)地對(duì)系統(tǒng)的各種協(xié)議和應(yīng)用場(chǎng)景提出優(yōu)化的見(jiàn)解,而不僅僅是接受任務(wù)攤派。至少,能夠在不需要依賴后端工程師的情況,能夠快速搭建一個(gè)物聯(lián)網(wǎng)demo系統(tǒng)。因此,掌握一些基本的網(wǎng)絡(luò)編程、web編程技能,對(duì)于提升物聯(lián)網(wǎng)研發(fā)工程師的開(kāi)發(fā)能力是非常重要的。
本文可以視為嵌入式企鵝圈發(fā)布微信Wifi 接入解決方案的首篇原創(chuàng)技術(shù)分享。微信Wifi接入方案系列技術(shù)分享將于2016年春節(jié)后陸續(xù)公開(kāi),敬請(qǐng)關(guān)注。本篇文章對(duì)物聯(lián)網(wǎng)涉及的知識(shí)進(jìn)行概述,之后的文章再進(jìn)行詳細(xì)的指導(dǎo)開(kāi)發(fā)。
一、 OSI七層模型和TCP/IP四層模型
OSI七層模型是網(wǎng)絡(luò)協(xié)議的理論研究模型,或者可以稱為理想的模型,而TCP/IP四層模型才是事實(shí)標(biāo)準(zhǔn),是已經(jīng)被廣泛使用的模型。兩者之間的關(guān)聯(lián)圖示如下:
對(duì)于兩種模型的解讀,我想說(shuō)的是作為開(kāi)發(fā)人員不必強(qiáng)行去理解各層的含義,例如會(huì)話層負(fù)責(zé)什么,表示層負(fù)責(zé)什么。當(dāng)你在開(kāi)發(fā)過(guò)程中沒(méi)有涉及到這些層次所解決的問(wèn)題的時(shí)候,你想理解并記住是比較困難的。但是,當(dāng)你遇到問(wèn)題并需要去解決的時(shí)候,這時(shí)你一定會(huì)對(duì)這些層次的職責(zé)非常清晰。
衡量一個(gè)物聯(lián)網(wǎng)平臺(tái)或者協(xié)議是否實(shí)用的非常關(guān)鍵的因素是它提供的消息觸達(dá)能力,其直接影響物聯(lián)網(wǎng)應(yīng)用開(kāi)發(fā)。所以,我們從消息觸達(dá)能力去分析TCP/IP這個(gè)事實(shí)標(biāo)準(zhǔn)模型。我們?cè)O(shè)想以下場(chǎng)景,并進(jìn)行分析。
1.網(wǎng)絡(luò)接口層。路由器1和wifi音箱、空調(diào)、熱水器組成一個(gè)家庭局域網(wǎng),其使用wifi(802.11)協(xié)議進(jìn)行通信。該協(xié)議定義了物理信號(hào)、數(shù)據(jù)幀格式、丟包重發(fā)機(jī)制、流量控制等等。這些都是網(wǎng)絡(luò)接口層的任務(wù)。還有,多個(gè)設(shè)備共享信道,同時(shí)發(fā)數(shù)據(jù)會(huì)產(chǎn)生沖突,它是怎么解決的,這也是網(wǎng)絡(luò)接口層的內(nèi)容。其實(shí),物聯(lián)網(wǎng)工程師不必在意這些內(nèi)容。因?yàn)閣ifi物理信號(hào)方面的內(nèi)容是由wifi芯片廠商負(fù)責(zé),而wifi單芯片(wifi+SOC)則會(huì)提供SDK包并提供SOCKET編程接口了。所以,我們職責(zé)的重點(diǎn)是關(guān)注網(wǎng)絡(luò)層以上的編程開(kāi)發(fā)知識(shí)。
2.網(wǎng)絡(luò)層,即IP協(xié)議,最基礎(chǔ)的認(rèn)識(shí)是每個(gè)IP對(duì)應(yīng)一個(gè)物聯(lián)設(shè)備、手機(jī)或者一個(gè)后方服務(wù)器。原則上一個(gè)網(wǎng)卡對(duì)應(yīng)一個(gè)IP,如圖中wifi音箱、wifi熱水器均有一個(gè)獨(dú)立的IP。網(wǎng)絡(luò)之間的通信都是基于IP進(jìn)行的,網(wǎng)絡(luò)包會(huì)通過(guò)路由器最終送到目標(biāo)IP所對(duì)應(yīng)的設(shè)備上。
Wifi音箱等家庭設(shè)備加入家庭局域網(wǎng),其實(shí)是各獲得一個(gè)局域網(wǎng)IP,192.168.*.*,包括路由器1也有一個(gè)局域網(wǎng)地址,但是路由器1還有一個(gè)互聯(lián)網(wǎng)IP。只有路由器的互聯(lián)網(wǎng)IP才能被外界所獲知,外界是不能主動(dòng)獲知局域網(wǎng)IP具體對(duì)應(yīng)哪個(gè)設(shè)備的,只有路由器1才知道,因此所有對(duì)外發(fā)送的數(shù)據(jù)包的源IP都是路由器1的互聯(lián)網(wǎng)IP,外界發(fā)送給設(shè)備的數(shù)據(jù)包的目標(biāo)IP也是路由器的互聯(lián)網(wǎng)IP。
我們都知道,設(shè)備上線時(shí)需要向物聯(lián)平臺(tái)服務(wù)器告知自己的狀態(tài),以便于用戶控制。因此物聯(lián)平臺(tái)服務(wù)器的IP必須是一個(gè)互聯(lián)網(wǎng)IP,或者是一個(gè)域名(DNS協(xié)議可以將域名解析為IP)。如果它是一個(gè)局域網(wǎng)IP,那設(shè)備是不可能訪問(wèn)到的。
這里,我們還必須要記住一點(diǎn),設(shè)備和物聯(lián)平臺(tái)的第一次通信永遠(yuǎn)都應(yīng)該設(shè)備主動(dòng)發(fā)出,因?yàn)榫退阄锫?lián)平臺(tái)知道路由器1的公網(wǎng)IP,它也無(wú)法將消息傳送到內(nèi)部的設(shè)備的。另外,服務(wù)器必須要持續(xù)設(shè)備到達(dá)物聯(lián)平臺(tái)最后一跳的路由信息,因?yàn)槁酚尚畔⒃贩祷氐倪^(guò)程中具有路由器1記錄是哪個(gè)設(shè)備發(fā)出的信息。如果不記錄這個(gè)信息,物聯(lián)平臺(tái)單靠路由器1的互聯(lián)網(wǎng)IP是無(wú)法觸達(dá)到具體設(shè)備的。
如果你不能理解上面這一段話,就記住,物聯(lián)平臺(tái)通過(guò)路由器1的互聯(lián)網(wǎng)IP主動(dòng)發(fā)一條消息到設(shè)備是不能成功的,但是,當(dāng)設(shè)備發(fā)一條消息給物聯(lián)平臺(tái)后,物聯(lián)平臺(tái)直接響應(yīng)該數(shù)據(jù)包(IP源地址和目標(biāo)地址調(diào)換位置)是可以觸達(dá)設(shè)備的。如果是滿足一問(wèn)一答的方式,那么服務(wù)器不需要記錄這個(gè)路由信息,如果需要滿足服務(wù)器主動(dòng)發(fā)消息給設(shè)備的場(chǎng)景,那么服務(wù)器是需要記錄這個(gè)信息的。
另外,我們知道,網(wǎng)絡(luò)設(shè)備在物理上表現(xiàn)為一個(gè)真實(shí)的網(wǎng)卡,網(wǎng)卡的MAC地址是6個(gè)字節(jié),48位。在一個(gè)局域網(wǎng)內(nèi)通信,網(wǎng)絡(luò)編程時(shí)都是基于IP地址的,路由器或者交換機(jī)如何通過(guò)IP地址找到對(duì)應(yīng)的MAC地址,即為ARP地址解析協(xié)議,這個(gè)也是網(wǎng)絡(luò)層的職責(zé),但是作為開(kāi)發(fā)人員來(lái)說(shuō),我們了解即可。
3. 傳輸層,即TCP/UDP協(xié)議。對(duì)于傳輸層,我們需要理解的是,一臺(tái)PC或者手機(jī)上運(yùn)行的網(wǎng)絡(luò)運(yùn)用可能很多,但是他們都對(duì)應(yīng)同樣一個(gè)IP。操作系統(tǒng)如何將一個(gè)數(shù)據(jù)包分發(fā)給對(duì)應(yīng)的網(wǎng)絡(luò)運(yùn)用呢?這就依靠傳輸層所定義的端口來(lái)區(qū)分。常見(jiàn)的網(wǎng)絡(luò)應(yīng)用層協(xié)議都會(huì)默認(rèn)傳輸層端口號(hào),如FTP對(duì)應(yīng)21,HTTP對(duì)應(yīng)80,SMTP對(duì)應(yīng)25等等。傳輸層除了定義端口號(hào)之外,還有兩個(gè)非常重要的協(xié)議,即TCP面向連接的協(xié)議和UDP數(shù)據(jù)包協(xié)議。前者可以理解為一個(gè)虛擬的電話連接協(xié)議,一旦雙方打電話建立起連接后雙方通話的過(guò)程中,所有的數(shù)據(jù)包均是走同樣的路由路徑。因?yàn)槊嫦蜻B接的協(xié)議會(huì)在帶寬中預(yù)留資源來(lái)保障,所以面向連接協(xié)議能夠保證質(zhì)量,因此適用于一些對(duì)數(shù)據(jù)質(zhì)量要求嚴(yán)格的網(wǎng)絡(luò)運(yùn)用中,如電子郵件應(yīng)用,如果不保證質(zhì)量,郵件內(nèi)容都不保證正確,誰(shuí)會(huì)使用這個(gè)郵件系統(tǒng)呢?但是,對(duì)于一些音頻視頻類運(yùn)用,丟一兩幀完全不影響用戶體驗(yàn),則會(huì)使用UDP協(xié)議,其不是面向連接,發(fā)完后之前的路由信息可以不在保存,其是使用最大努力交付(即trymy best)。
4. 應(yīng)用層。常見(jiàn)的網(wǎng)絡(luò)應(yīng)用協(xié)議包括HTTP、FTP、SMTP、POP等等。嵌入式物聯(lián)應(yīng)用是建立在這些網(wǎng)絡(luò)應(yīng)用協(xié)議的基礎(chǔ)之上的。這些協(xié)議會(huì)規(guī)范基本的請(qǐng)求連接、響應(yīng)和數(shù)據(jù)傳輸?shù)确矫娴母袷?。作為嵌入式物?lián)網(wǎng)應(yīng)用來(lái)說(shuō),其應(yīng)該自行定義應(yīng)用協(xié)議的格式,這些數(shù)據(jù)格式可以簡(jiǎn)單自定義,也可以使用成熟的標(biāo)準(zhǔn)格式,如HTML、XML、JSON等等。由于防火墻一般只放開(kāi)端口為80的HTTP數(shù)據(jù)包,所以物聯(lián)網(wǎng)應(yīng)用一般都會(huì)構(gòu)建在HTTP的基礎(chǔ)上。
所以,我們要區(qū)分網(wǎng)絡(luò)應(yīng)用層協(xié)議HTTP和應(yīng)用自定義協(xié)議。后者使用前者進(jìn)行傳輸通信。不管應(yīng)用自定義協(xié)議使用哪一種格式,都需要通信雙方同時(shí)使用。物聯(lián)設(shè)備和物聯(lián)平臺(tái)后臺(tái)通信時(shí),可以使用簡(jiǎn)單的XML格式或者JSON格式,而物聯(lián)平臺(tái)還要被PC瀏覽器訪問(wèn),那么,由于瀏覽器只支持HTML格式,則要求物聯(lián)平臺(tái)后臺(tái)提供HTML格式的內(nèi)容服務(wù),同理,物聯(lián)網(wǎng)平臺(tái)和手機(jī)APP之間的通信可以用XML或者JSON。甚至,我們可以自定義簡(jiǎn)單的命令來(lái)實(shí)現(xiàn)功能,但是使用XML或者JSON這些格式有助于數(shù)據(jù)有良好的可讀性,而且也有成熟的類庫(kù)來(lái)解釋。
這些都是建立在HTTP網(wǎng)絡(luò)應(yīng)用協(xié)議的基礎(chǔ)上的。
二、 socket編程
socket編程分為TCP和UDP兩種方式。分別如下:
可見(jiàn),TCP/UDP的socket套接字在通信之前需要綁定(bind)IP和端口地址。對(duì)于TCP來(lái)說(shuō),服務(wù)器需要先偵聽(tīng)listen,而客戶端發(fā)起connect請(qǐng)求后,服務(wù)器才能accept,之后即建立面向連接的通信環(huán)境,通過(guò)send/recv函數(shù)進(jìn)行通信。
而UDP編程則很簡(jiǎn)單,綁定之后可以立即開(kāi)始數(shù)據(jù)傳輸。
除了掌握基本的socket編程之外,還需要清楚以下知識(shí):
1)阻塞和非阻塞。網(wǎng)絡(luò)套接字有阻塞和非阻塞之分。如假設(shè)創(chuàng)建的socket是阻塞的,那么其recv函數(shù)就一定要等到對(duì)方傳送數(shù)據(jù)過(guò)來(lái),才會(huì)返回,否則會(huì)一直處于阻塞狀態(tài)。而非阻塞狀態(tài)則是立即看看緩沖有沒(méi)有數(shù)據(jù),如果有就返回?cái)?shù)據(jù),沒(méi)有會(huì)返回錯(cuò)誤,而不是一直死等。阻塞模式可以簡(jiǎn)單地理解為同步工作模式,而非阻塞模式可以理解為異步工作模式。
2)多路復(fù)用。作為服務(wù)器,可能會(huì)存在多個(gè)客戶端連接,如果輪詢每個(gè)客戶端socket有沒(méi)有數(shù)據(jù),那效率多累啊。Socket編程的select和poll接口用來(lái)解決這類多路IO復(fù)用的問(wèn)題,它能夠同時(shí)偵測(cè)多個(gè)連接的數(shù)據(jù)通信。
三、 B/S和C/S
1.B/S是瀏覽器和客戶端模式,使用HTML語(yǔ)法格式。其使用一問(wèn)一答,即服務(wù)器是無(wú)狀態(tài)的,它不知道客戶端之前是否已經(jīng)訪問(wèn)過(guò)。無(wú)狀態(tài)有助于服務(wù)器高效率而且穩(wěn)定地服務(wù)。但是這種模式對(duì)于物聯(lián)網(wǎng)應(yīng)用的影響是致命的。因?yàn)榉?wù)器無(wú)法主動(dòng)地發(fā)送消息給物聯(lián)設(shè)備。那么,如何改進(jìn)呢?
1)ajax技術(shù)。Ajax技術(shù)最新是為了解決頁(yè)面局部刷新頻繁的效率問(wèn)題的。即一個(gè)HTML頁(yè)面的局部數(shù)據(jù)發(fā)送變化了,在ajax之前需要重新發(fā)送一次請(qǐng)求,來(lái)刷新整個(gè)頁(yè)面。而ajax則是僅僅向服務(wù)器請(qǐng)求發(fā)送變化的數(shù)據(jù)。前者在請(qǐng)求時(shí)會(huì)看到頁(yè)面有閃爍,而后者則沒(méi)有。我們正好可以利用ajax來(lái)定時(shí)向服務(wù)器發(fā)起請(qǐng)求,詢問(wèn)服務(wù)器是否有更新的數(shù)據(jù)。如果詢問(wèn)頻率高,那么實(shí)時(shí)效果就好,但是會(huì)加重服務(wù)器負(fù)擔(dān)。本質(zhì)上,還是一問(wèn)一答的形式,而不是雙向通信。Ajax需要瀏覽器技術(shù)支持。
2)websocket技術(shù)。Websocket是為了解決HTML的雙向通信問(wèn)題而提出的,其在第一條HTTP請(qǐng)求之后會(huì)讓服務(wù)器將后續(xù)的協(xié)議更新到Websocket進(jìn)行通信。Websocket需要tomcat7.0以上的運(yùn)行容器技術(shù)支持。
物聯(lián)網(wǎng)應(yīng)用開(kāi)發(fā)在設(shè)備端可以通過(guò)socket編程來(lái)模擬HTTP協(xié)議,同樣可以模擬HTTP之上的HTML、XML或者Websocket。
C/S客戶端和服務(wù)器編程在智能機(jī)出現(xiàn)之前在PC桌面領(lǐng)域一度被認(rèn)為會(huì)在逐漸被B/S所取代,但是在智能機(jī)設(shè)備端它又煥發(fā)新生。盡管HTML5發(fā)展迅速,但是個(gè)人覺(jué)得瀏覽器在手機(jī)等智能設(shè)備端的體驗(yàn)還是比不上原生APP。而HTML5更大的優(yōu)勢(shì)是其移植性很強(qiáng)。
C/S編程可以直接使用socket通信進(jìn)行通信,那自然不存在雙方通信的問(wèn)題。如果C/S編程使用http類庫(kù)進(jìn)行編程通信,它同樣也會(huì)存在雙向通信的問(wèn)題。
目前看來(lái),很多人都希望沿用J2EE那套業(yè)務(wù)架構(gòu)來(lái)支持物聯(lián)網(wǎng),但是物聯(lián)設(shè)備畢竟是資源有限,有些終端可能是簡(jiǎn)單的單片機(jī),其跑完整的TCP/UDP協(xié)議都比較困難,因此有人提出了精簡(jiǎn)版的TCP/IP協(xié)議,如CoAP(受限制的應(yīng)用協(xié)議(ConstrainedApplicationProtocol)的代名詞)、ucIP、LWIP等等。從業(yè)務(wù)應(yīng)用協(xié)議來(lái)看,IBM研發(fā)的MQTT可能會(huì)成為物聯(lián)網(wǎng)應(yīng)用協(xié)議的標(biāo)準(zhǔn)。
四、 Web編程
Web編程最先指的是瀏覽器展示內(nèi)容的語(yǔ)法編程。Web靜態(tài)語(yǔ)言即是HTML。
1.HTML不支持?jǐn)?shù)據(jù)的動(dòng)態(tài)變化。因此產(chǎn)生了基于解釋引擎的動(dòng)態(tài)語(yǔ)言,如ASP、PHP、JSP等等。這類語(yǔ)言會(huì)使用HTML/CSS來(lái)描述展現(xiàn)樣式,而使用動(dòng)態(tài)語(yǔ)言來(lái)控制數(shù)據(jù)的展現(xiàn),例如訪問(wèn)數(shù)據(jù)庫(kù)獲取新數(shù)據(jù)等等。
需要知道,ASP,PHP,JSP這些語(yǔ)言是服務(wù)器編程語(yǔ)言,當(dāng)用戶通過(guò)瀏覽器訪問(wèn)服務(wù)器對(duì)應(yīng)網(wǎng)頁(yè)時(shí),該網(wǎng)頁(yè)的ASP/PHP/JSP等內(nèi)容會(huì)經(jīng)過(guò)服務(wù)器的解釋引擎轉(zhuǎn)化為具體的數(shù)據(jù),最終和其他的HTML、CSS數(shù)據(jù)一起返回給瀏覽器進(jìn)行展現(xiàn)。因此,瀏覽器得到的永遠(yuǎn)都是確定的HTML、CSS和數(shù)據(jù),不存在ASP/PHP/JSP的語(yǔ)句。
2.javascript腳本。腳本是瀏覽器技術(shù)支持的語(yǔ)法,而不是服務(wù)器技術(shù)支持的。例如一個(gè)登錄界面,要確保用戶輸入的正確性,如不規(guī)則字符,長(zhǎng)度太長(zhǎng)等等,一般會(huì)使用javascript腳本進(jìn)行檢測(cè),而不需要發(fā)送請(qǐng)求給服務(wù)器。上述講到的ajax技術(shù)也是瀏覽器支持的腳本技術(shù)。
3.jQuery,它是對(duì)javascript技術(shù)的封裝,能夠更好地進(jìn)行前端編程控制。
4.HTML/CSS/JS腳本,稱為web前端編程開(kāi)發(fā),而ASP/JSP/PHP等為后端開(kāi)發(fā)。
5.后端開(kāi)發(fā)自然會(huì)涉及到數(shù)據(jù)庫(kù)訪問(wèn)、業(yè)務(wù)邏輯,并且其需要和前端進(jìn)行交互。因此,web應(yīng)用編程架構(gòu)普遍使用MVC編程模型,即M為數(shù)據(jù)模型,負(fù)責(zé)數(shù)據(jù)庫(kù)訪問(wèn);V為視圖,負(fù)責(zé)展現(xiàn);C為控制。MVC模型能夠?qū)φ宫F(xiàn)和數(shù)據(jù)庫(kù)進(jìn)行良好的分離,有助于應(yīng)用開(kāi)發(fā)。
6.作為整體運(yùn)行架構(gòu)來(lái)理解,服務(wù)器需要包括數(shù)據(jù)庫(kù)(如mysql)、web應(yīng)用和解釋引擎和web服務(wù)(如apache和tomcat)。Apache提供http服務(wù)。
7.JSP的基礎(chǔ)是JAVA語(yǔ)法,J2EE架構(gòu)提供servlet技術(shù),用于支持網(wǎng)絡(luò)運(yùn)用。JSP其實(shí)是對(duì)servlet的高級(jí)封裝并作為獨(dú)立的技術(shù)出現(xiàn)的,JSP側(cè)重支持B/S方面的網(wǎng)絡(luò)運(yùn)用,而servlet則通過(guò)映射類的方式支持C/S方式的網(wǎng)絡(luò)運(yùn)用,如微信藍(lán)牙接入和wifi接入的后端技術(shù)即使用servlet進(jìn)行支持, 頂層使用XML/JSON格式。
聯(lián)系客服