最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Netty搭建服務(wù)端和客戶端過程詳解

 更新時(shí)間:2019年07月15日 09:28:54   作者:正號(hào)先生  
這篇文章主要介紹了使用Netty搭建服務(wù)端和客戶端過程詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

前言

前面我們介紹了網(wǎng)絡(luò)一些基本的概念,雖然說這些很難吧,但是至少要做到理解吧。有了之前的基礎(chǔ),我們來正式揭開Netty這神秘的面紗就會(huì)簡(jiǎn)單很多。

服務(wù)端

public class PrintServer {

  public void bind(int port) throws Exception {
    EventLoopGroup bossGroup = new NioEventLoopGroup();           //1
    EventLoopGroup workerGroup = new NioEventLoopGroup();          //2
    try {
      ServerBootstrap b = new ServerBootstrap();             //3
      b.group(bossGroup, workerGroup)                   //4                     
          .channel(NioServerSocketChannel.class)           //5
          .option(ChannelOption.SO_BACKLOG, 1024)           //6
          .childHandler(new ChannelInitializer<SocketChannel>() {   //7
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
              ch.pipeline().addLast(new PrintServerHandler());
            }
          });

      ChannelFuture f = b.bind(port).sync();       //8
      
      f.channel().closeFuture().sync();          //9
    } finally {
      // 優(yōu)雅退出,釋放線程池資源
      bossGroup.shutdownGracefully();
      workerGroup.shutdownGracefully();
    }
  }


  /**
   * @param args
   * @throws Exception
   */
  public static void main(String[] args) throws Exception {
    int port = 8080;
    new TimeServer().bind(port);
  }
}

我們來分析一下上面的這段代碼(下面的每一點(diǎn)對(duì)應(yīng)上面的注釋)

1~2:首先我們創(chuàng)建了兩個(gè)NioEventLoopGroup實(shí)例,它是一個(gè)由Netty封裝好的包含NIO的線程組。為什么創(chuàng)建兩個(gè)?我想經(jīng)過前面的學(xué)習(xí)大家應(yīng)該都清楚了。對(duì),因?yàn)镹etty的底層是IO多路復(fù)用,bossGroup 是用于接收客戶端的連接,原理就是一個(gè)實(shí)現(xiàn)的Selector的Reactor線程。而workerGroup用于進(jìn)行SocketChannel的網(wǎng)絡(luò)讀寫。

3:創(chuàng)建一個(gè)ServerBootstrap對(duì)象,可以把它想象成Netty的入口,通過這類來啟動(dòng)Netty,將所需要的參數(shù)傳遞到該類當(dāng)中,大大降低了的開發(fā)難度。

4:將兩個(gè)NioEventLoopGroup實(shí)例綁定到ServerBootstrap對(duì)象中。

5:創(chuàng)建Channel(典型的channel有NioSocketChannel,NioServerSocketChannel,OioSocketChannel,OioServerSocketChannel,EpollSocketChannel,EpollServerSocketChannel),這里創(chuàng)建的是NIOserverSocketChannel,它的功能可以理解為當(dāng)接受到客戶端的連接請(qǐng)求的時(shí)候,完成TCP三次握手,TCP物理鏈路建立成功。并將該“通道”與workerGroup線程組的某個(gè)線程相關(guān)聯(lián)。

6:設(shè)置參數(shù),這里設(shè)置的SO_BACKLOG,意思是客戶端連接等待隊(duì)列的長(zhǎng)度為1024.

7:建立連接后的具體Handler。就是我們接受數(shù)據(jù)后的具體操作,例如:記錄日志,對(duì)信息解碼編碼等。

8:綁定端口,同步等待成功

9:等待服務(wù)端監(jiān)聽端口關(guān)閉

綁定該服務(wù)端的Handler

public class PrintServerHandler extends ChannelHandlerAdapter {

  @Override
  public void channelRead(ChannelHandlerContext ctx, Object msg)
    throws Exception {
  ByteBuf buf = (ByteBuf) msg;                    //1
  byte[] req = new byte[buf.readableBytes()]; 
  buf.readBytes(req); //將緩存區(qū)的字節(jié)數(shù)組復(fù)制到新建的req數(shù)組中
  String body = new String(req, "UTF-8");
  System.out.println(body);
  String response= "打印成功";
  ByteBuf resp = Unpooled.copiedBuffer(response.getBytes());           
  ctx.write(resp);                          //2
  }  

  @Override
  public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
  ctx.flush();                            //3
  }


  @Override
  public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
  ctx.close();
  }
}

PrintServerHandler 繼承 ChannelHandlerAdapter ,在這里它的功能為 打印客戶端發(fā)來的數(shù)據(jù)并且返回客戶端打印成功。

