Java編寫基于netty的RPC框架

一 簡單概念RPC: ( Remote Procedure Call),遠程調用過程,是通過網絡調用遠程計算機的進程中某個方法,從而獲取到想要的數據,過程如同調用本地的方法一樣.阻塞IO :當阻塞I/O在調用InputStream.read()方法是阻塞的,一直等到數據到來時才返回,同樣ServerSocket.accept()方法時,也是阻塞,直到有客戶端連接才返回,I/O通信模式如下:
復制代碼

圖片描述(最多50字)

缺點:當客戶端多時,會創建大量的處理線程,并且為每一個線程分配一定的資源;阻塞可能帶來頻繁切換上下文,這時引入NIONIO : jdk1.4引入的(NEW Input/Output),是基于通過和緩存區的I/O方式,(插入一段題外話,學的多忘得也多,之前有認真研究過NIO,后來用到的時候,忘得一干二凈,所以學習一些東西,經常返回看看),NIO是一種非阻塞的IO模型,通過不斷輪詢IO事件是否就緒,非阻塞是指線程在等待IO的時候,可以做其他的任務,同步的核心是Selector,Selector代替線程本省的輪詢IO事件,避免了阻塞同時減少了不必要的線程消耗;非阻塞的核心是通道和緩存區,當IO事件的就緒時,可以將緩存區的數據寫入通道
復制代碼

圖片描述(最多50字)

其工作原理:1 由專門的線程來處理所有的IO事件,并且負責轉發2 事件驅動機制:事件到的時候才觸發,而不是同步監視3 線程通訊:線程之間通訊通過wait,notify等方式通訊,保證每次上下文切換都是有意義的,減少沒必要的線程切換通道 : 是對原I/O包中流的模擬,所有數據必須通過Channel對象,常見的通道FileChannel,SocketChannel,ServerSocketChannel,DatagramChannel(UDP協議向網絡連接的兩端讀寫數據)
復制代碼

圖片描述(最多50字)

Buffer緩存區 :實際上是一個容器,一個連續的數組,任何讀寫的數據都經過Buffer
復制代碼

圖片描述(最多50字)

Netty :是由JBOSS提供的一個java開源框架,是一個高性能,異步事件驅動的NIO框架,基于JAVA NIO提供的API實現,他提供了TCP UDP和文件傳輸的支持,,所有操作都是異步非阻塞的.通過Futrue-Listener機制,本質就是Reactor模式的現實,Selector作為多路復用器,EventLoop作為轉發器,而且,netty對NIO中buffer做優化,大大提高了性能二 Netty 客戶端和服務端的Netty中Bootstrap和Channel的生命周期Bootstrap簡介Bootstarp:引導程序,將ChannelPipeline,ChannelHandler,EventLoop進行整體關聯
復制代碼

圖片描述(最多50字)

Bootstrap具體分為兩個實現ServerBootstrap:用于服務端,使用一個ServerChannel接收客戶端的連接,并創建對應的子ChannelBootstrap:用于客戶端,只需要一個單獨的Channel,配置整個Netty程序,串聯起各個組件二者的主要區別:1 ServerBootstrap用于Server端,通過調用bind()綁定一個端口監聽連接,Bootstrap用于Client端,需要調用connect()方法來連接服務器端,我們也可以調用bind()方法接收返回ChannelFuture中Channel2 客戶端的Bootstrap一般用一個EventLoopGroup,而服務器的ServerBootstrap會用兩個第一個EventLoopGroup專門負責綁定到端口監聽連接事件,而第二個EventLoopGroup專門用來處處理每個接收的連接,這樣大大提高了并發量
復制代碼

