<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Netty的介紹與簡單使用

          共 7488字,需瀏覽 15分鐘

           ·

          2021-07-04 00:22

          有道無術(shù),術(shù)尚可求也!有術(shù)無道,止于術(shù)!

          一、Netty的優(yōu)勢

          盡管我們前面學(xué)習(xí)NIO的時候,我已經(jīng)盡可能的簡化代碼,但是我們依舊會發(fā)現(xiàn),JDK NIO的開發(fā)依舊是極為復(fù)雜,在業(yè)務(wù)開發(fā)中我們還要考慮到業(yè)務(wù)的處理流程、業(yè)務(wù)的復(fù)用、請求的并發(fā)量、請求過程中的編解碼問題、網(wǎng)絡(luò)傳輸中的半包粘包問題等等,會進(jìn)一步增加NIO開發(fā)的難度!歡迎關(guān)注公眾號【源碼學(xué)徒】

          • Netty是基于上述難題提供了一個統(tǒng)一的解決方案,Netty提供了一個對于Socket編程的統(tǒng)一模板,即使是一個沒有網(wǎng)絡(luò)編程基礎(chǔ)的開發(fā)人員,也能夠很輕松的開發(fā)出一個高并發(fā)、低延時的程序!

          • Netty提供了很多默認(rèn)的編解碼功能,能夠很輕松的實(shí)現(xiàn)一些市面上常見的協(xié)議比如FTP、HTTP、SMTP、WebSocket等,能夠通過很少的幾行代碼很輕松的解決網(wǎng)絡(luò)通訊過程中的半包、粘包問題!

          • 定制能力強(qiáng),Netty優(yōu)秀的代碼風(fēng)格和強(qiáng)大的擴(kuò)展能力,可以讓我們通過ChannelHandler對通信框架進(jìn)行靈活的擴(kuò)展,以及通過管道流(PipLine)實(shí)現(xiàn)業(yè)務(wù)功能的相互隔離與復(fù)用!

          • 成熟、穩(wěn)定,Netty修復(fù)了現(xiàn)在JDK已經(jīng)發(fā)現(xiàn)了的,所有的JDK NIO BUG,其中最著名的就是臭名昭著的JDK空輪訓(xùn)BUG!

          • 社區(qū)活躍,版本迭代周期短,發(fā)現(xiàn)的BUG可以被及時修復(fù),同時,更多的新功能會加入;

          二、Netty的架構(gòu)設(shè)計(jì)

          這是來自官網(wǎng)的一張架構(gòu)圖,我們可以大致的了解Netty的模塊!

          • Core核心層,是Netty的最主要的實(shí)現(xiàn),后續(xù)的所有擴(kuò)展都建立在Core之上,他提供了事件的可擴(kuò)展模型、網(wǎng)絡(luò)通訊編程的通用API、數(shù)據(jù)零拷貝和數(shù)據(jù)載體的封裝和復(fù)用!
          • Transport Service服務(wù)傳輸層,Netty提供了底層網(wǎng)絡(luò)通訊的能力,它抽象了底層網(wǎng)絡(luò)TCP、UDP等協(xié)議的網(wǎng)絡(luò)通信,使得用戶不在為一個網(wǎng)絡(luò)通信開發(fā)的底層技術(shù)所頭疼,似的注意力能夠更加專注于業(yè)務(wù)!也正是因?yàn)檫@一層的封裝,使得NIO/BIO之間能夠無縫切換!
          • Protocol Support協(xié)議層,Netty幾乎實(shí)現(xiàn)類市面上的大部分主流協(xié)議、包括HTTP、SSL、Protobuf、壓縮、大文件傳輸、WebSocket、文本、二進(jìn)制等主流協(xié)議, 而且Netty支持自定義擴(kuò)展協(xié)議。Netty豐富的協(xié)議使得用戶的開發(fā)成本大大降低,使用內(nèi)置的協(xié)議可以很輕松的開發(fā)一個類似于Tomcat的Http服務(wù)器!

          三、Netty的基本使用和介紹

          經(jīng)過上面的介紹,我們大概了解了Netty的基本架構(gòu),下面我們會看一下Netty的基本使用,然后我會逐行解析,希望能夠通過這一節(jié)課幫助大家入門Netty編程,也為后面的源碼學(xué)習(xí)更好的鋪墊一下!

          1. 開發(fā)一個服務(wù)端

          我們使用Netty開發(fā)一個簡單的服務(wù)端代碼:

          服務(wù)端接收到客戶端的消息,打印出來,然后主動中斷連接!

          啟動服務(wù)端源代碼:

          /**
          * 服務(wù)端
          *
          * @author 源碼學(xué)徒
          * @date 2021年4月19日12:39:21
          */

          public class EchoServer {

          public static void main(String[] args) {
          //設(shè)置事件循環(huán)組
          EventLoopGroup boss = new NioEventLoopGroup(1);
          EventLoopGroup worker = new NioEventLoopGroup();

          try {
          //設(shè)置服務(wù)啟動器
          ServerBootstrap serverBootstrap = new ServerBootstrap();
          serverBootstrap.group(boss, worker)
          .channel(NioServerSocketChannel.class)
          .localAddress(8989)
          //設(shè)置服務(wù)管道
          .childHandler(new ChannelInitializer<SocketChannel>()
          {
          @Override
          protected void initChannel(SocketChannel socketChannel) throws Exception {
          socketChannel.pipeline().addLast(new EchoServerHandler());
          }
          });
          //同步阻塞 直到綁定完成
          ChannelFuture channelFuture = serverBootstrap.bind().sync();
          //監(jiān)聽通道關(guān)閉方法 等待服務(wù)端通道關(guān)閉完成
          channelFuture.channel().closeFuture().sync();
          } catch (InterruptedException e) {
          e.printStackTrace();
          } finally {
          //優(yōu)雅的關(guān)閉線程組
          boss.shutdownGracefully();
          worker.shutdownGracefully();
          }
          }
          }

          服務(wù)端讀取數(shù)據(jù)處理器源代碼 :EchoServerHandler

          /**
          * 服務(wù)端打印處理的handler
          *
          * @author huangfu
          * @date 2021年4月19日12:42:34
          */

          public class EchoServerHandler extends ChannelInboundHandlerAdapter {
          @Override
          public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
          ByteBuf byteBuf = (ByteBuf) msg;
          try {
          //轉(zhuǎn)換為字符串
          String message = byteBuf.toString(StandardCharsets.UTF_8);
          System.out.println(message);
          }finally {
          ReferenceCountUtil.release(byteBuf);
          ctx.channel().close();
          }
          }
          }

          2. 服務(wù)端源代碼介紹

          EventLoopGroup boss = new NioEventLoopGroup(1);
          EventLoopGroup worker = new NioEventLoopGroup();

          定義兩個事件循環(huán)組,還記得我們第五章將的我們對NIO的優(yōu)化版本嗎?現(xiàn)在暫時你可以把它理解為兩個selector組

          • boss內(nèi)部只包含一個selector選擇器,用于接收新連接!
          • worker內(nèi)部默認(rèn)是CPU*2個selector選擇器,用于處理我們的業(yè)務(wù)邏輯!

          boss接收到新連接后,將新連接產(chǎn)生的SocketChannel交給worker線程組處理!用一個現(xiàn)在比較流行的比喻:boss相當(dāng)于老板,worker相當(dāng)于工人,boss不處理工作,只負(fù)責(zé)在外面跑業(yè)務(wù)拉活談合同。接到新活之后,就把這個活交給worker來干,自己再去接下一個活!

          這兩行代碼建議參考上一章的NIO的優(yōu)化版本學(xué)習(xí)!

          ServerBootstrap serverBootstrap = new ServerBootstrap();

          ServerBootstrap是Netty為我們提供的一個快速啟動配置類,為什么Netty相較于NIO開發(fā)比較簡單,就是因?yàn)镹etty為我們提供了一個網(wǎng)絡(luò)編程的代碼的模板,那么想要使用這些模板,就必須要告訴模板一些必要的參數(shù),供模板讀取,而ServerBootstrap正式這個作用,通過初始化的時候,我們設(shè)置各種參數(shù),我們將之保存到ServerBootstrap中,后續(xù)Netty服務(wù)啟動的時候,會讀取我們初始化的時候配置的各種參數(shù),完成自己的初始化

           serverBootstrap.group(boss, worker)

          將我們前面初始化的兩個事件循環(huán)組綁定起來,保存到serverBootstrap中,供后續(xù)讀取!

          .channel(NioServerSocketChannel.class)

          我們這里開發(fā)的是一個服務(wù)端程序,所以我們使用的是NioServerSocketChannel,在Netty中分為兩種SocketChannel,一種是NioServerSocketChannel一種是NioSocketChannel,兩者都繼承與JDK的ServerSocketChannel和SocketChannel,是Netty官方對于通訊管道的擴(kuò)展:

          image-20210419133824276
          • NioServerSocketChannel: 服務(wù)端通道
          • NioSocketChannel: 客戶端通道

          有關(guān)于兩個通道,我們后面會詳細(xì)分析,這里你們先記著,NioServerSocketChannel代表著服務(wù)端通道!NioSocketChannel代表著客戶端通道,不要搞混了!

          .localAddress(8989)

          設(shè)置一個端口號,服務(wù)端對外暴露的端口號!

          .childHandler(new ChannelInitializer<SocketChannel>() {
          @Override
          protected void initChannel(SocketChannel socketChannel) throws Exception {
          socketChannel.pipeline().addLast(new EchoServerHandler());
          }
          });

          這個代碼及其重要,后面也會重點(diǎn)提及,這里主要是做服務(wù)編排的,想客戶端Socket綁定一個通道,并添加我們的業(yè)務(wù)處理類 xxxxHandler,當(dāng)一個客戶端連接上服務(wù)端后,后續(xù)所有的業(yè)務(wù)處理,都會由這里注冊的各種Handler來處理,這就是Netty提供的能夠讓開發(fā)人員專注于業(yè)務(wù)開發(fā)的主要邏輯所在,后面會對這一塊代碼進(jìn)行一個重點(diǎn)的講解,這里也只需要記住,我們注冊這些Handler后,客戶端發(fā)來的數(shù)據(jù)都會在這些Handler中流轉(zhuǎn)處理!

          ChannelFuture channelFuture = serverBootstrap.bind().sync();

          上面的初始化完成了,開始進(jìn)行服務(wù)器啟動和端口綁定,根據(jù)上面設(shè)置的端口號綁定,細(xì)心的同學(xué)可能會發(fā)現(xiàn)我還調(diào)用了一個sync方法,Netty是基于異步事件來開發(fā)的,這里我們進(jìn)行bind調(diào)用之后,因?yàn)槭钱惒綀?zhí)行,所以我們并不知道什么時候完成,所以這里調(diào)用了一個阻塞的方法(sync),一直阻塞等待綁定完成后才繼續(xù)往下走!

          channelFuture.channel().closeFuture().sync();

          獲取一個服務(wù)端的通道對象,并且對服務(wù)端的通道對象添加一個關(guān)閉的監(jiān)聽,并調(diào)用阻塞方法(sync),調(diào)用后,程序會一直阻塞再這里,等待服務(wù)端管道關(guān)閉,才會繼續(xù)往下走!一般來說,服務(wù)端管道除非我們主動停機(jī)活因?yàn)楫惓1罎ⅲ駝t服務(wù)端管道會一直存活,那么改程序?qū)恢弊枞谶@里,形成一個服務(wù)!

          boss.shutdownGracefully();
          worker.shutdownGracefully();

          優(yōu)雅停機(jī),該段程序會將通道標(biāo)記為不可用狀態(tài),等待程序處理完畢后,釋放Netty所創(chuàng)建的所有資源!

          public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {....}

          當(dāng)服務(wù)端察覺到客戶端發(fā)來數(shù)據(jù)時,回調(diào)該邏輯!

          3. 開發(fā)一個客戶端

          /**
          * 打印程序客戶端
          *
          * @author huangfu
          * @date 2021年4月19日13:58:16
          */

          public class EchoClient {
          public static void main(String[] args) {
          EventLoopGroup worker = new NioEventLoopGroup();

          try {
          Bootstrap bootstrap = new Bootstrap();
          bootstrap.remoteAddress("127.0.0.1", 8989)
          .group(worker)
          .channel(NioSocketChannel.class)
          .handler(new ChannelInitializer<SocketChannel>()
          {
          @Override
          protected void initChannel(SocketChannel ch) throws Exception {
          ch.pipeline().addLast(new EchoClientHandler());
          }
          });

          ChannelFuture channelFuture = bootstrap.connect().sync();
          channelFuture.channel().closeFuture().sync();
          } catch (Exception e) {
          e.printStackTrace();
          } finally {
          worker.shutdownGracefully();
          }
          }
          }

          客戶端處理Handler

          /**
          * @author huangfu
          * @date
          */

          public class EchoClientHandler extends ChannelInboundHandlerAdapter {
          @Override
          public void channelActive(ChannelHandlerContext ctx) throws Exception {
          ByteBuf buffer = ByteBufAllocator.DEFAULT.buffer();
          buffer.writeBytes("Hello Netty".getBytes(StandardCharsets.UTF_8));
          ctx.channel().writeAndFlush(buffer);
          }
          }

          4. 客戶端源代碼介紹

          客戶端的代碼和服務(wù)端的代碼基本一致,所以這里不做全部講解,只做不一樣的講解:

          EventLoopGroup worker = new NioEventLoopGroup();

          這里客戶端只有一個事件循環(huán)組,為什么?因?yàn)榭蛻舳瞬淮嬖谛逻B接嘛!

          Bootstrap bootstrap = new Bootstrap();

          這個里和服務(wù)端的ServerBootstrap基本一致,是為了保存客戶端的配置所設(shè)置的一個類!

          ChannelFuture channelFuture = bootstrap.connect().sync();

          連接服務(wù)端,并等待鏈接完成!

          Handler的重載方法也發(fā)生了變化:

          public void channelActive(ChannelHandlerContext ctx) throws Exception {....}

          這里的含義是,當(dāng)客戶端被激活后既鏈接到服務(wù)端后,回調(diào)該邏輯!

          細(xì)心的同學(xué)在練習(xí)的時候可能會發(fā)現(xiàn)一點(diǎn)問題,我們發(fā)現(xiàn)客戶端會有 handler和childHandler兩種方法

          .handler()
          //設(shè)置服務(wù)管道
          .childHandler()
          • handler: 是綁定在 ServerSocketChannel之上的,負(fù)責(zé)服務(wù)端的邏輯處理!
          • childHandler: 是綁定在SockerChannel之上的,當(dāng)客戶端綁定成功后,會產(chǎn)生一個SocketChannel對象會調(diào)用該handler的綁定!

          總結(jié)

          本節(jié)課比較簡單,主要是對Netty的基本使用有一個比較簡單的認(rèn)知,希望大家課下多練習(xí),爭取會簡單的使用Netty!

          才疏學(xué)淺,如果文章中理解有誤,歡迎大佬們私聊指正!歡迎關(guān)注作者的公眾號,一起進(jìn)步,一起學(xué)習(xí)!



          ??「轉(zhuǎn)發(fā)」「在看」,是對我最大的支持??



          瀏覽 58
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  a在线日本免费观看 | 97人人爽人人爽人人爽人人爽 | 久操久操 | 日本大乳高潮视频在线观看 | 色就是色欧美setu |