八 Netty 學習:新連接接入源碼說明

Netty 學習(八):新連接接入源碼說明作者: Grey
原文地址:
博客園:Netty 學習(八):新連接接入源碼說明
CSDN:Netty 學習(八):新連接接入源碼說明
新連接的接入分為3個過程

  1. 檢測到有新連接 。
  2. 將新連接注冊到 worker 線程 。
  3. 注冊新連接的讀事件 。
檢測新連接的代碼在NioEventLoop中的processSelectedKey()方法中
private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {......final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe();......// Also check for readOps of 0 to workaround possible JDK bug which may otherwise lead// to a spin loopif ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {unsafe.read();}.....}啟動一個 Netty 服務端和 Netty 客戶端,在unsafe.read()這一行打斷點,可以得到這里的unsafe就是NioMessageUnsafe , 進入NioMessageUnsaferead()方法,
這個方法主要做的事情就是:創建 , 設置并綁定NioSocketChannel 。
private final List<Object> readBuf = new ArrayList<Object>();@Overridepublic void read() {......do {// 創建`NioSocketChannel`int localRead = doReadMessages(readBuf);......} while (continueReading(allocHandle));......// 設置并綁定 NioSocketChannelint size = readBuf.size();for (int i = 0; i < size; i ++) {readPending = false;pipeline.fireChannelRead(readBuf.get(i));}readBuf.clear();allocHandle.readComplete();pipeline.fireChannelReadComplete();......}}創建NioSocketChannel調用的是doReadMessages()方法 , 通過Debug , 可以看到doReadMessage()來自于NioServerSocketChannel
@Overrideprotected int doReadMessages(List<Object> buf) throws Exception {SocketChannel ch = SocketUtils.accept(javaChannel());try {if (ch != null) {buf.add(new NioSocketChannel(this, ch));return 1;}} catch (Throwable t) {logger.warn("Failed to create a new channel from an accepted socket.", t);try {ch.close();} catch (Throwable t2) {logger.warn("Failed to close a socket.", t2);}}return 0;}可以看到此時調用的是 Java 底層的accept()方法,創建了一條 JDK 層面的Channel,Netty 將其封裝成自定義的NioSocketChannel , 并加入一個List 。
繼續 Debug,進入 NioSocketChannel 的構造方法中,調用的是AbstractNioByteChannel的構造方法
protected AbstractNioByteChannel(Channel parent, SelectableChannel ch) {super(parent, ch, SelectionKey.OP_READ);}這個方法類似在 NIO 編程中,注冊 OP_READ 事件,表示 Channel 對讀事件感興趣 。
接下來是設置并綁定NioSocketChannel,處理每個NioSocketChannel , 通過 Debug 可以來到AbstractUnsaferegister0()方法
private void register0(ChannelPromise promise) {// 注冊SelectordoRegister();// 執行 handlerpipeline.invokeHandlerAddedIfNeeded();// 傳播 ChannelRegistered事件pipeline.fireChannelRegistered();// 注冊讀事件if (isActive()) {if (firstRegistration) {pipeline.fireChannelActive();} else if (config().isAutoRead()) {// This channel was registered before and autoRead() is set. This means we need to begin read// again so that we process inbound data.//// See https://github.com/netty/netty/issues/4805beginRead();}}}這個方法主要完成的事情就是:
  1. NioSocketChannel注冊到Selector
  2. 配置自定義的Handler
  3. 將連接注冊事件傳播下去,調用了每個HandlerchannelRegistered方法 。
  4. 注冊讀事件 。
完整代碼見:hello-netty
本文所有圖例見:processon: Netty學習筆記
更多內容見:Netty專欄
參考資料跟閃電俠學 Netty:Netty 即時聊天實戰與底層原理
深度解析Netty源碼
【八 Netty 學習:新連接接入源碼說明】

    推薦閱讀