一篇文章入門Netty

什麼是Netty?Netty是一個框架。或者說是一個工具集。封裝了網絡編程方面java的API。java

Netty有哪些核心組件?

  1. Channel:java nio的基本構造,表明一個實體(硬件設備、文件、網路套接字等)的開放鏈接。用做傳入(入站)或者傳出(出站)數據linux

  2. 回調:封裝操做完成後須要作的事情的方法編程

  3. Future: 提供異步操做的結果訪問bootstrap

  4. 事件和ChannelHandler:程序運行過程當中發生的事情抽象(事件)交給ChannerHandler來處理,channelHandler相似於爲了響應特定事件而執行的回調api

Netty的Hello world

server安全

public class EchoServer {
    private final int port;

    public EchoServer(int port) {
        this.port = port;
    }
    public static void main(String[]args)throws Exception{
        new EchoServer(8888).start();
    }
    public void start() throws Exception{
        final EchoServerHandler handler = new EchoServerHandler();
        EventLoopGroup group = new NioEventLoopGroup();
        try{
            ServerBootstrap b = new ServerBootstrap();
            b.group(group).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(handler);
                        }
                    });
            ChannelFuture f = b.bind().sync();
            f.channel().closeFuture().sync();
        }finally {
            group.shutdownGracefully().sync();
        }
    }
}

複製代碼

serverHandlerbash

public class EchoServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf in = (ByteBuf) msg;
        System.out.printf("Server get:"+in.toString(CharsetUtil.UTF_8));
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        //將目前暫存於ChannelOutboundBuffer中的消息在下一次flush或者writeAndFlush的時候沖刷到遠程並關閉這個channel
        ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
    }

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

client網絡

public class EchoClient {
    private final String host;
    private final int port;
    public EchoClient(String host,int port){
        this.host=host;
        this.port=port;
    }
    public void start() throws Exception{
        EventLoopGroup group = new NioEventLoopGroup();
        try{
            Bootstrap b = new Bootstrap();
            b.group(group).channel(NioSocketChannel.class)//指定NIO的傳輸方式
                    .remoteAddress(new InetSocketAddress(host,port))//指定遠程地址
                    .handler(new ChannelInitializer<SocketChannel>() {//向channel的pipeline添加handler
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new EchoClientHandler());//channelHander交給pipeline
                        }
                    });
            ChannelFuture f = b.connect().sync();//鏈接到遠程節點,阻塞直到鏈接完成
            System.out.println("wait");
            f.channel().closeFuture().sync();//阻塞直到鏈接關閉
            System.out.println("over");
        }finally {
            System.out.println("shutdown");
            group.shutdownGracefully().sync();//關閉線程池而且釋放資源
        }
    }
    public static void main(String[]args) throws Exception{
        new EchoClient("localhost",8888).start();
    }
}
複製代碼

clientHandler框架

public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.writeAndFlush(Unpooled.copiedBuffer("Hello world",CharsetUtil.UTF_8));
    }

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

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
        System.out.println("Client get:"+msg.toString(CharsetUtil.UTF_8));
    }
}
複製代碼

Channel、Eventloop 、ChannelFuture 是什麼關係?

它們是netty對網絡的抽象組件。異步

Channel自己用來提供基本的IO操做(bind/connect/read/write),鏈接創建以後經過EventLoop來處理所發生的事情,它們之間的對應關係是1個channel只能有1個EventLoop,可是一個EventLoop對應多個Channel。EventLoop整個生命週期中只和一個Thread綁定,對應來說一個Channel中的全部IO操做也都是在一個線程中執行的。執行的結果則是經過ChannelFuture來獲取

Channel有什麼特徵?

  1. channel是傳輸API的核心,每個都會被分配一個ChannelPipeline和ChannelConfig,ChannelConfig包含了Channel的全部配置,而且支持熱更新
  2. 每一個channel都是獨一無二的,channel之間的順序經過Comparable來實現比較
  3. channel的實現是線程安全的

pipeline和handler是什麼關係?

pipeline用來管理數據流,handler(client和server)是用來處理邏輯。

ChannelHandler接收事件,對事件進行邏輯處理,並將數據傳給鏈(多個按照必定順序定義的ChannelHandler)中的下一個ChannelHandler。ChannelPipLine就是ChannelHandler的編排順序(兩者創建關係的時機是ChannelInitializer執行initChannel的時候ChannelPipline組裝自定義的channelHandler)。出於方便ChannelHandler會提供一些適配實現類讓用戶專一於處理本身的業務邏輯。

bootstrap是什麼?

有兩種類型,客戶端(簡稱BootStrap)和服務端(簡稱ServerBootStrap)。區別有兩點

  1. BootStrap用來鏈接遠程節點,ServerBootStrap則是綁定本地端口監聽鏈接
  2. 客戶端須要一個EventLoopGroup(存多個EventLoop的東西),服務端須要兩個(能夠是同一個實例),一個用來綁定到本地端口表明已經監聽了(分配一個EventLoop),另外一個則是處理客戶端的鏈接(再分配一個EventLoop)

Netty支持的傳輸類型有哪些?

  • NIO:基於java api的selector機制實現。 大體原理是:當channel狀態發生變化的時獲得通知,執行狀態變化相應的任務,響應結束後,選擇器重置,再次重複這個過程

  • Epoll:只能在linux系統中使用,高負載狀況下,性能優於JDK的NIO。 大體原理是:I/O多路複用【經過一個文件符管理多個文件描述符(針對epoll能夠看作無限制)】,當一個文件描述符可讀或者可寫的時候,收到通知,立馬執行【邊沿觸發】
  • OIO(舊的阻塞IO):基於java.net的阻塞IO。 大體原理是:單線程監聽一個socket,任何I/O操做在任意的時間節點上都有可能被阻塞
  • Local:同一個JVM上運行的客戶端和服務端之間的通訊
  • Embedded:使用channel,但不須要真正意義上的網絡傳輸,通常用於測試

附錄

Netty In Action

相關文章
相關標籤/搜索