日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Tomcat架构解析之3 Connector NIO

發(fā)布時(shí)間:2025/3/19 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Tomcat架构解析之3 Connector NIO 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

上文簡(jiǎn)單記錄了默認(rèn)的Connector的內(nèi)部構(gòu)造及消息流,同時(shí)此Connector也是基于BIO的實(shí)現(xiàn)。
除BIO,也可以通過配置快速部署NIO的connector。在server.xml中如下配置;


整個(gè)Tomcat是一個(gè)比較完善的框架體系,各組件間都是基于接口實(shí)現(xiàn),方便擴(kuò)展
像這里的org.apache.coyote.http11.Http11NioProtocol和BIO的org.apache.coyote.http11.Http11Protocol都是統(tǒng)一的實(shí)現(xiàn)org.apache.coyote.ProtocolHandler接口
ProtocolHandler的實(shí)現(xiàn)類
從整體結(jié)構(gòu)上來說,NIO還是與BIO的實(shí)現(xiàn)保持大體一致
NIO connector的內(nèi)部結(jié)構(gòu)
還是可以看見Connector中三大件

  • Http11NioProtocol
  • Mapper
  • CoyoteAdapter

基本功能與BIO的類似
重點(diǎn)看看Http11NioProtocol.



和JIoEndpoint一樣,NioEndpoint是Http11NioProtocol中負(fù)責(zé)接收處理socket的主要模塊
NioEndpoint的主要流程
Acceptor及Worker分別是以線程池形式存在
Poller是一個(gè)單線程
注意,與BIO的實(shí)現(xiàn)一樣,默認(rèn)狀態(tài)下,在server.xml中

  • 沒有配置<Executor>,則以Worker線程池運(yùn)行
  • 配置了<Executor>,則以基于juc 系列的ThreadPoolExecutor線程池運(yùn)行。

Acceptor

  • 接收socket線程,這里雖然是基于NIO的connector,但是在接收socket方面還是傳統(tǒng)的serverSocket.accept()方式,獲得SocketChannel對(duì)象
  • 然后封裝在一個(gè)tomcat的實(shí)現(xiàn)類org.apache.tomcat.util.net.NioChannel對(duì)象中
  • 然后將NioChannel對(duì)象封裝在一個(gè)PollerEvent對(duì)象中,并將PollerEvent對(duì)象壓入events queue里。這里是個(gè)典型的生產(chǎn)者-消費(fèi)者模式,Acceptor與Poller線程之間通過queue通信,Acceptor是events queue的生產(chǎn)者,Poller是events queue的消費(fèi)者。

Poller

Poller線程中維護(hù)了一個(gè)Selector對(duì)象,NIO就是基于Selector來完成邏輯的
在Connector中并不止一個(gè)Selector,在Socket的讀寫數(shù)據(jù)時(shí),為了控制timeout也有一個(gè)Selector,在后面的BlockSelector中介紹。可以先把Poller線程中維護(hù)的這個(gè)Selector標(biāo)為主Selector
Poller是NIO實(shí)現(xiàn)的主要線程。首先作為events queue的消費(fèi)者,從queue中取出PollerEvent對(duì)象,然后將此對(duì)象中的channel以O(shè)P_READ事件注冊(cè)到主Selector中,然后主Selector執(zhí)行select操作,遍歷出可以讀數(shù)據(jù)的socket,并從Worker線程池中拿到可用的Worker線程,然后將socket傳遞給Worker。整個(gè)過程是典型的NIO實(shí)現(xiàn)。

Worker

Worker線程拿到Poller傳過來的socket后,將socket封裝在SocketProcessor對(duì)象中。然后從Http11ConnectionHandler中取出Http11NioProcessor對(duì)象,從Http11NioProcessor中調(diào)用CoyoteAdapter的邏輯,跟BIO實(shí)現(xiàn)一樣。在Worker線程中,會(huì)完成從socket中讀取http request,解析成HttpServletRequest對(duì)象,分派到相應(yīng)的servlet并完成邏輯,然后將response通過socket發(fā)回client。在從socket中讀數(shù)據(jù)和往socket中寫數(shù)據(jù)的過程,并沒有像典型的非阻塞的NIO的那樣,注冊(cè)O(shè)P_READ或OP_WRITE事件到主Selector,而是直接通過socket完成讀寫,這時(shí)是阻塞完成的,但是在timeout控制上,使用了NIO的Selector機(jī)制,但是這個(gè)Selector并不是Poller線程維護(hù)的主Selector,而是BlockPoller線程中維護(hù)的Selector,稱之為輔Selector。

NioSelectorPool

