導航:首頁 > 配伺服器 > netty伺服器怎麼用

netty伺服器怎麼用

發布時間:2023-01-22 03:34:17

A. android 怎麼使用netty

Netty是由JBOSS提供的一個java開源框架。Netty提供非同步的、事件驅動的網路應用程序框架和工具,用以快速開發高性能、高可靠性的網路伺服器和客戶端程序。也就是說,Netty是一個基於NIO的客戶,伺服器端編程框架,它在socket的基礎上根據各種常用的應用協議又進一步封裝,提供更便利的介面。如果需要快速搭建一個C/S服務框架,那Netty過來用是沒錯。反過來你的情況是需要學習這個課程,你應該掌握基本的socket編程及其通信原理,所以學習時直接用socket編程比較好。也許哪一天,你靈感來了,編出一個比Netty更好的框架,一個更牛的軟體。

B. 怎麼使用netty寫一個http長連接伺服器

netty本身實現的長連接,就是一個連接一個worker。worker的數量是有限的(通常是cpu cores+1),所以你的伺服器要是連接數多的話,得考慮使用「非同步」Request(netty的http沒實現這么個功能),或者說「Continuation」,當連接「無事可做」的時候,放棄線程的使用權,當要處理事務的時候,才重新拿到一個線程。
當然,如果你只想實現長連接而不在意request 一直佔有worker,那麼你只要不放棄連接就可以了(websocket本身也是一種長連接,netty裡面有websocket的例子)。

C. netty系列之:使用netty搭建websocket客戶端

在網速快速提升的時代,瀏覽器已經成為我們訪問各種服務的入口,很難想像如果離開了瀏覽器,我們的網路世界應該如何運作。現在恨不得把操作系統都搬上瀏覽器。但是並不是所有的應用都需要瀏覽器來執行,比如伺服器和伺服器之間的通信,就需要使用到自建客戶端來和伺服器進行交互。

本文將會介紹使用netty客戶端連接websocket的原理和具體實現。

在介紹netty客戶端之前,我們先看一個簡單的瀏覽器客戶端連接websocket的例子:

這里使用了瀏覽器最通用的語言javascript,並使用了瀏覽器提供的websocket API進行操作,非常的簡單。

那麼用netty客戶端實現websocket的連接是否和javascript使用一樣呢?我們一起來 探索 。

先看看netty對websocket的支持類都有哪些,接著我們看下怎麼具體去使用這些工具類。

和websocket server一樣,client中最核心的類也是handshaker,這里叫做WebSocketClientHandshaker。這個類有什麼作用呢?一起來看看。

這個類主要實現的就是client和server端之間的握手。

我們看一下它的最長參數的構造類:

參數中有websocket連接的URI,像是:」ws://flydean.com/mypath」。

有請求子協議的類型subprotocol,有自定義的HTTP headers:customHeaders,有最大的frame payload的長度:maxFramePayloadLength,有強制timeout關閉的時間,有使用HTTP協議進行升級的URI地址。

怎麼創建handshaker呢?同樣的,netty提供了一個方法。

提供了一個newHandshaker方法,可以方便的創建各種不同版本的handshaker:

可以看到,根據傳入協議版本的不同,可以分為WebSocketClientHandshaker13、WebSocketClientHandshaker08、WebSocketClientHandshaker07、WebSocketClientHandshaker00這幾種。

通常來說,對於webSocket協議,為了提升傳輸的性能和速度,降低網路帶寬佔用量,在使用過程中通常會帶上額外的壓縮擴展。為了處理這樣的壓縮擴展,netty同時提供了伺服器端和客戶端的支持。

對於伺服器端來說對應的handler叫做,對於客戶端來說對應的handler叫做。

通過將這兩個handler加入對應pipline中,可以實現對websocket中壓縮協議擴展的支持。

對於協議的擴展有兩個級別分別是permessage-deflate和perframe-deflate,分別對應和。