我們只需要實(shí)現(xiàn)channelRead,exceptionCaught,前一個(gè)為接受消息具體邏輯的實(shí)現(xiàn),后一個(gè)為發(fā)生異常后的具體邏輯實(shí)現(xiàn)。

1:我們可以看到,接受的消息被封裝為了Object ,我們將其轉(zhuǎn)換為ByteBuf ,前一章的講解中也說明了該類的作用。我們需要讀取的數(shù)據(jù)就在該緩存類中。

2~3:我們將寫好的數(shù)據(jù)封裝到ByteBuf中,然后通過write方法寫回到客戶端,這里的3調(diào)用flush方法的作用為,防止頻繁的發(fā)送數(shù)據(jù),write方法并不直接將數(shù)據(jù)寫入SocketChannel中,而是把待發(fā)送的數(shù)據(jù)放到發(fā)送緩存數(shù)組中,再調(diào)用flush方法發(fā)送數(shù)據(jù)。

客戶端

public class PrintClient {

  public void connect(int port, String host) throws Exception {
  EventLoopGroup group = new NioEventLoopGroup();         //1
  try {
    Bootstrap b = new Bootstrap();               //2
     b.group(group)                       //3
      .channel(NioSocketChannel.class)            //4
      .option(ChannelOption.TCP_NODELAY, true)        //5
      .handler(new ChannelInitializer<SocketChannel>() {   //6
      @Override
      public void initChannel(SocketChannel ch)        
        throws Exception {
        ch.pipeline().addLast(new PrintClientHandler());
      }
      });

    ChannelFuture f = b.connect(host, port).sync();       //7
    f.channel().closeFuture().sync();              //8
  } finally {
    // 優(yōu)雅退出,釋放NIO線程組
    group.shutdownGracefully();
  }
  }

  /**
   * @param args
   * @throws Exception
   */
  public static void main(String[] args) throws Exception {
  int port = 8080;
  new TimeClient().connect(port, "127.0.0.1");
  }
}

我們繼續(xù)來分析一下上面的這段代碼(下面的每一點(diǎn)對(duì)應(yīng)上面的注釋)

1:區(qū)別于服務(wù)端,我們?cè)诳蛻舳酥粍?chuàng)建了一個(gè)NioEventLoopGroup實(shí)例,因?yàn)榭蛻舳四悴⒉恍枰褂肐/O多路復(fù)用模型,需要有一個(gè)Reactor來接受請(qǐng)求。只需要單純的讀寫數(shù)據(jù)即可

2:區(qū)別于服務(wù)端,我們?cè)诳蛻舳酥恍枰獎(jiǎng)?chuàng)建一個(gè)Bootstrap對(duì)象,它是客戶端輔助啟動(dòng)類,功能類似于ServerBootstrap。

3:將NioEventLoopGroup實(shí)例綁定到Bootstrap對(duì)象中。

4:創(chuàng)建Channel(典型的channel有NioSocketChannel,NioServerSocketChannel,OioSocketChannel,OioServerSocketChannel,EpollSocketChannel,EpollServerSocketChannel),區(qū)別與服務(wù)端,這里創(chuàng)建的是NIOSocketChannel.

5:設(shè)置參數(shù),這里設(shè)置的TCP_NODELAY為true,意思是關(guān)閉延遲發(fā)送,一有消息就立即發(fā)送,默認(rèn)為false。

6:建立連接后的具體Handler。注意這里區(qū)別與服務(wù)端,使用的是handler()而不是childHandler()。handler和childHandler的區(qū)別在于,handler是接受或發(fā)送之前的執(zhí)行器;childHandler為建立連接之后的執(zhí)行器。

7:發(fā)起異步連接操作

8:當(dāng)代客戶端鏈路關(guān)閉

綁定該客戶端的Handler

public class PrintClientHandler extends ChannelHandlerAdapter {

  private static final Logger logger = Logger
    .getLogger(TimeClientHandler.class.getName());

  private final ByteBuf firstMessage;

  /**
   * Creates a client-side handler.
   */
  public TimeClientHandler() {
  byte[] req = "你好服務(wù)端".getBytes();
  firstMessage = Unpooled.buffer(req.length);                 //1
  firstMessage.writeBytes(req);

  }

  @Override
  public void channelActive(ChannelHandlerContext ctx) {
  ctx.writeAndFlush(firstMessage);                      //2       
  }

  @Override
  public void channelRead(ChannelHandlerContext ctx, Object msg)       //3
    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("服務(wù)端回應(yīng)消息 : " + body);
  }

  @Override
  public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {  //4
  // 釋放資源
  System.out.println("Unexpected exception from downstream : "
    + cause.getMessage());
  ctx.close();
  }
}

