日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
JavaNIO如何處理慢速的連接

對(duì)企業(yè)級(jí)的服務(wù)器軟件,高性能和可擴(kuò)展性是基本的要求。除此之外,還應(yīng)該有應(yīng)對(duì)各種不同環(huán)境的能力。例如,一個(gè)好的服務(wù)器軟件不應(yīng)該假設(shè)所有的客戶端都有很快的處理能力和很好的網(wǎng)絡(luò)環(huán)境。如果一個(gè)客戶端的運(yùn)行速度很慢,或者網(wǎng)絡(luò)速度很慢,這就意味著整個(gè)請(qǐng)求的時(shí)間變長(zhǎng)。而對(duì)于服務(wù)器來(lái)說(shuō),這就意味著這個(gè)客戶端的請(qǐng)求將占用更長(zhǎng)的時(shí)間。這個(gè)時(shí)間的延遲不是由服務(wù)器造成的,因此CPU的占用不會(huì)增加什么,但是網(wǎng)絡(luò)連接的時(shí)間會(huì)增加,處理線程的占用時(shí)間也會(huì)增加。這就造成了當(dāng)前處理線程和其他資源得不到很快的釋放,無(wú)法被其他客戶端的請(qǐng)求來(lái)重用。例如Tomcat,當(dāng)存在大量慢速連接的客戶端時(shí),線程資源被這些慢速的連接消耗掉,使得服務(wù)器不能響應(yīng)其他的請(qǐng)求了。

前面介紹過(guò),NIO的異步非阻塞的形式,使得很少的線程就能服務(wù)于大量的請(qǐng)求。通過(guò)Selector的注冊(cè)功能,可以有選擇性地返回已經(jīng)準(zhǔn)備好的頻道,這樣就不需要為每一個(gè)請(qǐng)求分配單獨(dú)的線程來(lái)服務(wù)。

在一些流行的NIO的框架中,都能看到對(duì)OP_ACCEPT和OP_READ的處理。很少有對(duì)OP_WRITE的處理。我們經(jīng)??吹降拇a就是在請(qǐng)求處理完成后,直接通過(guò)下面的代碼將結(jié)果返回給客戶端:

不對(duì)OP_WRITE進(jìn)行處理的樣例:

 
 
 
  1. while (bb.hasRemaining()) {  
  2.     int len = socketChannel.write(bb);  
  3.     if (len < 0) {  
  4.         throw new EOFException();  
  5.     }  

這樣寫(xiě)在大多數(shù)的情況下都沒(méi)有什么問(wèn)題。但是在客戶端的網(wǎng)絡(luò)環(huán)境很糟糕的情況下,服務(wù)器會(huì)遭到很沉重的打擊。

因?yàn)槿绻蛻舳说木W(wǎng)絡(luò)或者是中間交換機(jī)的問(wèn)題,使得網(wǎng)絡(luò)傳輸?shù)男屎艿?,這時(shí)候會(huì)出現(xiàn)服務(wù)器已經(jīng)準(zhǔn)備好的返回結(jié)果無(wú)法通過(guò)TCP/IP層傳輸?shù)娇蛻舳恕_@時(shí)候在執(zhí)行上面這段程序的時(shí)候就會(huì)出現(xiàn)以下情況。

(1) bb.hasRemaining()一直為“true”,因?yàn)榉?wù)器的返回結(jié)果已經(jīng)準(zhǔn)備好了。

(2) socketChannel.write(bb)的結(jié)果一直為0,因?yàn)橛捎诰W(wǎng)絡(luò)原因數(shù)據(jù)一直傳不過(guò)去。

(3) 因?yàn)槭钱惒椒亲枞姆绞剑瑂ocketChannel.write(bb)不會(huì)被阻塞,立刻被返回。

(4) 在一段時(shí)間內(nèi),這段代碼會(huì)被無(wú)休止地快速執(zhí)行著,消耗著大量的CPU的資源。事實(shí)上什么具體的任務(wù)也沒(méi)有做,一直到網(wǎng)絡(luò)允許當(dāng)前的數(shù)據(jù)傳送出去為止。

這樣的結(jié)果顯然不是我們想要的。因此,我們對(duì)OP_WRITE也應(yīng)該加以處理。在NIO中最常用的方法如下。