至於具體怎麼壓縮的,這里就不詳細進行講解了, 感興趣的小夥伴可以自行了解。

前面講解了netty對websocket客戶端的支持之後,本節將會講解netty到底是如何使用這些工具進行消息處理的。

首先是按照正常的邏輯創建客戶端的Bootstrap,並添加handler。這里的handler就是專門為websocket定製的client端handler。

除了上面提到的,就是自定義的handler了。

在自定義handler中,我們需要處理兩件事情,一件事情就是在channel ready的時候創建handshaker。另外一件事情就是具體websocket消息的處理了。

首先使用創建handler:

然後在channel active的時候使用handshaker進行握手連接:

然後在進行消息接收處理的時候還需要判斷handshaker的狀態是否完成,如果未完成則調用handshaker.finishHandshake方法進行手動完成:

當handshake完成之後,就可以進行正常的websocket消息讀寫操作了。

websocket的消息處理比較簡單,將接收到的消息轉換成為WebSocketFrame進行處理即可。

本文講解了netty提供的websocket客戶端的支持和具體的對接流程,大家可以再次基礎上進行擴展,以實現自己的業務邏輯。

本文的例子可以參考:learn-netty4

D. netty 服務端怎麼監測鏈接

首先要有心跳包檢測的類 設定多少時間沒有在通道裡面讀取到信息則判定為斷線,把通道清除掉。

使用Netty實現心跳檢測:

E. netty伺服器在接收消息後,怎麼向另一台伺服器傳遞消息

第一種,netty伺服器接收到消息後,在channelRead方法里可以在起一個客戶端,通過這個客戶端向另一台伺服器傳遞消息。第二種,創建一個消息中轉的類,這個類可以接收消息,然後創建一個netty客戶端再將消息中轉類的消息傳遞給另一台伺服器。兩種都可以,只是第一種是內置客戶端,個人覺得第二種更靈活,不過我在做的時候採用的是第一種方法。

F. Netty實現長連接的原理

主要邏輯 :

使用netty實現長連接,主要靠心跳來維持伺服器端及客戶端連接。

主要的實現邏輯如下:

伺服器端 :(HeartBeatRespHandler)

1, 伺服器在網路空閑操作一定時間後,服務端失敗心跳計數器加1。

2, 如果收到客戶端的ping心跳包,則清零失敗心跳計數器,如果連續n次未收到客戶端的ping心跳包,則關閉鏈路,釋放資源,等待客戶端重連。

客戶端 :(HeartBeatReqHandler)

1, 客戶端網路空閑在一定時間內沒有進行寫操作時,則發送一個ping心跳包。

2, 如果伺服器端未在發送下一個心跳包之前回復pong心跳應答包,則失敗心跳計數器加1。

3, 如果客戶端連續發送n(此處根據具體業務進行定義)次ping心跳包,伺服器端均未回復pong心跳應答包,則客戶端斷開連接,間隔一定時間進行重連操作,直至連接伺服器成功。

G. netty系列之:NIO和netty詳解

netty為什麼快呢?這是因為netty底層使用了JAVA的NIO技術,並在其基礎上進行了性能的優化,雖然netty不是單純的JAVA nio,但是netty的底層還是基於的是nio技術。

nio是JDK1.4中引入的,用於區別於傳統的IO,所以nio也可以稱之為new io。

nio的三大核心是Selector,channel和Buffer,本文我們將會深入探究NIO和netty之間的關系。

在講解netty中的NIO實現之前,我們先來回顧一下JDK中NIO的selector,channel是怎麼工作的。對於NIO來說selector主要用來接受客戶端的連接,所以一般用在server端。我們以一個NIO的伺服器端和客戶端聊天室為例來講解NIO在JDK中是怎麼使用的。

因為是一個簡單的聊天室,我們選擇Socket協議為基礎的ServerSocketChannel,首先就是open這個Server channel:

然後向server channel中注冊selector:

雖然是NIO,但是對於Selector來說,它的select方法是阻塞方法,只有找到匹配的channel之後才會返回,為了多次進行select操作,我們需要在一個while循環裡面進行selector的select操作:

selector中會有一些SelectionKey,SelectionKey中有一些表示操作狀態的OP Status,根據這個OP Status的不同,selectionKey可以有四種狀態,分別是isReadable,isWritable,isConnectable和isAcceptable。

當SelectionKey處於isAcceptable狀態的時候,表示ServerSocketChannel可以接受連接了,我們需要調用register方法將serverSocketChannel accept生成的socketChannel注冊到selector中,以監聽它的OP READ狀態,後續可以從中讀取數據:

當selectionKey處於isReadable狀態的時候,表示可以從socketChannel中讀取數據然後進行處理:

上面的serverResponse方法中,從selectionKey中拿到對應的SocketChannel,然後調用SocketChannel的read方法,將channel中的數據讀取到byteBuffer中,要想回復消息到channel中,還是使用同一個socketChannel,然後調用write方法回寫消息給client端,到這里一個簡單的回寫客戶端消息的server端就完成了。

接下來就是對應的NIO客戶端,在NIO客戶端需要使用SocketChannel,首先建立和伺服器的連接:

然後就可以使用這個channel來發送和接受消息了:

向channel中寫入消息可以使用write方法,從channel中讀取消息可以使用read方法。

這樣一個NIO的客戶端就完成了。

雖然以上是NIO的server和client的基本使用,但是基本上涵蓋了NIO的所有要點。接下來我們來詳細了解一下netty中NIO到底是怎麼使用的。

以netty的ServerBootstrap為例,啟動的時候需要指定它的group,先來看一下ServerBootstrap的group方法:

ServerBootstrap可以接受一個EventLoopGroup或者兩個EventLoopGroup,EventLoopGroup被用來處理所有的event和IO,對於ServerBootstrap來說,可以有兩個EventLoopGroup,對於Bootstrap來說只有一個EventLoopGroup。兩個EventLoopGroup表示acceptor group和worker group。

EventLoopGroup只是一個介面,我們常用的一個實現就是NioEventLoopGroup,如下所示是一個常用的netty伺服器端代碼:

這里和NIO相關的有兩個類,分別是NioEventLoopGroup和NioServerSocketChannel,事實上在他們的底層還有兩個類似的類分別叫做NioEventLoop和NioSocketChannel,接下來我們分別講解一些他們的底層實現和邏輯關系。

NioEventLoopGroup和DefaultEventLoopGroup一樣都是繼承自MultithreadEventLoopGroup:

他們的不同之處在於newChild方法的不同,newChild用來構建Group中的實際對象,NioEventLoopGroup來說,newChild返回的是一個NioEventLoop對象,先來看下NioEventLoopGroup的newChild方法:

這個newChild方法除了固定的executor參數之外,還可以根據NioEventLoopGroup的構造函數傳入的參數來實現更多的功能。

這里參數中傳入了SelectorProvider、SelectStrategyFactory、RejectedExecutionHandler、taskQueueFactory和tailTaskQueueFactory這幾個參數,其中後面的兩個EventLoopTaskQueueFactory並不是必須的。

最後所有的參數都會傳遞給NioEventLoop的構造函數用來構造出一個新的NioEventLoop。

在詳細講解NioEventLoop之前,我們來研讀一下傳入的這幾個參數類型的實際作用。

SelectorProvider是JDK中的類,它提供了一個靜態的provider()方法可以從Property或者ServiceLoader中載入對應的SelectorProvider類並實例化。

另外還提供了openDatagramChannel、openPipe、openSelector、openServerSocketChannel和openSocketChannel等實用的NIO操作方法。

SelectStrategyFactory是一個介面,裡面只定義了一個方法,用來返回SelectStrategy:

什麼是SelectStrategy呢?

先看下SelectStrategy中定義了哪些Strategy:

SelectStrategy中定義了3個strategy,分別是SELECT、CONTINUE和BUSY_WAIT。

我們知道一般情況下,在NIO中select操作本身是一個阻塞操作,也就是block操作,這個操作對應的strategy是SELECT,也就是select block狀態。

如果我們想跳過這個block,重新進入下一個event loop,那麼對應的strategy就是CONTINUE。

BUSY_WAIT是一個特殊的strategy,是指IO 循環輪詢新事件而不阻塞,這個strategy只有在epoll模式下才支持,NIO和Kqueue模式並不支持這個strategy。

RejectedExecutionHandler是netty自己的類,和 java.util.concurrent.RejectedExecutionHandler類似,但是是特別針對SingleThreadEventExecutor來說的。這個介面定義了一個rejected方法,用來表示因為SingleThreadEventExecutor容量限制導致的任務添加失敗而被拒絕的情況:

EventLoopTaskQueueFactory是一個介面,用來創建存儲提交給EventLoop的taskQueue:

這個Queue必須是線程安全的,並且繼承自java.util.concurrent.BlockingQueue.

講解完這幾個參數,接下來我們就可以詳細查看NioEventLoop的具體NIO實現了。

首先NioEventLoop和DefaultEventLoop一樣,都是繼承自SingleThreadEventLoop:

表示的是使用單一線程來執行任務的EventLoop。

首先作為一個NIO的實現,必須要有selector,在NioEventLoop中定義了兩個selector,分別是selector和unwrappedSelector:

在NioEventLoop的構造函數中,他們是這樣定義的:

首先調用openSelector方法,然後通過返回的SelectorTuple來獲取對應的selector和unwrappedSelector。

這兩個selector有什麼區別呢?

在openSelector方法中,首先通過調用provider的openSelector方法返回一個Selector,這個Selector就是unwrappedSelector:

然後檢查DISABLE_KEY_SET_OPTIMIZATION是否設置,如果沒有設置那麼unwrappedSelector和selector實際上是同一個Selector:

DISABLE_KEY_SET_OPTIMIZATION表示的是是否對select key set進行優化:

如果DISABLE_KEY_SET_OPTIMIZATION被設置為false,那麼意味著我們需要對select key set進行優化,具體是怎麼進行優化的呢?

先來看下最後的返回:

最後返回的SelectorTuple第二個參數就是selector,這里的selector是一個對象。

繼承自selector,構造函數傳入的第一個參數是一個delegate,所有的Selector中定義的方法都是通過調用
delegate來實現的,不同的是對於select方法來說,會首先調用selectedKeySet的reset方法,下面是以isOpen和select方法為例觀察一下代碼的實現:

selectedKeySet是一個SelectedSelectionKeySet對象,是一個set集合,用來存儲SelectionKey,在openSelector()方法中,使用new來實例化這個對象:

netty實際是想用這個SelectedSelectionKeySet類來管理Selector中的selectedKeys,所以接下來netty用了一個高技巧性的對象替換操作。

首先判斷系統中有沒有sun.nio.ch.SelectorImpl的實現:

SelectorImpl中有兩個Set欄位:

這兩個欄位就是我們需要替換的對象。如果有SelectorImpl的話,首先使用Unsafe類,調用PlatformDependent中的objectFieldOffset方法拿到這兩個欄位相對於對象示例的偏移量,然後調用putObject將這兩個欄位替換成為前面初始化的selectedKeySet對象:

如果系統設置不支持Unsafe,那麼就用反射再做一次:

還記得前面我們提到的selectStrategy嗎?run方法通過調用selectStrategy.calculateStrategy返回了select的strategy,然後通過判斷
strategy的值來進行對應的處理。

如果strategy是CONTINUE,這跳過這次循環,進入到下一個loop中。

BUSY_WAIT在NIO中是不支持的,如果是SELECT狀態,那麼會在curDeadlineNanos之後再次進行select操作:

如果strategy > 0,表示有拿到了SelectedKeys,那麼需要調用processSelectedKeys方法對SelectedKeys進行處理:

上面提到了NioEventLoop中有兩個selector,還有一個selectedKeys屬性,這個selectedKeys存儲的就是Optimized SelectedKeys,如果這個值不為空,就調用processSelectedKeysOptimized方法,否則就調用processSelectedKeysPlain方法。

processSelectedKeysOptimized和processSelectedKeysPlain這兩個方法差別不大,只是傳入的要處理的selectedKeys不同。

處理的邏輯是首先拿到selectedKeys的key,然後調用它的attachment方法拿到attach的對象:

如果channel還沒有建立連接,那麼這個對象可能是一個NioTask,用來處理channelReady和channelUnregistered的事件。

如果channel已經建立好連接了,那麼這個對象可能是一個AbstractNioChannel。

針對兩種不同的對象,會去分別調用不同的processSelectedKey方法。

對第一種情況,會調用task的channelReady方法:

對第二種情況,會根據SelectionKey的readyOps()的各種狀態調用ch.unsafe()中的各種方法,去進行read或者close等操作。

NioEventLoop雖然也是一個SingleThreadEventLoop,但是通過使用NIO技術,可以更好的利用現有資源實現更好的效率,這也就是為什麼我們在項目中使用NioEventLoopGroup而不是DefaultEventLoopGroup的原因。

H. netty系列之:一口多用,使用同一埠運行不同協議

在之前的文章中,我們介紹了在同一個netty程序中支持多個不同的服務,它的邏輯很簡單,就是在一個主程序中啟動多個子程序,每個子程序通過一個BootStrap來綁定不同的埠,從而達到訪問不同埠就訪問了不同服務的目的。

但是多個埠雖然區分度夠高,但是使用起來還是有諸多不便,那麼有沒有可能只用一個埠來統一不同的協議服務呢?

今天給大家介紹一下在netty中使用同一埠運行不同協議的方法,這種方法叫做port unification。

在講解自定義port unification之前,我們來看下netty自帶的port unification,比如。

我們知道SOCKS的主要協議有3中,分別是SOCKS4、SOCKS4a和SOCKS5,他們屬於同一種協議的不同版本,所以肯定不能使用不同的埠,需要在同一個埠中進行版本的判斷。

具體而言,繼承自ByteToMessageDecoder,表示是將ByteBuf轉換成為對應的Socks對象。

那他是怎麼區分不同版本的呢?

在decode方法中,傳入了要解碼的ByteBuf in,首先獲得它的readerIndex:

我們知道SOCKS協議的第一個位元組表示的是版本,所以從in ByteBuf中讀取第一個位元組作為版本號:

有了版本號就可以通過不同的版本號進行處理,具體而言,對於SOCKS4a,需要添加Socks4ServerEncoder和Socks4ServerDecoder:

對於SOCKS5來說,需要添加Socks5ServerEncoder和Socks5InitialRequestDecoder兩個編碼和解碼器:

這樣,一個port unification就完成了,其思路就是通過傳入的同一個埠的ByteBuf的首位元組,來判斷對應的SOCKS的版本號,從而針對不同的SOCKS版本進行處理。

在本例中,我們將會創建一個自定義的Port Unification,用來同時接收HTTP請求和gzip請求。

在這之前,我們先看一下兩個協議的magic word,也就是說我們拿到一個ByteBuf,怎麼能夠知道這個是一個HTTP協議,還是傳輸的一個gzip文件呢?

先看下HTTP協議,這里我們默認是HTTP1.1,對於HTTP1.1的請求協議,下面是一個例子:

HTTP請求的第一個單詞就是HTTP請求的方法名,具體而言有八種方法,分別是:

OPTIONS
返回伺服器針對特定資源所支持的HTTP請求方法。也可以利用向Web伺服器發送'*'的請求來測試伺服器的功能性。
HEAD
向伺服器索要與GET請求相一致的響應,只不過響應體將不會被返回。這一方法可以在不必傳輸整個響應內容的情況下,就可以獲取包含在響應消息頭中的元信息。
GET
向特定的資源發出請求。注意:GET方法不應當被用於產生「副作用」的操作中,例如在Web Application中。其中一個原因是GET可能會被網路蜘蛛等隨意訪問。
POST
向指定資源提交數據進行處理請求(例如提交表單或者上傳文件)。數據被包含在請求體中。POST請求可能會導致新的資源的建立和/或已有資源的修改。
PUT
向指定資源位置上傳其最新內容。
DELETE
請求伺服器刪除Request-URI所標識的資源。
TRACE
回顯伺服器收到的請求,主要用於測試或診斷。
CONNECT
HTTP/1.1協議中預留給能夠將連接改為管道方式的代理伺服器

那麼需要幾個位元組來區分這八個方法呢?可以看到一個位元組是不夠的,因為我們有POST和PUT,他們的第一個位元組都是P。所以應該使用2個位元組來作為magic word。

對於gzip協議來說,它也有特殊的格式,其中gzip的前10個位元組是header,其中第一個位元組是0x1f,第二個位元組是0x8b。

這樣我們用兩個位元組也能區分gzip協議。

這樣,我們的handler邏輯就出來了。首先從byteBuf中取出前兩個位元組,然後對其進行判斷,區分出是HTTP請求還是gzip請求:

對應的,我們還需要對其添加相應的編碼和解碼器,對於gzip來說,netty提供了ZlibCodecFactory:

對於HTTP來說,netty也提供了HttpRequestDecoder和HttpResponseEncoder還有HttpContentCompressor來對HTTP消息進行編碼解碼和壓縮。

添加了編碼和解碼器之後,如果你想自定義一些操作,只需要再添加自定義的對應的消息handler即可,非常的方便。

本文的例子可以參考: learn-netty4

I. netty基本使用- socket通信

[netty 基本使用- 作為http伺服器][gcssloop]
[gcssloop]: http://www.jianshu.com/p/cd88723c96dc

ServerSocket.java

** ServerInitializer.java **

** ServerHandler.java 處理業務 **

** ClientSocket.java **

** Clientinitializer.java **

**ClientHandler.java 處理業務 **

** 可以多次和伺服器端通信的寫法 **

netty 常用的處理大數據分包傳輸問題的解決類。

編碼類,自動將

+----------------+

| "HELLO, WORLD" |

+----------------+

格式的數據轉換成

+--------+----------------+

+--------+----------------+

格式的數據

[netty 數據分包、組包、粘包處理機制][123]
[123]: http://blog.163.com/linfenliang@126/blog/static/127857195201210821145721/

閱讀全文

與netty伺服器怎麼用相關的資料

熱點內容
大型雲伺服器有哪些 瀏覽:466
解壓版三國街機 瀏覽:423
去中心化app裡麵包含什麼 瀏覽:948
密鑰安裝命令行 瀏覽:505
文獻編譯英文 瀏覽:659
php調用瀏覽器 瀏覽:527
數控車床編程初學實例 瀏覽:949
cad中篩選命令是什麼 瀏覽:800
數控銑床法蘭克編程 瀏覽:330
怎麼樣分解壓縮包圖標 瀏覽:619
php兩年工作經驗簡歷 瀏覽:765
怎麼提前解壓房貸 瀏覽:699
反詐宣傳app哪裡可以拿到用戶資料 瀏覽:856
華為交換機命令配置 瀏覽:12
電機pid演算法實例c語言 瀏覽:974
安裝ue5未找到金屬編譯器 瀏覽:965
l1壓縮性骨折微創手術 瀏覽:617
看電腦配置命令 瀏覽:110
單片機調用db數值偏移量 瀏覽:447
賓士smart車型壓縮機功率 瀏覽:529