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