足彩总进球数怎么中奖 竞彩足球总进球在哪看 总进球计算器 竞彩总进球数怎么算 世界杯荷兰总进球数 c罗职业生涯总进球数 裁判员总进球 竞彩足球总进球大小球 竞彩总进球数复选 c罗职业生涯总进球650 总进球数难于上青天 c罗总进球650 欧冠总进球c罗 竞猜总进球计算器 计算器足球总进球数玩法

Java高階必備之Netty基礎原理


   


  Netty是Java程序員通向高階之路必須要過的門檻之一。干了幾年的Java程序員發現業務開發似乎就是在SSH的世界里摸滾打爬的時候,會開始感到迷茫,難道程序員的日子就是如此枯燥么?深入使用一下Netty,另一個世界的大門就會開始打開。枯燥的編碼會漸漸變得有趣,自主思考的能力也會開始加強。


  Netty是建立在Java NIO基礎之上最廣泛使用的高性能網絡框架。了解Netty之前,必須對NIO的概念有所了解。


  NIO的意思是非阻塞IO,也就是說單個線程可以同時進行多個IO操作,而不會被任何IO操作阻塞住。同一個線程即能同時Accept網絡套件字,又可以同時對套件字進行讀寫操作,然后還可以同時處理消息。

  NIO基于事件機制,所有的IO操作都能抽象成一個事件。當新連接到來時,可以從內核中拿到ServerSocket的可讀事件。當連接上的消息到來時,可以從內核中拿到Socket的讀事件。當Socket中的緩沖區未滿的時候,可以從內核中拿到Socket的可寫事件。


  當NIO線程從內核中拿到一個事件Event,就會開始使用相應的事件處理器EventHandler對這個事件進行處理。如果拿到ServerSocket可讀事件,就會調用ServerSocket.accept獲取一個新的Socket連接,然后將這個Socket連接加入到感興趣的描述符列表中,如果拿到Socket可讀事件就會開始調用Socket.read讀取套件字的消息進行處理,處理完畢將返回結果序列化成一個字節數組,當Socket可以拿到可寫事件時,說明套件字緩沖區未滿,就拼命的將字節數組往Socket里灌,也就是調用Socket.write進行IO的寫操作。



  1.png

 

  NIO從內核中拿事件的操作使用的是Selector.select函數調用,它對應操作系統界面的IO多路復用API。在現代操作系統里mac平臺上對應的是kqueue模型,linux平臺對應的是epoll模型,windows平臺對應的是iocp模型。Java是一個跨平臺的語言,JVM底層對操作系統的具體實現進行了抽象,統一向上層提供的是Selector系列API。用戶只需要使用Selector提供的通用API來處理NIO相關功能即可,而無需關系底層具的操作系統API的差別了。


  Selector可以理解為一個描述符對象[SocketChannel]列表,Selector通過調用操作系統API,傳遞一個描述符列表參數,然后就可以拿到內核提供的與所有的描述符相關的事件[Key]列表。

 

2.png 


  上面提到的NIO線程是一個單線程,但是實際上它可以是一個線程池,線程池中的每個線程負責一部分描述符的讀寫操作。它也可以是兩個線程池,一個線程池只用來處理ServerSocket描述符建立新連接,另一個線程池專門干Socket讀寫的事。


 3.png 


  Netty提供了良好的封裝,可以讓我們很方便的配置線程池的功用。代碼中的NioEventLoopGroup代表的就是一個線程池,池中每個線程都是一個獨立的NioEventLoop,即Nio事件循環。當acceptor線程池接收到一個新連接后會將這個連接通過隊列發送到讀寫線程池繼續進行處理。線程池分開的好處是當讀寫線程池繁忙的時候不影響acceptor接收新連接。


  NIO的讀寫操作也是一系列復雜的過程。當NIO讀事件發生時,線程使用read操作讀取到的消息可能是不完整的,剩下的部分可能還要在接下來多次讀事件發生后才能讀到完整的一個消息對象字節數組。也可能read操作讀取到的消息包含多個消息對象,最后剩下的部分又是一個不完整的消息,這就需要在每個描述符關聯對象中保存中間半包的狀態。消息和消息之間又有組合關系,比如HTTP POST消息包含HTTP Header和HTTP Body兩個部分,而HTTP Body又可能因為太大而分解為多個HTTP Chunks進行傳輸,這就要求NIO的讀寫消息的設計包含結構層級。寫操作也不是一個簡單的write操作就了事了,寫操作要考慮到內核為每個套件字分配的buffer大小,如果buffer不夠了,write寫進去的數組是不能完全寫進去的,寫不進去的字節數據必須保留起來,等待下次寫事件發生時,也就是內核緩沖有空閑空間了,才可以將剩下的數據發送過去。

 

4.png 


  Netty將消息的讀寫抽象為pipeline消息管道,結構上有點類似于計算機網絡分層結構。pipeline的每一層會對應一個Handler,以上一層輸出的消息結構作為輸入,輸出新的消息結構作為下一層的輸入。pipeline對象掛接在每一個Socket鏈路上。

  

5.png 


  代碼中我們在pipeline里定義了四層Handler,第一個是處理ReadTimeout,當一個連接長達60s沒有任何消息的情況下會向下一層輸出一個讀超時消息。第二層是一個Redis消息解碼器,將Socket中的字節流轉換成Redis命令對象,第三層是一個Redis消息編碼器,將Redis輸出對象轉稱字節流,第四層是消息處理器,用來逐個處理Redis命令邏輯,這里一般就是我們復雜的業務邏輯所在地,我們會在業務邏輯里最終給Socket回饋消息輸出,這個消息輸出又會走一遍pipeline的每一層,直到轉換成字節流寫到內核socket緩沖區中才算完事。


  然后我們設置一些套件字的特殊屬性,比如監聽隊列大小、讀寫緩沖警戒水位大小、是否延遲發送等,然后綁定監聽指定端口,服務器就可以開始永無止盡地工作了。



2012年梅西总进球数
足彩总进球数怎么中奖 竞彩足球总进球在哪看 总进球计算器 竞彩总进球数怎么算 世界杯荷兰总进球数 c罗职业生涯总进球数 裁判员总进球 竞彩足球总进球大小球 竞彩总进球数复选 c罗职业生涯总进球650 总进球数难于上青天 c罗总进球650 欧冠总进球c罗 竞猜总进球计算器 计算器足球总进球数玩法
开个休闲零食店赚钱吗 盛世皇朝游戏 福彩3d专家预测 体彩新11选5最优玩法 竞彩离散指数查看 攒劲甘肃麻将交流群 大学校园赚钱的店面 手游棋牌排行 现金游戏捕鱼达人 推荐一个可以兼职赚钱的网站 蓝盾国际娱乐注册 怎样买大小单双技巧 江西快三预测贴吧 奔驰宝马单机免费游戏下载 现在卖课程赚钱 新浪斗地主游戏大厅