一般NIO框架中對(duì)OP_WRITE的處理:

 
 
 
  1. while (bb.hasRemaining()) {  
  2.     int len = socketChannel.write(bb);  
  3.     if (len < 0){  
  4.         throw new EOFException();  
  5.     }  
  6.     if (len == 0) {  
  7.         selectionKey.interestOps(  
  8.                         selectionKey.interestOps() | SelectionKey.OP_WRITE);  
  9.         mainSelector.wakeup();  
  10.         break;  
  11.     }  

上面的程序在網(wǎng)絡(luò)不好的時(shí)候,將此頻道的OP_WRITE操作注冊(cè)到Selector上,這樣,當(dāng)網(wǎng)絡(luò)恢復(fù),頻道可以繼續(xù)將結(jié)果數(shù)據(jù)返回客戶端的時(shí)候,Selector會(huì)通過(guò)SelectionKey來(lái)通知應(yīng)用程序,再去執(zhí)行寫(xiě)的操作。這樣就能節(jié)約大量的CPU資源,使得服務(wù)器能適應(yīng)各種惡劣的網(wǎng)絡(luò)環(huán)境。

可是,Grizzly中對(duì)OP_WRITE的處理并不是這樣的。我們先看看Grizzly的源碼吧。在Grizzly中,對(duì)請(qǐng)求結(jié)果的返回是在ProcessTask中處理的,經(jīng)過(guò)SocketChannelOutputBuffer的類(lèi),最終通過(guò)OutputWriter類(lèi)來(lái)完成返回結(jié)果的動(dòng)作。在OutputWriter中處理OP_WRITE的代碼如下:

Grizzly中對(duì)OP_WRITE的處理:

 
 
 
  1. public static long flushChannel(SocketChannel socketChannel,  
  2.         ByteBuffer bb, long writeTimeout) throws IOException  
  3. {  
  4.     SelectionKey key = null;  
  5.     Selector writeSelector = null;  
  6.     int attempts = 0;  
  7.     int bytesProduced = 0;  
  8.     try {  
  9.         while (bb.hasRemaining()) {  
  10.             int len = socketChannel.write(bb);  
  11.             attempts++;  
  12.             if (len < 0){  
  13.                 throw new EOFException();  
  14.             }  
  15.             bytesProduced += len;  
  16.             if (len == 0) {  
  17.                 if (writeSelector == null){  
  18.                     writeSelector = SelectorFactory.getSelector();  
  19.                     if (writeSelector == null){  
  20.                         // Continue using the main one  
  21.                         continue;  
  22.                     }  
  23.                 }  
  24.                 key = socketChannel.register(writeSelector, key.OP_WRITE);  
  25.                 if (writeSelector.select(writeTimeout) == 0) {  
  26.                     if (attempts > 2)  
  27.                         throw new IOException("Client disconnected");  
  28.                 } else {  
  29.                     attempts--;  
  30.                 }  
  31.             } else {  
  32.                 attempts = 0;  
  33.             }  
  34.         }  
  35.     } finally {  
  36.         if (key != null) {  
  37.             key.cancel();  
  38.             key = null;  
  39.         }  
  40.         if (writeSelector != null) {  
  41.             // Cancel the key.  
  42.             writeSelector.selectNow();  
  43.             SelectorFactory.returnSelector(writeSelector);  
  44.         }  
  45.     }  
  46.     return bytesProduced;  

上面的程序例17.9與例17.8的區(qū)別之處在于:當(dāng)發(fā)現(xiàn)由于網(wǎng)絡(luò)情況而導(dǎo)致的發(fā)送數(shù)據(jù)受阻(len==0)時(shí),例17.8的處理是將當(dāng)前的頻道注冊(cè)到當(dāng)前的Selector中;而在例17.9中,程序從SelectorFactory中獲得了一個(gè)臨時(shí)的Selector。在獲得這個(gè)臨時(shí)的Selector之后,程序做了一個(gè)阻塞的操作:writeSelector.select(writeTimeout)。這個(gè)阻塞操作會(huì)在一定時(shí)間內(nèi)(writeTimeout)等待這個(gè)頻道的發(fā)送狀態(tài)。如果等待時(shí)間過(guò)長(zhǎng),便認(rèn)為當(dāng)前的客戶端的連接異常中斷了。

這種實(shí)現(xiàn)方式頗受爭(zhēng)議。有很多開(kāi)發(fā)者置疑Grizzly的作者為什么不使用例17.8的模式。另外在實(shí)際處理中,Grizzly的處理方式事實(shí)上放棄了NIO中的非阻塞的優(yōu)勢(shì),使用writeSelector.select(writeTimeout)做了個(gè)阻塞操作。雖然CPU的資源沒(méi)有浪費(fèi),可是線程資源在阻塞的時(shí)間內(nèi),被這個(gè)請(qǐng)求所占有,不能釋放給其他請(qǐng)求來(lái)使用。

Grizzly的作者對(duì)此的回應(yīng)如下。

(1) 使用臨時(shí)的Selector的目的是減少線程間的切換。當(dāng)前的Selector一般用來(lái)處理OP_ACCEPT,和OP_READ的操作。使用臨時(shí)的Selector可減輕主Selector的負(fù)擔(dān);而在注冊(cè)的時(shí)候則需要進(jìn)行線程切換,會(huì)引起不必要的系統(tǒng)調(diào)用。這種方式避免了線程之間的頻繁切換,有利于系統(tǒng)的性能提高。

(2) 雖然writeSelector.select(writeTimeout)做了阻塞操作,但是這種情況只是少數(shù)極端的環(huán)境下才會(huì)發(fā)生。大多數(shù)的客戶端是不會(huì)頻繁出現(xiàn)這種現(xiàn)象的,因此在同一時(shí)刻被阻塞的線程不會(huì)很多。

(3) 利用這個(gè)阻塞操作來(lái)判斷異常中斷的客戶連接。

(4) 經(jīng)過(guò)壓力實(shí)驗(yàn)證明這種實(shí)現(xiàn)的性能是非常好的。


網(wǎng)站題目:JavaNIO如何處理慢速的連接
網(wǎng)頁(yè)URL:http://m.5511xx.com/article/cdehhhc.html