public class Server { public static void main(String[] args) throws Exception { // 1 創建線兩個事件循環組 // 一個是用于處理服務器端接收客戶端連接的 // 一個是進行網絡通信的(網絡讀寫的) EventLoopGroup pGroup = new NioEventLoopGroup(); EventLoopGroup cGroup = new NioEventLoopGroup(); // 2 創建輔助工具類ServerBootstrap,用于服務器通道的一系列配置 ServerBootstrap b = new ServerBootstrap(); b.group(pGroup, cGroup) // 綁定倆個線程組 .channel(NioServerSocketChannel.class) // 指定NIO的模式.NioServerSocketChannel對應TCP, NioDatagramChannel對應UDP .option(ChannelOption.SO_BACKLOG, 1024) // 設置TCP緩沖區 .option(ChannelOption.SO_SNDBUF, 32 * 1024) // 設置發送緩沖大小 .option(ChannelOption.SO_RCVBUF, 32 * 1024) // 這是接收緩沖大小 .option(ChannelOption.SO_KEEPALIVE, true) // 保持連接 .childHandler(new ChannelInitializer() { @Override protected void initChannel(SocketChannel sc) throws Exception { //SocketChannel建立連接后的管道 // 3 在這里配置 通信數據的處理邏輯, 可以addLast多個... sc.pipeline().addLast(new ServerHandler()); } }); // 4 綁定端口, bind返回future(異步), 加上sync阻塞在獲取連接處 ChannelFuture cf1 = b.bind(8765).sync(); //ChannelFuture cf2 = b.bind(8764).sync(); //可以綁定多個端口 // 5 等待關閉, 加上sync阻塞在關閉請求處 cf1.channel().closeFuture().sync(); //cf2.channel().closeFuture().sync(); pGroup.shutdownGracefully(); cGroup.shutdownGracefully(); } }

public class ServerHandler extends ChannelHandlerAdapter { @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { System.out.println("server channel active... "); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf buf = (ByteBuf) msg; byte[] req = new byte[buf.readableBytes()]; buf.readBytes(req); String body = new String(req, "utf-8"); System.out.println("Server :" + body ); String response = "返回給客戶端的響應:" + body ; ctx.writeAndFlush(Unpooled.copiedBuffer(response.getBytes())); // future完成后觸發監聽器, 此處是寫完即關閉(短連接). 因此需要關閉連接時, 要通過server端關閉. 直接關閉用方法ctx[.channel()].close() //.addListener(ChannelFutureListener.CLOSE); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { System.out.println("讀完了"); ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable t) throws Exception { ctx.close(); } }

public class Client { public static void main(String[] args) throws Exception {

EventLoopGroup group = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel sc) throws Exception { sc.pipeline().addLast(new ClientHandler());}
});ChannelFuture cf1 = b.connect("127.0.0.1", 8765).sync();
//ChannelFuture cf2 = b.connect("127.0.0.1", 8764).sync(); //可以使用多個端口
//發送消息, Buffer類型. write需要flush才發送, 可用writeFlush代替
cf1.channel().writeAndFlush(Unpooled.copiedBuffer("777".getBytes()));
cf1.channel().writeAndFlush(Unpooled.copiedBuffer("666".getBytes()));
Thread.sleep(2000);
cf1.channel().writeAndFlush(Unpooled.copiedBuffer("888".getBytes()));
//cf2.channel().writeAndFlush(Unpooled.copiedBuffer("999".getBytes()));cf1.channel().closeFuture().sync();
//cf2.channel().closeFuture().sync();
group.shutdownGracefully();
復制代碼

} }

public class ClientHandler extends ChannelHandlerAdapter{ @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { try { ByteBuf buf = (ByteBuf) msg; byte[] req = new byte[buf.readableBytes()]; buf.readBytes(req); String body = new String(req, "utf-8"); System.out.println("Client :" + body ); } finally { // 記得釋放xxxHandler里面的方法的msg參數: 寫(write)數據, msg引用將被自動釋放不用手動處理; 但只讀數據時,!必須手動釋放引用數 ReferenceCountUtil.release(msg); } } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { ctx.close(); } } 其他組件:

Handle: 為了支持各種協議和處理數據的方式,可以是連接,數據接收,異常,數據格式轉換等ChannelHandlerChannelInboundHandler :最常用的Handler,作用是處理接收數據的事件,來處理我們的核心業務邏輯。ChannelInitializer :,當一個鏈接建立時,我們需要知道怎么來接收或者發送數據,當然,我們有各種各樣的Handler實現來處理它,那么ChannelInitializer便是用來配置這些Handler,它會提供一個ChannelPipeline,并把Handler加入到ChannelPipeline。ChannelPipeline :一個Netty應用基于ChannelPipeline機制,這種機制依賴EventLoop和EventLoopGroup,這三個都和事件或者事件處理相關EventLoop : 為Channel處理IO操作,一個EventLoop可以為多個Channel服務EventLoopGroup :包含多個EventLoopChannel :代表一個Socket連接Future :在Netty中所有的IO操作都是異步的,,因此我們不知道,過來的請求是否被處理了,所以我們注冊一個監聽,當操作執行成功或者失敗時監聽自動觸發,所有操作都會返回一個ChannelFutrueChannelFutureNetty 是一個非阻塞的,事件驅動的,網絡編程框架,我們通過一張圖理解一下,Channel,EventLoop以及EventLoopGroup之間的關系
復制代碼

圖片描述(最多50字)

解釋一下,當一個連接過來,Netty首先會注冊一個channel,然后EventLoopGroup會分配一個EventLoop綁定到這個channel,在這個channel的整個生命周期過程中,這個EventLoop一直為他服務,這個玩意就是一個線程
復制代碼

圖片描述(最多50字)

這下聊一下Netty如何處理數據?前面有講到,handler數據處理核心,,而ChannelPipeline負責安排Handler的順序和執行,我們可以這樣理解,數據在ChannelPipeline中流動,其中ChannelHandler就是一個個閥門,這些數據都會經過每一個ChannelHandler并且被他處理,其中ChannelHandler的兩個子類ChannelOutboundHandler和ChannelInboundHandler,根據不同的流向,選擇不同的Handler
復制代碼

圖片描述(最多50字)

由圖可以看出,一個數據流進入ChannelPipeline時,一個一個handler挨著執行,各個handler的數據傳遞,這需要調用方法中ChannelHandlerContext來操作,而這個ChannelHandlerContext可以用來讀寫Netty中的數據流三 Netty中的業務處理netty中會有很多Handler.具體哪一種Handler還要看繼承是InboundAdapter還是OutboundAdapter,Netty中提供一系列的Adapter來幫助我們簡化開發,在ChannelPipeline中的每一個handler都負責把Event傳遞個洗下一個handler,有這些adapter,這些工作可以自動完成,,我們只需覆蓋我們真正實現的部分即可,接下來比較常用的三種ChannelHandlerEncoders和Decodeers我們在網絡傳輸只能傳輸字節流,在發送數據時,把我們的message轉換成bytes這個過程叫Encode(編碼),相反,接收數據,需要把byte轉換成message,這個過程叫Decode(解碼)Domain Logic我們真正關心的如何處理解碼以后的數據,我們真正的業務邏輯便是接收處理的數據,Netty提供一個常用的基類就是SimpleChannelInboundHandler<T>,其中T就是Handler處理的數據類型,消息到達這個Handler,會自動調用這個Handler中的channelRead0(ChannelHandlerContext,T)方法,T就是傳過來的數據對象四 基于netty實現的Rpc的例子這是我的github上項目的位置https://github.com/developerxiaofeng/rpcByNetty項目目錄結構如下
復制代碼

圖片描述(最多50字)

詳細的項目細節看類中的注釋,很詳細哦!!!
復制代碼

歡迎工作一到五年的Java工程師朋友們加入Java架構開發: 855835163 群內提供免費的Java架構學習資料(里面有高可用、高并發、高性能及分布式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/253016.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/253016.shtml
英文地址,請注明出處:http://en.pswp.cn/news/253016.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

linux下c和c++互相調用

c調用cpp 創建個目錄 創建4個文件 c.c--c文件 cpp.cpp--c文件 cpp.hh--c聲明文件 Makefile c.c [javascript] view plaincopy#include "cpp.hh" int main() { cpp_fun(); } cpp.cpp [cpp] view plaincopy#include "cpp.hh" #include <stdi…

Applications Manager Docker監控

Docker 是一個流行的開源容器應用程序&#xff0c;允許您將應用程序、應用程序的內部依賴和關聯庫打包到一個單元中。Docker 的主要優點在于單臺機器上的多個 docker 容器共享同一操作系統內核&#xff0c;這可以幫助提升性能和節省大量內存。監控 docker 容器會很困難&#xf…

find

Linux中find常見用法示例 find path -option [ -print ] [ -exec -ok command ] {} \; find命令的參數&#xff1b; pathname: find命令所查找的目錄路徑。例如用.來表示當前目錄&#xff0c;用/來表示系統根目錄。-print&#xff1a; find命令將匹配的文件輸出…

PHP將多個文件中的內容合并為新的文件

function test(){$hostdir iconv("utf-8","gbk","C:\Users\原萬里\Desktop\日常筆記") ; //iconv()轉換編碼方式&#xff0c;將UTF-8轉換為gbk&#xff0c;若是報錯在gbk后加//IGNORE$filesnames scandir($hostdir); …

HTTP Live Streaming直播(iOS直播)技術分析與實現

不經意間發現&#xff0c;大半年沒寫博客了&#xff0c;自覺汗顏。實則2012后半年&#xff0c;家中的事一樣接著一樣發生&#xff0c;實在是沒有時間。快過年了&#xff0c;總算忙里偷閑&#xff0c;把最近的一些技術成果&#xff0c;總結成了文章&#xff0c;與大家分享。 前些…

中文論文格式【雜】

轉自知乎&#xff0c;https://www.zhihu.com/question/23791742/answer/344752056 【紙張】畢業論文一律打印&#xff0c;采取A4紙張&#xff0c;頁邊距一律采取&#xff1a;上、下2.5cm&#xff0c;左3cm,右1.5cm&#xff0c;行間距取多倍行距(設置值為1.25);字符間距為默認值…

jmeter 非gui 模式跑jmx

D:\study\apache-jmeter-3.0\bin>jmeter -n -t D:\study\apache-jmeter-3.0\基金排行.jmx -l D:\study\apache-jmeter-3.0\result_log\獲取基金排行.jtl D:\study\apache-jmeter-3.2\bin>jmeter -n -t D:\study\apache-jmeter-3.2\bin\examples\test\百度新聞首頁.jmx -l…

noip模擬賽 遭遇

分析&#xff1a;暴力挺好打的&#xff0c;對于前30%的數據神搜&#xff0c;hi相同的數據將所有的建筑按照c從小到大排序&#xff0c;看最多能跳多少,ci0的數據將所有的建筑按照h從小到大排序&#xff0c;枚舉起點和終點&#xff0c;看能否跳這么多,取個max就可以了.這樣70分就…

揭開全景相機創業真相:國外一開源國內就自主

今年以來全景相機有了一個大爆發&#xff0c;國外Google、三星、諾基亞等大廠都進入了這個領域&#xff0c;國內也有很多廠商推出了全景相機。 Bubl全景相機國外一開源&#xff0c;國內就自主。這在VR&#xff08;虛擬現實&#xff09;領域體現的淋漓盡致——Google的Cardborad…

福大軟工1816 · 團隊現場編程實戰(抽獎系統)

值得一看的補充版本演示視頻 軟工錦鯉在這里程序版本鏈接及說明 按時提交版本 以基礎功能為主github鏈接&#xff1a;first version測試環境說明 本程序在python 3.6以上環境下運行操作說明&#xff1a; 鍵入抽獎關鍵詞&#xff0c;支持&#xff1a;#我要紅包#或“我要換組“或…

LeakCanary——直白的展現Android中的內存泄露

之前碰到的OOM問題&#xff0c;終于很直白的呈現在我的眼前&#xff1a;我嘗試了MAT&#xff0c;但是發現不怎么會用。直到今天終于發現了這個新工具&#xff1a; 當我們的App中存在內存泄露時會在通知欄彈出通知&#xff1a; 當點擊該通知時&#xff0c;會跳轉到具體的頁面&am…

老司機做VR視頻,需要什么樣的全景相機?

做為一個在全景內容領域摸爬滾打一年有余的老司機&#xff0c;經歷了太多的坑。最近有不少朋友轉行進入這個領域&#xff0c;問我買什么樣的相機好。我現在項目太多&#xff0c;根本沒空詳盡解答。所以寫下這篇文章&#xff0c;不懂得自己看吧。 說白了&#xff0c;買什么樣子…

域乎曹勝虎:傳統互聯網“生病”了

11月17日&#xff0c;2018&#xff08;第12屆&#xff09;創業周暨全球創業周中國站在上海盛大召開&#xff0c;由上海域乎信息技術有限公司&#xff08;以下簡稱“域乎”&#xff09;承辦的區塊鏈專場論壇——《區塊鏈產業應用賦能精英論壇》成功舉辦&#xff0c;吸引了眾多業…

xml的方式配置AOP:Aspect Oriented Programming

在某些類中, 什么時機, 做什么事情 切入點(point-cut): 在某些類中(Class<?>[] itfc new Class<?>[] { IStudentService.class }) 通知: 什么時機, 做什么事情(InvocationHandler的invoke方法) 切面: 切入點 通知 織入(weaver): Proxy.newProxyInstance: 把切入…

[No0000112]ComputerInfo,C#獲取計算機信息(cpu使用率,內存占用率,硬盤,網絡信息)...

github地址&#xff1a;https://github.com/charygao/SmsComputerMonitor 軟件用于實時監控當前系統資源等情況&#xff0c;并調用接口&#xff0c;當資源被超額占用時&#xff0c;發送警報到個人手機&#xff1b;界面模擬Console的顯示方式&#xff0c;信息緩沖大小由配置決定…

I2C總線之(一)---概述

概述&#xff1a;IC 是Inter-Integrated Circuit的縮寫&#xff0c;發音為"eye-squared cee" or "eye-two-cee" , 它是一種兩線接口。 IC 只是用兩條雙向的線&#xff0c;一條 Serial Data Line (SDA) &#xff0c;另一條Serial Clock (SCL)。 SCL&#xf…

js中級(1)

動畫(1) Css樣式提供了運動 過渡的屬性transition 從一種情況到另一種情況叫過渡 Transition:attr time linear delay&#xff1b; Attr 是變化的屬性 Time 是花費的時間 Linear 變化的速度 Delay 是延遲 復習background:url() no-repeat 50% 50% red; Background-image Ba…

I2C總線之(二)---時序

一、協議 1.空閑狀態 I2C總線總線的SDA和SCL兩條信號線同時處于高電平時&#xff0c;規定為總線的空閑狀態。此時各個器件的輸出級場效應管均處在截止狀態&#xff0c;即釋放總線&#xff0c;由兩條信號線各自的上拉電阻把電平拉高。 2.起始位與停止位的定義&#xff1a; 起始信…

微信小程序設置底部導航欄目方法

微信小程序底部想要有一個漂亮的導航欄目&#xff0c;不知道怎么制作&#xff0c;于是百度找到了本篇文章&#xff0c;分享給大家。 好了 小程序的頭部標題 設置好了&#xff0c;我們來說說底部導航欄是如何實現的。 我們先來看個效果圖 這里&#xff0c;我們添加了三個導航圖標…

HTTP協議(3)瀏覽器的使用之查看源碼

在做CTF的Web類題目時&#xff0c;推薦使用Firefox瀏覽器。下面介紹一些在解題過程中關于瀏覽器的常用技巧。首先就是查看源碼。在做Web題目時&#xff0c;經常需要查看網站源碼&#xff0c;有的flag直接就藏在源碼中&#xff0c;有些題目則是在源碼中給出提示和線索&#xff0…