NioEndpoint對(duì)象中維護(hù)了一個(gè)NioSelecPool對(duì)象,這個(gè)NioSelectorPool中又維護(hù)了一個(gè)BlockPoller線程,這個(gè)線程就是基于輔Selector進(jìn)行NIO的邏輯。以執(zhí)行servlet后,得到response,往socket中寫數(shù)據(jù)為例,最終寫的過程調(diào)用NioBlockingSelector的write方法。

public int write(ByteBuffer buf, NioChannel socket, long writeTimeout,MutableInteger lastWrite) throws IOException { SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector()); if ( key == null ) throw new IOException("Key no longer registered"); KeyAttachment att = (KeyAttachment) key.attachment(); int written = 0; boolean timedout = false; int keycount = 1; //assume we can write long time = System.currentTimeMillis(); //start the timeout timer try { while ( (!timedout) && buf.hasRemaining()) { if (keycount > 0) { //only write if we were registered for a write //直接往socket中寫數(shù)據(jù) int cnt = socket.write(buf); //write the data lastWrite.set(cnt); if (cnt == -1) throw new EOFException(); written += cnt; //寫數(shù)據(jù)成功,直接進(jìn)入下一次循環(huán),繼續(xù)寫 if (cnt > 0) { time = System.currentTimeMillis(); //reset our timeout timer continue; //we successfully wrote, try again without a selector } } //如果寫數(shù)據(jù)返回值cnt等于0,通常是網(wǎng)絡(luò)不穩(wěn)定造成的寫數(shù)據(jù)失敗 try { //開始一個(gè)倒數(shù)計(jì)數(shù)器 if ( att.getWriteLatch()==null || att.getWriteLatch().getCount()==0) att.startWriteLatch(1); //將socket注冊(cè)到輔Selector,這里poller就是BlockSelector線程 poller.add(att,SelectionKey.OP_WRITE); //阻塞,直至超時(shí)時(shí)間喚醒,或者在還沒有達(dá)到超時(shí)時(shí)間,在BlockSelector中喚醒 att.awaitWriteLatch(writeTimeout,TimeUnit.MILLISECONDS); }catch (InterruptedException ignore) { Thread.interrupted(); } if ( att.getWriteLatch()!=null && att.getWriteLatch().getCount()> 0) { keycount = 0; }else { //還沒超時(shí)就喚醒,說明網(wǎng)絡(luò)狀態(tài)恢復(fù),繼續(xù)下一次循環(huán),完成寫socket keycount = 1; att.resetWriteLatch(); } if (writeTimeout > 0 && (keycount == 0)) timedout = (System.currentTimeMillis() - time) >= writeTimeout; } //while if (timedout) throw new SocketTimeoutException(); } finally { poller.remove(att,SelectionKey.OP_WRITE); if (timedout && key != null) { poller.cancelKey(socket, key); } } return written; }

也就是說當(dāng)socket.write()返回0時(shí),說明網(wǎng)絡(luò)狀態(tài)不穩(wěn)定,這時(shí)將socket注冊(cè)O(shè)P_WRITE事件到輔Selector,由BlockPoller線程不斷輪詢這個(gè)輔Selector,直到發(fā)現(xiàn)這個(gè)socket的寫狀態(tài)恢復(fù)了,通過那個(gè)倒數(shù)計(jì)數(shù)器,通知Worker線程繼續(xù)寫socket動(dòng)作。

看一下BlockSelector線程的邏輯;

