【netty筆錄】-“hello world”

                     **用netty寫個hello world**				

要成爲架構師,瞭解一些框架內部的通信機制的必不可少的,所以最近學習了netty的相關知識,本次就先用netty寫個“hello world”來體驗下。
Netty或多或少應該都聽說過,我這裏就不用在贅述他的背景,netty的內部通訊模式有多種:
NIO io.netty.channel.socket.nio 使用java.nio.channels 包作爲基礎——基於選擇器的方式
Epoll io.netty.channel.epoll 由 JNI 驅動的 epoll()和非阻塞 IO。這個傳輸支持只有在Linux 上可用的多種特性,按照作者的話來說在linux下使用這種通訊模式能獲得更高的性能,能減少GC次數.將NioEventLoopGroup替換爲EpollEventLoopGroup , 並且將NioServerSocketChannel.class 替換爲EpollServerSocketChannel.class 即可。
OIO io.netty.channel.socket.oio 使用java.net 包作爲基礎——使用阻塞流(相當於BIO)
Local io.netty.channel.local 可以在VM 內部通過管道進行通信的本地傳輸
Embedded io.netty.channel.embedded Embedded 傳輸,允許使用ChannelHandler 而又不需要一個真正的基於網絡的傳輸。在測試ChannelHandler 實現時非常有用

這裏主要是用NIO的方式,NIO的原理會單獨分享和實現,netty的幫助程序員封裝起了NIO的使得代碼編寫起來會比較簡單,瞭解一個新的東西要先從大的方向去了解,netty的核心組件:
1.channel java的channel是網絡io和文件io通用,netty的channel只包含網絡通訊的功能。
netty的channel並沒有繼承java的channel;
2、EventLoop、EventLoopGroup
結構圖
3.事件和ChannelHandler
應用程序開發人員的角度來看,Netty 的主要組件是ChannelHandler,
它充當了所有處理入站和出站數據的應用程序邏輯的地方。
Netty 以適配器類的形式提供了大量默認的ChannelHandler 實現,
幫我們簡化應用程序處理邏輯的開發過程。
開始:
先寫客戶端:

public class NettyClient {


    private ChannelFuture f;
    public void connect(String ip,Integer port){
        EventLoopGroup  eventLoopGroup = new NioEventLoopGroup();
        //程序啓動器
        Bootstrap b =new Bootstrap();

        try {
        b.group(eventLoopGroup)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .handler(new ChannelInitializer<SocketChannel>(){

                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline().addLast(new NettyClientHandler());
                    }
                });
            f = b.connect(ip, port).sync();/*連接到遠程節點,阻塞等待直到連接完成*/
            f.channel().closeFuture().sync();/*阻塞,直到channel關閉*/
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            eventLoopGroup.shutdownGracefully();
        }
    }


    public static void main(String[] args) {
        int port =8080;
        NettyClient client = new NettyClient();
        client.connect("localhost",port);
    }


Netty是 Reactor模型的是基於事件驅動的,所以可以看到具體業務是由handler來處理, ChannelPipeline 提供了ChannelHandler 鏈的容器,並定義了用於在該鏈上傳播入站和出站事件流的API。

public class NettyClientHandler extends SimpleChannelInboundHandler<ByteBuf> {

    protected NettyClientHandler() {
        super();
    }



    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
//        System.out.println("hello , i am client");
        ByteBuf buf= Unpooled.copiedBuffer("hello server",CharsetUtil.UTF_8);
        ctx.writeAndFlush(buf);
    }

   /* @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        super.channelRead(ctx, msg);
        ByteBuf buf= (ByteBuf) msg;
        System.out.println("accept msg:" + buf.toString(CharsetUtil.UTF_8));

    }*/

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
        System.out.println("client accept:"+byteBuf.toString(CharsetUtil.UTF_8));
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        super.channelReadComplete(ctx);
    }

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

服務端:

 public void bind(Integer port){
        EventLoopGroup bossGroup=new NioEventLoopGroup();//selector[]
        EventLoopGroup workGroup=new NioEventLoopGroup();
        ServerBootstrap b =new ServerBootstrap();
        try {
            b.group(bossGroup,workGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>(){

                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new NettyServerOutBandHandler());
                            socketChannel.pipeline().addLast(new NettyServerInBandHandler());
                        }
                    });
            ChannelFuture f =b.bind(port).sync();
            f.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) {
        Integer port =8080;
        NettyServer nettyServer= new NettyServer();
        nettyServer.bind(port);
    }

ChannelPipeline是有入棧出站順序的,通常把出站的放在前面,因爲有執行順序會先執行出站的讀,可以做檢測過濾相關操作

 @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
    }

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
        System.out.println("server accept:"+byteBuf.toString(CharsetUtil.UTF_8));
    }


    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        super.channelReadComplete(ctx);
        System.out.println("讀完");
        ctx.writeAndFlush(Unpooled.copiedBuffer("hello client 3",CharsetUtil.UTF_8));
    }

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

定義了一個出站的handler和一個入棧的

public class NettyServerOutBandHandler extends ChannelOutboundHandlerAdapter {
    public NettyServerOutBandHandler() {
        super();
    }

    @Override
    public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception {
        super.connect(ctx, remoteAddress, localAddress, promise);
        System.out.println("連接成功!");
    }

    @Override
    public void read(ChannelHandlerContext ctx) throws Exception {
        super.read(ctx);
//        System.out.println(ctx.read());

//        ctx.writeAndFlush(Unpooled.copiedBuffer("hello client1",CharsetUtil.UTF_8));

    }

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        super.write(ctx, msg, promise);
        ctx.writeAndFlush(Unpooled.copiedBuffer("hello client2",CharsetUtil.UTF_8));

    }
}

運行結果,先啓動服務端,後啓動客戶端

服務端輸出
客戶端輸出

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章