Netty原理與基礎(一) 1.簡介 2.Netty目標 3.創建第一個Netty項目 4.Reactor反應器模式

1.簡介

Netty是爲了快速開發可維護的高性能、高可擴展、網絡服務器和客戶端程序而提供的異步事件驅動基礎框架和工具。換句話說,Netty是一個Java NIO客戶端/服務器框架

2.Netty目標

  • 使開發可以做到“快速和輕鬆”
  • 做到高性能和高擴展

3.創建第一個Netty項目

        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>${netty.version}</version>
        </dependency>
public class NettyDiscardServer {
    private final int serverPort;
    ServerBootstrap b = new ServerBootstrap();

    public NettyDiscardServer(int port) {
        this.serverPort = port;
    }

    public void runServer() {
        //創建reactor 線程組
        EventLoopGroup bossLoopGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerLoopGroup = new NioEventLoopGroup();

        try {
            //1 設置reactor 線程組
            b.group(bossLoopGroup, workerLoopGroup);
            //2 設置nio類型的channel
            b.channel(NioServerSocketChannel.class);
            //3 設置監聽端口
            b.localAddress(serverPort);
            //4 設置通道的參數
            b.option(ChannelOption.SO_KEEPALIVE, true);
            b.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
            b.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);

            //5 裝配子通道流水線
            b.childHandler(new ChannelInitializer<SocketChannel>() {
                //有連接到達時會創建一個channel
                protected void initChannel(SocketChannel ch) throws Exception {
                    // pipeline管理子通道channel中的Handler
                    // 向子channel流水線添加一個handler處理器
                    ch.pipeline().addLast(new NettyDiscardHandler());
                }
            });
            // 6 開始綁定server
            // 通過調用sync同步方法阻塞直到綁定成功
            ChannelFuture channelFuture = b.bind().sync();
            Logger.info(" 服務器啓動成功,監聽端口: " +
                    channelFuture.channel().localAddress());

            // 7 等待通道關閉的異步任務結束
            // 服務監聽通道會一直等待通道關閉的異步任務結束
            ChannelFuture closeFuture = channelFuture.channel().closeFuture();
            closeFuture.sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 8 優雅關閉EventLoopGroup,
            // 釋放掉所有資源包括創建的線程
            workerLoopGroup.shutdownGracefully();
            bossLoopGroup.shutdownGracefully();
        }

    }

    public static void main(String[] args) throws InterruptedException {
        int port = NettyDemoConfig.SOCKET_SERVER_PORT;
        new NettyDiscardServer(port).runServer();
    }
}
  • 客戶端代碼:
public class EchoClient {

    public void start() throws IOException {

        InetSocketAddress address =
                new InetSocketAddress(NioDemoConfig.SOCKET_SERVER_IP,
                        NioDemoConfig.SOCKET_SERVER_PORT);

        // 1、獲取通道(channel)
        SocketChannel socketChannel = SocketChannel.open(address);
        // 2、切換成非阻塞模式
        socketChannel.configureBlocking(false);
        //不斷的自旋、等待連接完成,或者做一些其他的事情
        while (!socketChannel.finishConnect()) {

        }
        Print.tcfo("客戶端啓動成功!");

        //啓動接受線程
        Processer processer = new Processer(socketChannel);
        new Thread(processer).start();

    }

    static class Processer implements Runnable {
        final Selector selector;
        final SocketChannel channel;

        Processer(SocketChannel channel) throws IOException {
            //Reactor初始化
            selector = Selector.open();
            this.channel = channel;
            channel.register(selector,
                    SelectionKey.OP_READ | SelectionKey.OP_WRITE);
        }

        public void run() {
            try {
                while (!Thread.interrupted()) {
                    selector.select();
                    Set<SelectionKey> selected = selector.selectedKeys();
                    Iterator<SelectionKey> it = selected.iterator();
                    while (it.hasNext()) {
                        SelectionKey sk = it.next();
                        if (sk.isWritable()) {
                            ByteBuffer buffer = ByteBuffer.allocate(NioDemoConfig.SEND_BUFFER_SIZE);

                            Scanner scanner = new Scanner(System.in);
                            Print.tcfo("請輸入發送內容:");
                            if (scanner.hasNext()) {
                                SocketChannel socketChannel = (SocketChannel) sk.channel();
                                String next = scanner.next();
                                buffer.put((Dateutil.getNow() + " >>" + next).getBytes());
                                buffer.flip();
                                // 操作三:通過DatagramChannel數據報通道發送數據
                                socketChannel.write(buffer);
                                buffer.clear();
                            }

                        }
                        if (sk.isReadable()) {
                            // 若選擇鍵的IO事件是“可讀”事件,讀取數據
                            SocketChannel socketChannel = (SocketChannel) sk.channel();

                            //讀取數據
                            ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                            int length = 0;
                            while ((length = socketChannel.read(byteBuffer)) > 0) {
                                byteBuffer.flip();
                                Logger.info("server echo:" + new String(byteBuffer.array(), 0, length));
                                byteBuffer.clear();
                            }

                        }
                        //處理結束了, 這裏不能關閉select key,需要重複使用
                        //selectionKey.cancel();
                    }
                    selected.clear();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws IOException {
        new EchoClient().start();
    }
}

4.Reactor反應器模式

4.1Reactor反應器模式中IO事件的處理流程

  • 1.通道註冊
  • 2.查詢選擇
  • 3.事件分發
  • 4.io操作和業務處理

4.2Netty中的Channel通道組件

  • 反應器模式和通道緊密相關,反應器的查詢和分發的IO事件都來自於Channel通道組件。
  • Netty中不直接使用Java NIO的Channel通道組件,對Channel通道組件進行了自己的封裝。
  • Netty還能處理Java的面向流的OIO(Old-IO,即傳統的阻塞式IO)
  • Netty中的每一種協議的通道,都有NIO(異步IO)和OIO(阻塞式IO)兩個版本


4.3Netty中的Reactor反應器

  • Netty中的反應器有多個實現類,與Channel通道類有關係。對應於NioSocketChannel通道,Netty的反應器類爲:NioEventLoop。
  • NioEventLoop類綁定了兩個重要的Java成員屬性:一個是Thread線程類的成員,一個是Java NIO選擇器的成員屬性。

4.4 Netty中的Handler處理器

Netty的Handler處理器分爲兩大類:第一類是ChannelInboundHandler通道入站處理器;第二類是ChannelOutboundHandler通道出站處理器。二者都繼承了ChannelHandler處理器接口

4.5Netty的流水性模式

  • (1)反應器(或者SubReactor子反應器)和通道之間是一對多的關係:一個反應器可以查詢很多個通道的IO事件。
  • (2)通道和Handler處理器實例之間,是多對多的關係:一個通道的IO事件被多個的Handler實例處理;一個Handler處理器實例也能綁定到很多的通道,處理多個通道的IO事件。
  • Netty設計了一個特殊的組件,叫作ChannelPipeline(通道流水線),它像一條管道,將綁定到一個通道的多個Handler處理器實例,串在一起,形成一條流水線。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章