Netty客戶端接入流程N(yùn)ioSocketChannel創(chuàng)建解析
前文傳送門(mén):Netty客戶端處理接入事件handle創(chuàng)建
NioSocketChannel的創(chuàng)建
回到上一小節(jié)的read()方法
public void read() {
//必須是NioEventLoop方法調(diào)用的, 不能通過(guò)外部線程調(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用于臨時(shí)承載讀到鏈接
int localRead = doReadMessages(readBuf);
if (localRead == 0) {
break;
}
if (localRead < 0) {
closed = true;
break;
}
//分配器將讀到的鏈接進(jìn)行計(jì)數(shù)
allocHandle.incMessagesRead(localRead);
//連接數(shù)是否超過(guò)最大值
} while (allocHandle.continueReading());
} catch (Throwable t) {
exception = t;
}
int size = readBuf.size();
//遍歷每一條客戶端連接
for (int i = 0; i < size; i ++) {
readPending = false;
//傳遞事件, 將創(chuàng)建NioSokectChannel進(jìn)行傳遞
//最終會(huì)調(diào)用ServerBootstrap的內(nèi)部類(lè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>();
這里只是簡(jiǎn)單的定義了一個(gè)ArrayList, doReadMessages(readBuf)方法就是將讀到的鏈接放在這個(gè)list中, 因?yàn)檫@里是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) {
//封裝成一個(gè)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)該不會(huì)陌生
封裝成一個(gè)NioSokectChannel扔到Readbuf中
這里的NioSocketChannel是對(duì)jdk底層的SocketChannel的包裝, 我們看到其構(gòu)造方法傳入兩個(gè)參數(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)用了父類(lèi)構(gòu)造方法, 傳入兩個(gè)參數(shù), parent代表創(chuàng)建自身channel的, NioServerSocketChannel, socket代表jdk底層的socketChannel
跟到父類(lèi)構(gòu)造方法中
protected AbstractNioByteChannel(Channel parent, SelectableChannel ch) {
super(parent, ch, SelectionKey.OP_READ);
}其中SelectionKey.OP_READ代表其監(jiān)聽(tīng)事件是讀事件
繼續(xù)跟父類(lèi)的構(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)聽(tīng)事件readInterestOp, 也就是讀事件
ch.configureBlocking(false)這一步熟悉nio的小伙伴也不陌生, 就是將jdk的SocketChannel設(shè)置為非阻塞
我們繼續(xù)跟到父類(lèi)構(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)用的, 所以會(huì)走到其父類(lèi)AbstractNioByteChannel的newUnsafe()
跟到newUnsafe()中:
protected AbstractNioUnsafe newUnsafe() {
return new NioByteUnsafe();
}這里創(chuàng)建了NioByteUnsafe對(duì)象, 所以NioSocketChannel對(duì)應(yīng)的unsafe是NioByteUnsafe
繼續(xù)往下跟, 我們看到其初始化了pipeline, 有關(guān)pipline的知識(shí), 我們會(huì)在下一章節(jié)中講到
回到NioSocketChannel中的構(gòu)造方法:
public NioSocketChannel(Channel parent, SocketChannel socket) {
super(parent, socket);
config = new NioSocketChannelConfig(this, socket.socket());
}同NioServerSocketChannel一樣, 這里也初始化了一個(gè)Config屬性, 傳入兩個(gè)參數(shù), 當(dāng)前NioSocketChannel自身和jdk的底層SocketChannel的socket對(duì)象
我們跟進(jìn)其構(gòu)造方法
private NioSocketChannelConfig(NioSocketChannel channel, Socket javaSocket) {
super(channel, javaSocket);
}同樣, 這個(gè)類(lèi)是NioSocketChannel的內(nèi)部類(lèi)
繼續(xù)跟父類(lèi)構(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對(duì)象, 并且默認(rèn)的情況禁止了Nagle算法, 有關(guān)Nagle, 感興趣的同學(xué)可以學(xué)習(xí)下相關(guān)知識(shí)
繼續(xù)跟到父類(lèi)構(gòu)造方法中:
public DefaultChannelConfig(Channel channel) {
this(channel, new AdaptiveRecvByteBufAllocator());
}又跟到到了我們熟悉的部分了, 也就是說(shuō), 無(wú)論NioServerSocketChannel和NioSocketChannel, 最后都會(huì)初始化DefaultChannelConfig, 并創(chuàng)建可變ByteBuf分配器, 我們之前小節(jié)對(duì)此做過(guò)詳細(xì)剖析這里不再贅述, 這部分忘記的內(nèi)容可以閱讀之前小節(jié)內(nèi)容進(jìn)行回顧
這個(gè)分配器什么時(shí)候真正分配字節(jié)緩沖的呢?我們會(huì)在之后的章節(jié)進(jìn)行詳細(xì)剖析
至此我們剖析完成了NioSocketChannel的初始化過(guò)程
以上就是Netty客戶端接入流程N(yùn)ioSocketChannel創(chuàng)建源碼解析的詳細(xì)內(nèi)容,更多關(guān)于Netty客戶端接入流程N(yùn)ioSocketChannel的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Netty分布式NioSocketChannel注冊(cè)到selector方法解析
- Netty分布式NioEventLoop任務(wù)隊(duì)列執(zhí)行源碼分析
- Netty源碼分析NioEventLoop執(zhí)行select操作入口
- Netty分布式NioEventLoop優(yōu)化selector源碼解析
- Netty源碼分析NioEventLoop線程的啟動(dòng)
- Netty源碼分析NioEventLoop初始化線程選擇器創(chuàng)建
- Netty源碼解析NioEventLoop創(chuàng)建的構(gòu)造方法
- Netty實(shí)戰(zhàn)源碼解析NIO編程
相關(guān)文章
簡(jiǎn)單了解Java多線程實(shí)現(xiàn)的四種方式
這篇文章主要介紹了簡(jiǎn)單了解Java多線程實(shí)現(xiàn)的四種方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05
springboot框架阿里開(kāi)源低代碼工具LowCodeEngine
這篇文章主要為大家介紹了springboot框架阿里開(kāi)源低代碼LowCodeEngine工具使用詳解有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
Mybatis基于xml配置實(shí)現(xiàn)單表的增刪改查功能
這篇文章主要介紹了Mybatis基于xml配置實(shí)現(xiàn)單表的增刪改查,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04
Spring定時(shí)任務(wù)注解@Scheduled詳解
這篇文章主要介紹了Spring定時(shí)任務(wù)注解@Scheduled詳解,@Scheduled注解是包org.springframework.scheduling.annotation中的一個(gè)注解,主要是用來(lái)開(kāi)啟定時(shí)任務(wù),本文提供了部分實(shí)現(xiàn)代碼與思路,需要的朋友可以參考下2023-09-09
Java數(shù)據(jù)結(jié)構(gòu)常見(jiàn)幾大排序梳理
Java常見(jiàn)的排序算法有:直接插入排序、希爾排序、選擇排序、冒泡排序、歸并排序、快速排序、堆排序等。本文詳解介紹它們的實(shí)現(xiàn)以及圖解,需要的可以參考一下2022-03-03
Java如何實(shí)現(xiàn)可折疊Panel方法示例
這篇文章主要給大家介紹了關(guān)于利用Java如何實(shí)現(xiàn)可折疊Panel的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-07-07
通過(guò)Java壓縮JavaScript代碼實(shí)例分享
這篇文章主要介紹了通過(guò)Java壓縮JavaScript代碼實(shí)例分享,具有一定參考價(jià)值,需要的朋友可以了解下。2017-12-12