PrintClientHandler 繼承 ChannelHandlerAdapter ,在這里它的功能為 發(fā)送數(shù)據(jù)并打印服務(wù)端發(fā)來的數(shù)據(jù)。

我們只需要實(shí)現(xiàn)channelActive,channelRead,exceptionCaught,第一個(gè)為建立連接后立即執(zhí)行,后兩個(gè)與一個(gè)為接受消息具體邏輯的實(shí)現(xiàn),另一個(gè)為發(fā)生異常后的具體邏輯實(shí)現(xiàn)。

1:將發(fā)送的信息封裝到ByteBuf中。

2:發(fā)送消息。

3:接受客戶端的消息并打印

4:發(fā)生異常時(shí),打印異常信息,釋放客戶端資源

總結(jié)

這是一個(gè)入門程序,對(duì)應(yīng)前面所講的I/O多路復(fù)用模型以及NIO的特性,能很有效的理解該模式的編程方式。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java實(shí)現(xiàn)stream的三個(gè)常用方式(toMap,groupingBy,findFirst)

    Java實(shí)現(xiàn)stream的三個(gè)常用方式(toMap,groupingBy,findFirst)

    本文主要介紹了Java實(shí)現(xiàn)stream的三個(gè)常用方式,主要包括toMap,groupingBy,findFirst,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-10-10
  • 如何解決Idea沒有elementui標(biāo)簽的代碼提示問題

    如何解決Idea沒有elementui標(biāo)簽的代碼提示問題

    這篇文章主要介紹了如何解決Idea沒有elementui標(biāo)簽的代碼提示問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • java中PO、VO、BO、POJO、DAO、DTO、TO、QO、Bean、conn的理解

    java中PO、VO、BO、POJO、DAO、DTO、TO、QO、Bean、conn的理解

    這篇文章主要介紹了java中PO、VO、BO、POJO、DAO、DTO、TO、QO、Bean、conn的理解,需要的朋友可以參考下
    2020-02-02
  • java獲得mysql和oracle鏈接的類

    java獲得mysql和oracle鏈接的類

    這篇文章主要介紹了java獲得mysql和oracle鏈接的類,可實(shí)現(xiàn)基于jdbc的mysql與oracle數(shù)據(jù)庫連接,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-07-07
  • Java的幾種文件拷貝方式示例詳解

    Java的幾種文件拷貝方式示例詳解

    在Java編程中文件操作是常見且重要的任務(wù)之一,其中文件拷貝是一種基本操作,這篇文章主要給大家介紹了關(guān)于Java幾種文件拷貝方式的相關(guān)資料,文中給出了詳細(xì)的代碼示例,需要的朋友可以參考下
    2024-08-08
  • SpringBoot整合Tomcat連接池的使用

    SpringBoot整合Tomcat連接池的使用

    這篇文章主要介紹了SpringBoot整合Tomcat連接池的使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Kafka中消息隊(duì)列的兩種模式講解

    Kafka中消息隊(duì)列的兩種模式講解

    這篇文章主要介紹了Kafka中消息隊(duì)列的兩種模式講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • Java8新特性Lambda表達(dá)式的一些復(fù)雜用法總結(jié)

    Java8新特性Lambda表達(dá)式的一些復(fù)雜用法總結(jié)

    lambda表達(dá)式是JAVA8中提供的一種新的特性,它支持Java也能進(jìn)行簡(jiǎn)單的“函數(shù)式編程”。 下面這篇文章主要給大家介紹了關(guān)于Java8新特性Lambda表達(dá)式的一些復(fù)雜用法的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-07-07
  • springboot使用Mybatis-plus分頁插件的案例詳解

    springboot使用Mybatis-plus分頁插件的案例詳解

    這篇文章主要介紹了springboot使用Mybatis-plus分頁插件的相關(guān)知識(shí),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-05-05
  • java?ThreadPoolExecutor線程池內(nèi)部處理流程解析

    java?ThreadPoolExecutor線程池內(nèi)部處理流程解析

    這篇文章主要為大家介紹了java?ThreadPoolExecutor線程池內(nèi)部處理流程解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12

最新評(píng)論

探索| 织金县| 福安市| 汝城县| 普宁市| 蕉岭县| 黄陵县| 阿拉尔市| 中阳县| 上林县| 南漳县| 含山县| 苏尼特右旗| 昌吉市| 凤翔县| 永城市| 额尔古纳市| 香河县| 汨罗市| 凉城县| 衡东县| 页游| 叙永县| 额敏县| 沐川县| 航空| 武平县| 水城县| 平罗县| 五原县| 南宁市| 宣汉县| 阳曲县| 宁武县| 万盛区| 南川市| 红安县| 汝州市| 马鞍山市| 信宜市| 安溪县|