netty 源碼簡單分析一

來源:互聯網
上載者:User

標籤:netty 源碼

周末簡單看了下netty5的源碼,只看懂了個大概,記錄下成果,方便下次再看的時候回憶.

上服務端代碼:

public void run() throws Exception {        EventLoopGroup bossGroup = new NioEventLoopGroup();        EventLoopGroup workerGroup = new NioEventLoopGroup();        try {            ServerBootstrap b = new ServerBootstrap();            b.group(bossGroup, workerGroup)             .channel(NioServerSocketChannel.class)             .childHandler(new ChannelInitializer<SocketChannel>() {                @Override                public void initChannel(SocketChannel ch) throws Exception {                    ch.pipeline().addLast(                            new ObjectEncoder(),                            new ObjectDecoder(ClassResolvers.cacheDisabled(null)),                            new ObjectEchoServerHandler(),                            new MyServerHandler());                }             });            // Bind and start to accept incoming connections.            b.bind(port).sync().channel().closeFuture().sync();                    } finally {            bossGroup.shutdownGracefully();            workerGroup.shutdownGracefully();        }    }
EventLoopGroup類有4個相關類容易搞混: 

EventExecutor EventExecutorGroup, EventLoop, EventLoopGroup,  

   EventExecutor 繼承自EventExecutorGroup , EventExecutorGroup 繼承自ScheduledExecutorService(java內建的線程池服務類), EventExecutor 是一個特殊的EventExecutorGroup,提供了檢測一個線程是否在eventLoop中被執行之類的方法.

    EventLoopGroup 也繼承自EventExecutorGroup, 並提供EventLoop的產生方法next(),

    EventLoop繼承自EventLoopGroup, EventLoop的英文解釋是:Will handle all the I/O-Operations for a Channel once it was registered,即處理channel的io操作,


ServerBootstrap 類主要用於建立NioServerSocketChannel類,並初始化. 主要看它的 bind()方法,如下:

private ChannelFuture doBind(final SocketAddress localAddress) {        final ChannelFuture regFuture = initAndRegister();        final Channel channel = regFuture.channel();        if (regFuture.cause() != null) {            return regFuture;        }        final ChannelPromise promise;        if (regFuture.isDone()) {            promise = channel.newPromise();            doBind0(regFuture, channel, localAddress, promise);        } else {            // Registration future is almost always fulfilled already, but just in case it's not.            promise = new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE);            regFuture.addListener(new ChannelFutureListener() {                @Override                public void operationComplete(ChannelFuture future) throws Exception {                    doBind0(regFuture, channel, localAddress, promise);                }            });        }        return promise;    }

上面代碼主要是兩個過程,一個註冊生產 channel,第二個是將channel綁定到指定連接埠,

建立並註冊方法如下:

final ChannelFuture initAndRegister() {        Channel channel;        try {            channel = createChannel();        } catch (Throwable t) {            return VoidChannel.INSTANCE.newFailedFuture(t);        }        try {            init(channel);        } catch (Throwable t) {            channel.unsafe().closeForcibly();            return channel.newFailedFuture(t);        }        ChannelPromise regFuture = channel.newPromise();        channel.<span style="color:#ff0000;">unsafe().register(regFuture);</span>        if (regFuture.cause() != null) {            if (channel.isRegistered()) {                channel.close();            } else {                channel.unsafe().closeForcibly();            }        }        // If we are here and the promise is not failed, it's one of the following cases:        // 1) If we attempted registration from the event loop, the registration has been completed at this point.        //    i.e. It's safe to attempt bind() or connect() now beause the channel has been registered.        // 2) If we attempted registration from the other thread, the registration request has been successfully        //    added to the event loop's task queue for later execution.        //    i.e. It's safe to attempt bind() or connect() now:        //         because bind() or connect() will be executed *after* the scheduled registration task is executed        //         because register(), bind(), and connect() are all bound to the same thread.        return regFuture;    }

上面標紅的代碼,註冊操作實際由unsafe這個工具類來完成, 主要也是向ServerSocketChannel 這個類進行註冊,和java NIO註冊類似.源碼如下:

 protected void doRegister() throws Exception {        boolean selected = false;        for (;;) {            try {                selectionKey = javaChannel().register(eventLoop().selector, 0, this);                return;            } catch (CancelledKeyException e) {                if (!selected) {                    // Force the Selector to select now as the "canceled" SelectionKey may still be                    // cached and not removed because no Select.select(..) operation was called yet.                    eventLoop().selectNow();                    selected = true;                } else {                    // We forced a select operation on the selector before but the SelectionKey is still cached                    // for whatever reason. JDK bug ?                    throw e;                }            }        }    }

channel 類與 unsafe類區別: channel 類主要給基於netty開發的程式員進行讀寫操作,但是netty內部跟  NIo的IO操作主要通過unsafe這個類進行.

通過分析channel的類繼承關係會發現, channel部分抽象類別內部同時也包含相應unsafe類的實現, 是NioServerSocketChannel類的繼承結構.


AbstractNioMessageChannel 到 AbstractChannel 類內部都有 unsafe內部類作為實際操作IO類.







聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.