Netty----什麼是Netty學習

liucw_cn發表於2017-07-16

什麼Netty?

  Netty是由JBOSS提供的一個java開源框架。Netty提供非同步的、事件驅動的網路應用程式框架和工具,用以快速開發高效能、高可靠性的網路伺服器和客戶端程式。
  也就是說,Netty 是一個基於NIO的客戶、伺服器端程式設計框架,使用Netty 可以確保你快速和簡單的開發出一個網路應用,例如實現了某種協議的客戶,服務端應用。Netty相當簡化和流線化了網路應用的程式設計開發過程,例如,TCP和UDP的socket服務開發。
我們下面編寫四個類
  1.用於接收資料的伺服器端Socket
  2.用於接收客戶端的訊息,用於接收和反饋客戶端發出的訊息類ServertHandler
  3.用於傳送資料的伺服器端Client
  4.用於傳送資料和接收伺服器端發出的資料處理類ClientHandler

public class Server {

    public static void main(String[] args) throws InterruptedException {
        //1.第一個執行緒組是用於接收Client端連線的
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        //2.第二個執行緒組是用於實際的業務處理的
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        ServerBootstrap b = new ServerBootstrap();
        b.group(bossGroup, workerGroup);//繫結兩個執行緒池
        b.channel(NioServerSocketChannel.class);//指定NIO的模式,如果是客戶端就是NioSocketChannel
        b.option(ChannelOption.SO_BACKLOG, 1024);//TCP的緩衝區設定
        b.option(ChannelOption.SO_SNDBUF, 32*1024);//設定傳送緩衝的大小
        b.option(ChannelOption.SO_RCVBUF, 32*1024);//設定接收緩衝區大小
        b.option(ChannelOption.SO_KEEPALIVE, true);//保持連續
        b.childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel sc) throws Exception {
                ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());//拆包粘包定義結束字串(第一種解決方案)
                sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,buf));//在管道中加入結束字串
                //  sc.pipeline().addLast(new FixedLengthFrameDecoder(200));第二種定長
                sc.pipeline().addLast(new StringDecoder());//定義接收型別為字串把ByteBuf轉成String
                sc.pipeline().addLast(new ServerHandler());//在這裡配置具體資料接收方法的處理
            }
        });
        ChannelFuture future = b.bind(8765).sync();//繫結埠
        future.channel().closeFuture().sync();//等待關閉(程式阻塞在這裡等待客戶端請求)
        bossGroup.shutdownGracefully();//關閉執行緒
        workerGroup.shutdownGracefully();//關閉執行緒
    }
}

  1.在上面這個Server.java中,我們都要定義兩個執行緒池,boss和worker,boss是用於管理連線到server端的client的連線數的執行緒池,而woeker是用於管理實際操作的執行緒池。
  2.ServerBootstrap用一個ServerSocketChannelFactory 來例項化。ServerSocketChannelFactory 有兩種選擇,一種是NioServerSocketChannelFactory,一種是OioServerSocketChannelFactory。 前者使用NIO,後則使用普通的阻塞式IO。它們都需要兩個執行緒池例項作為引數來初始化,一個是boss執行緒池,一個是worker執行緒池。
  3.然後使ServerBookstrap管理boss和worker執行緒池。並且設定各個緩衝區的大小。
  4.這裡的事件處理類經常會被用來處理一個最近的已經接收的Channel。ChannelInitializer是一個特殊的處理類,他的目的是幫助使用者配置一個新的Channel。也許你想通過增加一些處理類比如NettyServerHandler來配置一個新的Channel 或者其對應的ChannelPipeline來實現你的網路程式。 當你的程式變的複雜時,可能你會增加更多的處理類到pipline上,然後提取這些匿名類到最頂層的類上。
  5.在使用原始的encoder、decoder的情況下,Netty傳送接收資料都是按照ByteBuf的形式,其它形式都是不合法的。 而在上面這個Socket中,我使用sc.pipeline().addLast()這個方法設定了接收為字串型別,注意:只能設定接收為字串型別,傳送還是需要傳送ByteBuf型別的資料。而且在這裡我還設定了以$_為結尾的字串就代表了本次請求字串的結束。
  6.通過b.bind繫結埠,用於監聽的埠號。

public class ServerHandler extends ChannelHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        String body = (String) msg;
        System.out.println("server"+body);//前面已經定義了接收為字串,這裡直接接收字串就可以
        //服務端給客戶端的響應
        String response= " hi client!$_";//傳送的資料以定義結束的字串結尾
        ctx.writeAndFlush(Unpooled.copiedBuffer(response.getBytes()));//傳送必須還是ByteBuf型別
    }

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

}

  ServertHandler繼承自 ChannelHandlerAdapter,這個類實現了ChannelHandler介面,ChannelHandler提供了許多事件處理的介面方法,然後你可以覆蓋這些方法。現在僅僅只需要繼承ChannelHandlerAdapter類而不是你自己去實現介面方法。
  1.由於我們再server端開始的時候已經定義了接收型別為String,所以在這裡我們接收到的msg直接強轉成String就可以了。同時也要定義以什麼為一次請求的結尾。

public class Client {

    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup worker = new NioEventLoopGroup();
        Bootstrap b = new Bootstrap();
        b.group(worker)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel sc) throws Exception {
                        ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());
                        sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,buf));
                        sc.pipeline().addLast(new StringDecoder());
                        sc.pipeline().addLast(new ClientHandler());
                    }
                });
        ChannelFuture f=b.connect("127.0.0.1",8765).sync();
        f.channel().writeAndFlush(Unpooled.copiedBuffer(" hi server2$_".getBytes()));
        f.channel().writeAndFlush(Unpooled.copiedBuffer(" hi server3$_".getBytes()));
        f.channel().writeAndFlush(Unpooled.copiedBuffer(" hi server4$_".getBytes()));
        f.channel().closeFuture().sync();
        worker.shutdownGracefully();
    }
}

  client端和Socket端幾乎程式碼相同,只是client端用的不是ServerBootstrap而是Bootstrap來管理連線。這裡沒什麼好說的。

public class ClientHandler extends ChannelHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        try {
            System.out.println("client"+msg.toString());
        } finally {
            ReferenceCountUtil.release(msg);//釋放緩衝區
        }
    }

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

  ClientHandler和ServertHandler程式碼和原理也是一樣,只是在client端我們要釋放緩衝區。為什麼在ServerHandler我們不需要釋放呢 ?因為在ServertHandler我們呼叫ctx.writeAndFlush方法的時候,這個方法預設已經幫我們釋放了緩衝區。

    <dependencies>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>5.0.0.Alpha1</version>
        </dependency>

        <!-- 如果我們想要在Netty中傳遞一個物件該怎麼辦呢 ?那麼這個時候我們可以結合Marshalling來傳遞。首先需要匯入兩個Marshalling的依賴包 -->
        <dependency>
            <groupId>org.jboss.marshalling</groupId>
            <artifactId>jboss-marshalling</artifactId>
            <version>2.0.0.CR1</version>
        </dependency>
        <dependency>
            <groupId>org.jboss.marshalling</groupId>
            <artifactId>jboss-marshalling-serial</artifactId>
            <version>2.0.0.CR1</version>
        </dependency>
    </dependencies>

相關文章