12.25 物聯網,車聯網netty服務器springboot支持圖形化源碼

先轉發,加關注後私信“netty源碼”即可免費獲取源碼

基於netty4,protoBuff的netty心跳服務器支持鑑權、斷線重連、其他業務模塊開發、支持圖形化實時監控,可直接投入生產

Netty心跳服務器

Springboot2.0.8集成 netty4 ,使用protobuf作為ping的數據交換,比json更加的小巧,佔用數據量更小,可用於任何第三方應用做心跳監控

應用場景

比如公司可以使用的一種業務場景是這樣的: 現有多臺服務器,有a業務的 有b業務的 有c業務的 有d業務項目等等,有時候用戶量大或者其他因素,這些服務器down掉了,大多數情況都是基於運維監控報警的,但是由於項目都是多臺機器部署同一個項目,項目掛了後centos主機並不能很快檢查出來,一般時間會比較長在半小時之內,甚至有的時候是用戶來打電話告知項目down掉了,這對公司來說影響多麼的大。 掛上了項目心跳後,可以實時看到100多臺機器的實時ping值是否正常,當然你也可以通過定時請求http接口來判斷是否應用正常,熟知http接口的請求耗費資源,使用本項目的ping或者其他鑑權,protobuff基本上消耗網路開銷非常的小,響應快,netty的長連接上線下立馬感知,性能穩定好。

開發環境

JDK8+IntelliJ IDEAspringboot 2.0.8.RELEASENetty4.1.6.Finalprotobuf-java3.3.0RedisThymeleaf模板Echarts圖表Tomcat8.5

項目說明

已完成功能客戶端授權驗證(基於protoBuff)心跳檢測(基於protoBuff)斷線重連計算ping值(支持到微秒)其他子業務模塊(架子已搭進去)為了方便測試,項目已經支持跨域訪問

說明

Netty是一個NIO客戶端服務器框架,可以快速輕鬆地開發協議服務器和客戶端等網絡應用程序。它極大地簡化並簡化了TCP和UDP套接字服務器等網絡編程。 “快速簡便”並不意味著最終的應用程序會受到可維護性或性能問題的影響。Netty經過精心設計,具有豐富的協議,如FTP,SMTP,HTTP以及各種二進制和基於文本的傳統協議。因此,Netty成功地找到了一種在不妥協的情況下實現易於開發,性能,穩定性和靈活性的方法。4x(推薦,穩定,jdk1.6+)

幾個常見的類

ServerBootstrap

netty服務器的幫助類

NioEventLoopGroup

處理I/O操作的多線程事件循環相當於一組線程池,服務器一般需要指定兩個NioEventLoopGroup,一個作為監控tcp連接的,一個作為處理io事件的,前者默認1個線程就可以,後者最好是cpu核心數的2倍 客戶端用一個就夠了

NioServerSocketChannel

主要是server端接收建立SocketChannel用的

NioSocketChannel

主要是客戶端接收SocketChannel用的

ChannelInboundHandlerAdapter

可以重寫的各種事件處理程序方法,包括channelRead()、exceptionCaught()等方法

SimpleChannelInboundHandler

可以重寫的各種事件處理程序方法,包括channelRead0()方法 這個可以跟指定的消息類型比上面的,如果自定義的消息類型用這個稍微多一點

ChannelPipeline

存放各種處理器,包括解碼器,編碼器等自定義處理器,idleStateHandler一定要放在第一個,傳送數據時,編碼器和解碼器一定要放在前面,這個加載是分順序的

ChannelHandlerContext

ChannelHandlerContext的writeAndFlush和ChannelHandlerContext.channel().writeAndFlush()是有區別的 前者是從當前hanler從後往前找OutputboundHandler,然後交給它執行的,後者是從最後一個開始執行handler的,最常見就是寫錯pipeline中的順序後,客戶端或服務器發消息就收不到了

ChannelInitializer

客戶端和服務器都要用這個的SocketChannel,初始化的時候,加載ChannelPipeline

Bootstrap

客戶端的連接幫助類

idleStateHandler

Netty 可以使用 IdleStateHandler 來實現連接管理,當連接空閒時間太長(沒有發送、接收消息)時則會觸發一個事件,我們便可在該事件中實現心跳機制

基本以上的幾個類就可以滿足日常的80%需求了,剩下就是書寫各自的業務

心跳服務器實現詳細過程

客戶端網絡空閒5秒沒有進行寫操作是,進行發送一次ping心跳給服務端;用自定義的消息格式類,其中包含驗證auth、ping、pong等類型來代表不同的業務,首次連接時候在ChannelInboundHandlerAdapter中可以建立連接,客戶端會發送一次auth類型的授權信息(用戶名+鹽值密碼),服務器收到後作出校驗響應,只有收到服務器的auth_ack響應客戶端才能做出連接,否則斷開當前鏈接,釋放鏈路;客戶端如果在下一個發送ping心跳週期來臨時,還沒有收到服務端pong的心跳應答,則失敗心跳計數器加1;每當客戶端收到服務端的pong心跳應答後,失敗心跳計數器清零;如果連續超過3次沒有收到服務端的心跳回復,則斷開當前連接,在5秒後進行重連操作,直到重連成功,否則每隔5秒又會進行重連;服務端網絡空閒狀態到達10秒後,服務端心跳失敗計數器加1;只要收到客戶端的ping消息,服務端心跳失敗計數器清零;服務端連續3次沒有收到客戶端的ping消息後,將關閉鏈路,釋放資源,等待客戶端重連;

心跳相關驗證

當客戶端超過三次沒有收到服務器pong,客戶端主動斷開當前channel連接,重連服務器

當服務器超過三次沒有收到客戶端ping,服務器主動斷開當前客戶端的channel連接

ping值設計過程

ping值是基於客戶端來的,即客戶端發送ping之後,會先記錄當前的時間(默認單位是ms),支持微秒的方法,當客戶端再次收到響應後,記錄當前時間a,因為數據傳輸雙方時間是相同的,所以拿當前時間b-a,再除以2就是ping值了。然後把這個ping值,記錄到redis中去。這裡使用的是 System.currentTimeMillis(),用new Date().getTime()時間會出錯,不知道為啥?看源碼是一樣的邏輯不大理解

起初是基於服務器計時的,但是服務器和客戶端不可能在一臺主機上,導致時間存在偏差,ping值就不準確了。 存到redis主要是為了使echarts訪問最近幾次的ping狀態。起初想做成websocket的,但是這樣的話,第一次進來當前頁面數據會不全,而且不好日後做歷史ping的統計

物聯網定製開發



先轉發,加關注後私信“netty源碼”即可免費獲取源碼