Netty客戶端接入流程NioSocketChannel創(chuàng)建解析
前文傳送門:Netty客戶端處理接入事件handle創(chuàng)建
NioSocketChannel的創(chuàng)建
回到上一小節(jié)的read()方法
public void read() { //必須是NioEventLoop方法調(diào)用的, 不能通過外部線程調(diào)用 assert eventLoop().inEventLoop(); //服務(wù)端channel的config final ChannelConfig config = config(); //服務(wù)端channel的pipeline final ChannelPipeline pipeline = pipeline(); //處理服務(wù)端接入的速率 final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle(); //設(shè)置配置 allocHandle.reset(config); boolean closed = false; Throwable exception = null; try { try { do { //創(chuàng)建jdk底層的channel //readBuf用于臨時承載讀到鏈接 int localRead = doReadMessages(readBuf); if (localRead == 0) { break; } if (localRead < 0) { closed = true; break; } //分配器將讀到的鏈接進行計數(shù) allocHandle.incMessagesRead(localRead); //連接數(shù)是否超過最大值 } while (allocHandle.continueReading()); } catch (Throwable t) { exception = t; } int size = readBuf.size(); //遍歷每一條客戶端連接 for (int i = 0; i < size; i ++) { readPending = false; //傳遞事件, 將創(chuàng)建NioSokectChannel進行傳遞 //最終會調(diào)用ServerBootstrap的內(nèi)部類ServerBootstrapAcceptor的channelRead()方法 pipeline.fireChannelRead(readBuf.get(i)); } readBuf.clear(); allocHandle.readComplete(); pipeline.fireChannelReadComplete(); //代碼省略 } finally { //代碼省略 } }
我們繼續(xù)剖析int localRead = doReadMessages(readBuf)這一部分邏輯
我們首先看readBuf
private final List<Object> readBuf = new ArrayList<Object>();
這里只是簡單的定義了一個ArrayList, doReadMessages(readBuf)方法就是將讀到的鏈接放在這個list中, 因為這里是NioServerSocketChannel所以這走到了NioServerSocketChannel的doReadMessage()方法
跟到doReadMessage()方法中:
protected int doReadMessages(List<Object> buf) throws Exception { //根據(jù)當(dāng)前jdk底層的serverSocketChannel拿到j(luò)dk底層channel SocketChannel ch = javaChannel().accept(); try { if (ch != null) { //封裝成一個NioSokectChannel扔到buf中 buf.add(new NioSocketChannel(this, ch)); return 1; } } catch (Throwable t) { //代碼省略 } return 0; }
jdk底層相關(guān)的內(nèi)容
首先根據(jù)jdk的ServerSocketChannel拿到j(luò)dk的Channel, 熟悉Nio的小伙伴應(yīng)該不會陌生
封裝成一個NioSokectChannel扔到Readbuf中
這里的NioSocketChannel是對jdk底層的SocketChannel的包裝, 我們看到其構(gòu)造方法傳入兩個參數(shù), this代表當(dāng)前NioServerSocketChannel, ch代表jdk的SocketChannel
我們跟到NioSocketChannel的構(gòu)造方法中:
public NioSocketChannel(Channel parent, SocketChannel socket) { super(parent, socket); config = new NioSocketChannelConfig(this, socket.socket()); }
這里看到調(diào)用了父類構(gòu)造方法, 傳入兩個參數(shù), parent代表創(chuàng)建自身channel的, NioServerSocketChannel, socket代表jdk底層的socketChannel
跟到父類構(gòu)造方法中
protected AbstractNioByteChannel(Channel parent, SelectableChannel ch) { super(parent, ch, SelectionKey.OP_READ); }
其中SelectionKey.OP_READ代表其監(jiān)聽事件是讀事件
繼續(xù)跟父類的構(gòu)造方法:
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) { super(parent); this.ch = ch; this.readInterestOp = readInterestOp; try { //設(shè)置為非阻塞 ch.configureBlocking(false); } catch (IOException e) { //代碼省略 } }
這里初始化了自身成員變量ch, 就是jdk底層的SocketChannel, 并初始化了自身的監(jiān)聽事件readInterestOp, 也就是讀事件
ch.configureBlocking(false)這一步熟悉nio的小伙伴也不陌生, 就是將jdk的SocketChannel設(shè)置為非阻塞
我們繼續(xù)跟到父類構(gòu)造方法中:
protected AbstractChannel(Channel parent) { this.parent = parent; id = newId(); unsafe = newUnsafe(); pipeline = newChannelPipeline(); }
這里初始化parent, 也就是創(chuàng)建自身的NioServerSocketChannel, 并為自身創(chuàng)建了唯一id
初始化unsafe, 我們跟到newUnsafe()方法中
由于此方法是NioEventLoop調(diào)用的, 所以會走到其父類AbstractNioByteChannel的newUnsafe()
跟到newUnsafe()中:
protected AbstractNioUnsafe newUnsafe() { return new NioByteUnsafe(); }
這里創(chuàng)建了NioByteUnsafe對象, 所以NioSocketChannel對應(yīng)的unsafe是NioByteUnsafe
繼續(xù)往下跟, 我們看到其初始化了pipeline, 有關(guān)pipline的知識, 我們會在下一章節(jié)中講到
回到NioSocketChannel中的構(gòu)造方法:
public NioSocketChannel(Channel parent, SocketChannel socket) { super(parent, socket); config = new NioSocketChannelConfig(this, socket.socket()); }
同NioServerSocketChannel一樣, 這里也初始化了一個Config屬性, 傳入兩個參數(shù), 當(dāng)前NioSocketChannel自身和jdk的底層SocketChannel的socket對象
我們跟進其構(gòu)造方法
private NioSocketChannelConfig(NioSocketChannel channel, Socket javaSocket) { super(channel, javaSocket); }
同樣, 這個類是NioSocketChannel的內(nèi)部類
繼續(xù)跟父類構(gòu)造方法:
public DefaultSocketChannelConfig(SocketChannel channel, Socket javaSocket) { super(channel); if (javaSocket == null) { throw new NullPointerException("javaSocket"); } //保存當(dāng)前javaSocket this.javaSocket = javaSocket; //是否禁止Nagle算法 if (PlatformDependent.canEnableTcpNoDelayByDefault()) { try { setTcpNoDelay(true); } catch (Exception e) { } } }
這里保存了SocketChannel的socket對象, 并且默認的情況禁止了Nagle算法, 有關(guān)Nagle, 感興趣的同學(xué)可以學(xué)習(xí)下相關(guān)知識
繼續(xù)跟到父類構(gòu)造方法中:
public DefaultChannelConfig(Channel channel) { this(channel, new AdaptiveRecvByteBufAllocator()); }
又跟到到了我們熟悉的部分了, 也就是說, 無論NioServerSocketChannel和NioSocketChannel, 最后都會初始化DefaultChannelConfig, 并創(chuàng)建可變ByteBuf分配器, 我們之前小節(jié)對此做過詳細剖析這里不再贅述, 這部分忘記的內(nèi)容可以閱讀之前小節(jié)內(nèi)容進行回顧
這個分配器什么時候真正分配字節(jié)緩沖的呢?我們會在之后的章節(jié)進行詳細剖析
至此我們剖析完成了NioSocketChannel的初始化過程
以上就是Netty客戶端接入流程NioSocketChannel創(chuàng)建源碼解析的詳細內(nèi)容,更多關(guān)于Netty客戶端接入流程NioSocketChannel的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
一文帶你深入了解Java的數(shù)據(jù)結(jié)構(gòu)
Java工具包提供了強大的數(shù)據(jù)結(jié)構(gòu)。這篇文章主要為大家詳細介紹了Java數(shù)據(jù)結(jié)構(gòu)中常用的幾種接口和類,感興趣的小伙伴可以跟隨小編一起了解一下2023-05-05SpringCloud?微服務(wù)數(shù)據(jù)權(quán)限控制的實現(xiàn)
這篇文章主要介紹的是權(quán)限控制的數(shù)據(jù)權(quán)限層面,意思是控制可訪問數(shù)據(jù)資源的數(shù)量,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2021-11-11關(guān)于SpringSecurity簡介以及和Shiro的區(qū)別
這篇文章主要介紹了關(guān)于SpringSecurity簡介以及和Shiro的區(qū)別,在Java應(yīng)用安全領(lǐng)域,Spring Security會成為被首先推崇的解決方案,就像我們看到服務(wù)器就會聯(lián)想到Linux一樣順理成章,需要的朋友可以參考下2023-07-07java中并發(fā)Queue種類與各自API特點以及使用場景說明
這篇文章主要介紹了java中并發(fā)Queue種類與各自API特點以及使用場景說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06Java中一維二維數(shù)組的靜態(tài)和動態(tài)初始化
今天通過本文給大家分享Java中的數(shù)組,包括一維數(shù)組和二維數(shù)組的靜態(tài)初始化和動態(tài)初始化問題,感興趣的朋友一起看看吧2017-10-10Spring使用Redis限制用戶登錄失敗的次數(shù)及暫時鎖定用戶登錄權(quán)限功能
這篇文章主要介紹了Spring使用Redis限制用戶登錄失敗的次數(shù)及暫時鎖定用戶登錄權(quán)限功能,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下2024-02-02