1. 程式人生 > >基於Java Netty框架構建高性能的Jt808協議的GPS服務器(轉)

基於Java Netty框架構建高性能的Jt808協議的GPS服務器(轉)

邏輯 利用 影響 成熟 機制 和數 rap 架構 spdy

原文地址:http://www.jt808.com/?p=971

使用Java語言開發一個高質量和高性能的jt808 協議的GPS通信服務器,並不是一件簡單容易的事情,開發出來一段程序和能夠承受數十萬臺車載接入是兩碼事,除去開發部標jt808協議的固有復雜性和幾個月長周期的協議Bug調試,作為大批量794車載終端接入的服務端,需要能夠處理網絡的閃斷、客戶端的重連、安全認證和消息的編解碼、半包處理等。如果沒有足夠的網絡編程經驗積累和深入了解部標jt808協議文檔,自研的GPS服務器往往需要半年甚至數年的時間才能最終穩定下來,這種成本即便對一個大公司而言也是個嚴重的挑戰。

1)我們在開發部標協議的GPS服務器,需要解決以下幾個問題:

1. 通信服務器固有的連接管理,能夠處理網絡的閃斷、客戶端的重連、安全認證和消息的編解碼、半包處理;

2. 海量終端接入的高並發性能;

3. 良好的內存管理,車載終端的連接本事是基於GPRS的無線連接,車輛在野外高速移動過程中,信號處於不穩定狀態,雖然是基於長連接,但是這種連接不斷的中斷和接入,服務器在處理終端接入,數據解析,報警分析,批量入庫的時候,能夠內存分配合理,不會造成內存泄漏,在百萬次的調用中不會造成內存累計上升;

技術分享圖片

2)要開發一個高性能的GPS服務器的三個主題:

1) 傳輸:用什麽樣的通道將數據發送給對方,BIO、NIO或者AIO,IO模型在很大程度上決定了框架的性能。

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預置的編解碼功能列表如下:base64、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公鑰回發以驗證協議的正確性

基於Java Netty框架構建高性能的Jt808協議的GPS服務器(轉)