public void run() { while (run) { try { ...... Iterator iterator = keyCount > 0 ? selector.selectedKeys().iterator() : null; while (run && iterator != null && iterator.hasNext()) { SelectionKey sk = (SelectionKey) iterator.next(); KeyAttachment attachment = (KeyAttachment)sk.attachment(); try { attachment.access(); iterator.remove(); ; sk.interestOps(sk.interestOps() & (~sk.readyOps())); if ( sk.isReadable() ) { countDown(attachment.getReadLatch()); } //發(fā)現(xiàn)socket可寫狀態(tài)恢復(fù),將倒數(shù)計(jì)數(shù)器置位,通知Worker線程繼續(xù) if (sk.isWritable()) { countDown(attachment.getWriteLatch()); } }catch (CancelledKeyException ckx) { if (sk!=null) sk.cancel(); countDown(attachment.getReadLatch()); countDown(attachment.getWriteLatch()); } }//while }catch ( Throwable t ) { log.error("",t); } } events.clear(); try { selector.selectNow();//cancel all remaining keys }catch( Exception ignore ) { if (log.isDebugEnabled())log.debug("",ignore); } }

使用這個(gè)輔Selector主要是減少線程間的切換,同時(shí)還可減輕主Selector的負(fù)擔(dān)。以上描述了NIO connector工作的主要邏輯,可以看到在設(shè)計(jì)上還是比較精巧的。NIO connector還有一塊就是Comet,有時(shí)間再說吧。需要注意的是,上面從Acceptor開始,有很多對(duì)象的封裝,NioChannel及其KeyAttachment,PollerEvent和SocketProcessor對(duì)象,這些不是每次都重新生成一個(gè)新的,都是NioEndpoint分別維護(hù)了它們的對(duì)象池;

ConcurrentLinkedQueue<SocketProcessor> processorCache = new ConcurrentLinkedQueue<SocketProcessor>() ConcurrentLinkedQueue<KeyAttachment> keyCache = new ConcurrentLinkedQueue<KeyAttachment>() ConcurrentLinkedQueue<PollerEvent> eventCache = new ConcurrentLinkedQueue<PollerEvent>() ConcurrentLinkedQueue<NioChannel> nioChannels = new ConcurrentLinkedQueue<NioChannel>()

當(dāng)需要這些對(duì)象時(shí),分別從它們的對(duì)象池獲取,當(dāng)用完后返回給相應(yīng)的對(duì)象池,這樣可以減少因?yàn)閯?chuàng)建及GC對(duì)象時(shí)的性能消耗

總結(jié)

以上是生活随笔為你收集整理的Tomcat架构解析之3 Connector NIO的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 深夜在线网站 | free黑人多人性派对hd | 狠狠操夜夜爽 | 中文字幕电影一区二区 | 亚洲av无码国产在丝袜线观看 | 国产欧美一区二区三区精华液好吗 | 97人人澡人人爽人人模亚洲 | 日韩在线一卡二卡 | 精品国产二区三区 | 国产精品一区二区在线播放 | 污网站在线免费 | 国产成人精品一区二区三区四区 | 国产美女福利在线 | 欧美日韩啪啪 | 日本高清www免费视频 | 特黄网站 | 免费黄在线看 | 美脚の诱脚舐め脚视频播放 | 国产精品国产三级国产专区51 | 99色在线观看 | 色网在线免费观看 | 亚洲精品久久久久av无码 | 国产成人久久精品麻豆二区 | 99久久99| 亚洲综合色视频 | 成人av一区二区三区 | 男人天堂1024 | 国产精品网址 | 亚洲乱码一区 | 亚洲自拍偷拍精品视频 | 亚洲视频色 | 亚洲国产精品无码观看久久 | 兔费看少妇性l交大片免费 日韩高清不卡 | 国产成人午夜高潮毛片 | 中国在线观看视频高清免费 | 国产特级淫片免费看 | 亚洲一区二区电影网 | 日韩福利小视频 | 日本涩涩视频 | 国产精品久久麻豆 | 男女激情四射网站 | 女教师痴汉调教hd中字 | 黄色片在线观看视频 | 日韩av资源网 | 国产精品无码免费播放 | 五月婷婷俺也去 | 亚欧美在线观看 | www.av免费 | 成人爽站w47pw | 国产亚洲精品久久久久久久久动漫 | 中国女人裸体乱淫 | 黄色精品视频 | 国产一二三在线视频 | 国产成人免费在线观看 | 日本精品一区视频 | 欧美交换配乱吟粗大25p | 亚洲国产成人精品久久 | www.av777| 每日av在线| 一本到视频 | 亚洲精品国产精品乱码在线观看 | 香蕉视频1024 | 国产一区二区女内射 | 免费av资源 | 国产内射一区二区 | 91久久精品国产91性色69 | 少妇15p| 男女污污网站 | 成人在线短视频 | 公侵犯一区二区三区 | 亚州黄色| 伊人久久狼人 | 看特级黄色片 | 伦hdwww日本bbw另类 | 亚洲国产精品成人va在线观看 | 中文字幕欧美一区 | 亚洲产国偷v产偷v自拍涩爱 | 91鲁| 亚洲AV成人午夜无码精品久久 | 久久久久久久国产视频 | 日本少妇三级 | 日本久操视频 | 日韩精品视频免费播放 | 天天射天天拍 | 性高潮久久久久久久 | av鲁丝一区鲁丝二区鲁丝 | 噜噜av| 国内精品卡一卡二卡三 | 亚洲女人被黑人巨大进入 | 99久久精品免费看国产免费软件 | 国产91影院| 香蕉日日| 69er小视频| 色偷偷免费 | 色猫咪av在线 | 欧美69久成人做爰视频 | 久久久久久国产精品 | 少妇被黑人到高潮喷出白浆 | 激情天堂网 |