原文地址:http://www.jt808.com/?p=971前端
使用Java語言開發一個高質量和高性能的jt808 協議的GPS通訊服務器,並非一件簡單容易的事情,開發出來一段程序和可以承受數十萬臺車載接入是兩碼事,除去開發部標jt808協議的固有複雜性和幾個月長週期的協議Bug調試,做爲大批量794車載終端接入的服務端,須要可以處理網絡的閃斷、客戶端的重連、安全認證和消息的編解碼、半包處理等。若是沒有足夠的網絡編程經驗積累和深刻了解部標jt808協議文檔,自研的GPS服務器每每須要半年甚至數年的時間才能最終穩定下來,這種成本即使對一個大公司而言也是個嚴重的挑戰。java
1)咱們在開發部標協議的GPS服務器,須要解決如下幾個問題:linux
1. 通訊服務器固有的鏈接管理,可以處理網絡的閃斷、客戶端的重連、安全認證和消息的編解碼、半包處理;spring
2. 海量終端接入的高併發性能;shell
3. 良好的內存管理,車載終端的鏈接本事是基於GPRS的無線鏈接,車輛在野外高速移動過程當中,信號處於不穩定狀態,雖然是基於長鏈接,可是這種鏈接不斷的中斷和接入,服務器在處理終端接入,數據解析,報警分析,批量入庫的時候,可以內存分配合理,不會形成內存泄漏,在百萬次的調用中不會形成內存累計上升;數據庫
2)要開發一個高性能的GPS服務器的三個主題:編程
1) 傳輸:用什麼樣的通道將數據發送給對方,BIO、NIO或者AIO,IO模型在很大程度上決定了框架的性能。 windows
2) 協議:採用什麼樣的通訊協議,HTTP或者內部私有協議。協議的選擇不一樣,性能模型也不一樣。相比於公有協議,內部私有協議的性能一般能夠被設計的更優。 數組
3) 線程:數據報如何讀取?讀取以後的編解碼在哪一個線程進行,編解碼後的消息如何派發,Reactor線程模型的不一樣,對性能的影響也很是大。緩存
Netty是業界最流行的NIO框架,能夠很好的解決上面三個問題,它的可靠性、高性能和可擴展性已經獲得了上百上千的商用項目驗證,相對於.NET中的基於完成端口的通訊框架,它要優越的多,它的優勢總結以下:
1. API使用簡單,開發門檻低;
2. 功能強大,內聚了不少實用的功能,簡化用戶的開發;
3. 定製性好,經過ChannelPipeline機制能夠靈活的進行功能定製和擴展;
4. 性能高;
5. 成熟穩定,社區活躍,Bug的修復週期比較短,新功能不斷的被加入,用戶能夠體驗到更多、更實用的功能。
6. 經歷了大規模不一樣行業的商用考驗,架構質量獲得了充分的驗證。
Netty爲了向使用者屏蔽NIO通訊的底層細節,在和用戶交互的邊界作了封裝,目的就是爲了減小用戶開發工做量,下降開發難度。ServerBootstrap是Socket服務端的啓動輔助類,用戶經過ServerBootstrap能夠方便的建立Netty的服務端。
3)編碼器和解碼器的設計
對於jt808協議的解析處理,須要編寫自定義的解碼器了,目前Netty提供了多個基礎編碼器能夠供開發者進行繼承和拓展,開發的時候,須要瞭解這幾個解碼器的主要做用,主要用於那些通訊數據傳輸的場景。
爲了下降用戶的開發難度,Netty對經常使用的功能和API作了裝飾,以屏蔽底層的實現細節。編解碼功能的定製,對於熟悉Netty底層實現的開發者而言,直接基於ChannelHandler擴展開發,難度並非很大。可是對於大多數初學者或者不肯意去了解底層實現細節的用戶,須要提供給他們更簡單的類庫和API,而不是ChannelHandler。
Netty在這方面作得很是出色,針對編解碼功能,它既提供了通用的編解碼框架供用戶擴展,又提供了經常使用的編解碼類庫供用戶直接使用。在保證定製擴展性的基礎之上,儘可能下降用戶的開發工做量和開發門檻,提高開發效率。
一般咱們也習慣將編碼(Encode)稱爲序列化(serialization),它將對象序列化爲字節數組,用於網絡傳輸、數據持久化或者其它用途。
反之,解碼(Decode)/反序列化(deserialization)把從網絡、磁盤等讀取的字節數組還原成原始對象(一般是原始對象的拷貝),以方便後續的業務邏輯操做。
Netty預置的編解碼功能列表以下:base6四、Protobuf、JBoss Marshalling、spdy等。
在GPS行業當中,對於終端通訊協議的設計有多種:
1)基於字符串設計的方式,這種方式就是終端發送一個ASCII字符串,而後服務器獲取後基於約定的分隔符分割爲一個數組,再依次從數組中獲取對應下標的數據,這種方式一般是深圳小的硬件公司的技術水平較低的開發團隊喜歡採用,這種方式容易理解,但傳輸字節較多,效率較低,比較佔用流量,不適用於基於流量套餐的無線卡傳輸。
2)基於定長協議的傳輸。
① 消息定長,例如每一個報文的大小爲固定長度200字節,若是不夠空位補空格。 ② 在包尾增長回車換行符進行分割,例如FTP協議。
③ 將消息分爲消息頭和消息體,消息頭中包含表示消息總長度(或者消息體整體長度) 的字段,一般涉及思路爲消息頭的第一個字段使用init32來表示消息的總長度。
④ 更復雜的應用層協議,例如部標808協議
部標協議數據包設計的特色:
1) 基於分隔符,包頭和包圍用0x7E來區分一個完整的數據包;
2) 動態包頭,不想其餘協議在設計的時候,包頭長度都是固定長度,而808協議的包頭長度是不固定的;
3) 包體是動態長度,長度從包頭中讀取。
解碼器就是要根據協議設計的數據包的規則,來對字節流進行解析,解碼成完整的數據包。Netty提供了一下幾種基礎的解碼器提供給咱們,供繼承或直接使用:
1)LineBasedFrameDecoder的工做原理是它依次便利ByteBuf中的可讀字節,判斷看是否有「\n」或者「\r\n」,若是有就以此位置爲結束位置,從可讀索引到結束位置區間的字節就組成了一行。他是以換行符爲結束標誌的解碼器,支持攜帶結束符或者不攜帶結束符兩種解碼方式,同時支持配置當行的最大長度。若是連續讀取帶最大長度後任然沒有發現換行符,就會拋出異常,同時忽略掉以前讀到的異常碼流。
2)StringDecoder的功能很是簡單,就是將接收到的對象轉換成字符串,而後繼續調用後面的handler。LineBasedFrameDecoder+StringDecoder組合就是按行切換的文本解碼器,它被設計用來支持TCP的粘包和拆包。
3)DelimiterBasedFrameDecoder特殊符號解碼器,其已通過濾掉了分隔符。
4)FixedLengthFrameDecoder固定長度解碼器,它可以按照指定的長度對消息進行自動解碼。利用FixedLengthFrameDecoder解碼器不管一次接受到多少數據報,它都會按照構造函數中設置的固定長度進行解碼,若是是半包消息,FixedLengthFrameDecoder會緩存半包消息並等待下個包到達後進行拼包,直到取到一個完整的包。
4)基於Netty開發一個部標808協議的服務器,具體的步驟以下:
1)咱們使用Netty要作的工做就是編寫編碼器和解碼器,而後按照Netty的要求來編寫調用,最後獲得一個完整的jt808協議的數據包。
2)按照數據處理鏈條,分工職責,爲了提升終端接入能力和數據分析、入庫能力,將終端消息的處理分紅獨立的五級處理模塊,每一個處理模塊都是異步獨立的,每一個模塊內都含有獨立的處理隊列,互不影響,提升數據的吞吐量和系統的響應能力。
1)第一級:實時數據解析入庫,入庫能力決定了客戶端所看到的實時數據是否延遲;
2)第二級:報警分析併入庫(包括32種jt808協議規定的報警、停車報警和路線偏移報警),報警分析只有快速分析才能快速的推送到前端客戶端;
3) 第三級:消息應答和指令下發,應答能夠有必定的延遲,而不影響整個系統性能。
4)第四級:報表統計,因爲油量統計、里程統計、上線率統計,須要定時掃描數據庫,生成每一個時段的數據統計提供給報表查詢使用.
5)第五級:日誌記錄和顯示
因爲netty和Mina都能很是好的和spring容器集成在一塊兒,引入spring框架,基於面向接口編程,系統能夠同時支持netty和mina兩種通訊框架,用戶能夠根據本身的環境,經過配置決定是用mina或者是netty。
5)鏈接管理和日誌報文監控
在windows系統,能夠運行swing界面進行監控,若是運行在阿里雲的linux系統上,能夠直接編寫java shell腳本,基於後臺服務運行,經過java 命令來調用當前的鏈接,日誌監控,主要依賴於log文件。
6) jt808系統源碼易於和第三方系統如PHP平臺進行集成,提供了接口和清晰的數據庫文檔。
jt808服務器,協議解析、命令下發、報警解析、數據庫入庫、數據統計、壓力測試等各方面都要考慮的很是充分完善,808協議全協議棧的實現,還要有庫表文檔和字段說明。
808服務器主要用的庫表:
部門表 |
車輛表 |
終端表 |
實時表 |
歷史軌跡表 |
駕駛員表 |
電子運單表 |
報警統計報表 |
報警推送表 |
電子圍欄表 |
線段表 |
終端命令表 |
終端參數表 |
基礎數據表 |
多媒體上傳記錄 |
行駛記錄儀表 |
里程統計中間表 |
部門上線率統計表 |
油量變化記錄 |
油量和里程統計表 |
車輛上線率統計表 |
五分鐘一次油量和里程記錄 |
6) 本808服務器對於部標jt808所有協議棧都進行了充分的支持:
序號 |
項目名稱 |
觸發條件 |
預期迴應 |
01 |
終端心跳 |
根據設定的心跳時間參數,定時自動上報 |
主動上發,須要平臺提供通用應答,長時間沒法得到應答將致使程序自動斷開重連。 |
02 |
設置終端參數 |
平臺下發 |
回覆通用應答,可設置的參數參考行標協議文本8.8 |
03 |
超速設置 |
平臺下發 |
回覆通用應答 |
04 |
疲勞駕駛設置 |
平臺下發 |
回覆通用應答 |
05 |
超時停車設置 |
平臺下發 |
回覆通用應答 |
06 |
查詢終端參數 |
平臺下發 |
回覆0×0104應答參照行標協議文本8.10描述,回覆的參數信息包含前述設置指令所設定修改的內容 |
07 |
終端控制 |
平臺下發 |
回覆通用應答 |
08 |
位置信息查詢 |
平臺下發 |
回覆固化的位置信息:26.033435N,119.139317E 高度23.59,速度0,角度0 |
09 |
臨時位置跟蹤控制 |
平臺下發 |
回覆通用應答 |
10 |
文本信息下發 |
平臺下發 |
回覆通用應答 |
11 |
追加事件 |
平臺下發 |
回覆通用應答 |
12 |
刪除特定事件 |
平臺下發 |
回覆通用應答 |
13 |
更新事件 |
平臺下發 |
回覆通用應答 |
14 |
修改事件 |
平臺下發 |
回覆通用應答 |
15 |
刪除所有事件 |
平臺下發 |
回覆通用應答 |
16 |
追加新事件 |
平臺下發 |
回覆通用應答 |
17 |
提問下發 |
平臺下發 |
程序當即回覆通用應答,稍後由用戶手動操做回覆提問 |
18 |
信息點播菜單追加 |
平臺下發 |
回覆通用應答 |
19 |
信息點播菜單修改 |
平臺下發 |
回覆通用應答 |
20 |
信息點播菜單更新 |
平臺下發 |
回覆通用應答 |
21 |
信息點播菜單刪除 |
平臺下發 |
回覆通用應答 |
22 |
信息點播菜單追加 |
平臺下發 |
回覆通用應答 |
23 |
信息點播菜單修改 |
平臺下發 |
回覆通用應答 |
24 |
信息點播菜單更新 |
平臺下發 |
回覆通用應答 |
25 |
信息服務 |
平臺下發 |
回覆通用應答 |
26 |
電話回撥 |
平臺下發 |
回覆通用應答,不觸發任何邏輯動做,請關注日誌 |
27 |
電話回撥_監聽 |
平臺下發 |
回覆通用應答,不觸發任何邏輯動做,請關注日誌 |
28 |
設置電話本_刪除 |
平臺下發 |
回覆通用應答 |
29 |
設置電話本_更新電話本 |
平臺下發 |
回覆通用應答 |
30 |
設置電話本_追加電話本 |
平臺下發 |
回覆通用應答 |
31 |
設置電話本_修改電話本 |
平臺下發 |
回覆通用應答 |
32 |
車輛控制_車門解鎖 |
平臺下發 |
回覆通用應答 |
33 |
車輛控制_車門加鎖 |
平臺下發 |
回覆通用應答 |
34 |
更新圓形區域 |
平臺下發 |
回覆通用應答 |
35 |
刪除圓形區域 |
平臺下發 |
回覆通用應答 |
36 |
更新矩形區域 |
平臺下發 |
回覆通用應答 |
37 |
刪除矩形區域 |
平臺下發 |
回覆通用應答 |
38 |
更新多邊形區域 |
平臺下發 |
回覆通用應答 |
39 |
刪除多邊形區域 |
平臺下發 |
回覆通用應答 |
40 |
更新路線 |
平臺下發 |
回覆通用應答 |
41 |
刪除全部路線 |
平臺下發 |
回覆通用應答 |
42 |
行駛記錄儀數據採集命令 |
平臺下發 |
根據形式記錄議命令字發回測試數據,數據可能會產生分包 |
43 |
行駛記錄儀參數下傳命令 |
平臺下發 |
回覆通用應答 |
44 |
抓拍當即上傳 |
平臺下發 |
回覆通用應答,隨後分包上發固化的多媒體數據,上發數據與多媒體通道有關* |
45 |
錄像當即上傳 |
平臺下發抓拍指令附帶錄像提示 |
回覆通用應答,隨後分包上發固化的多媒體數據,上發數據與多媒體通道有關* |
46 |
檢索多媒體列表 |
平臺下發 |
根據查詢的多媒體類型回覆固化的多媒體列表數據,參考行標協議8.46,通道與時間參數將被解析於日誌中,可是不會影響列表內容 |
47 |
存儲多媒體上傳 |
平臺下發 |
根據通道*和多媒體類型定義回傳多媒體數據,時間和事件等參數將被正確解析與日誌中,可是不會影響上發的多媒體內容 |
48 |
錄音32Kbps當即上傳 |
平臺下發 |
回覆通用應答 |
49 |
數據下行透傳 |
平臺下發 |
回覆通用應答 |
50 |
平臺RSA公鑰 |
平臺下發 |
回覆終端RSA公鑰,本軟件將把平臺下發的RSA公鑰回發以驗證協議的正確性 |