站長資訊網
        最全最豐富的資訊網站

        Java NIO類庫Selector機制解析(上)

        自從J2SE
        1.4版本以來,JDK發布了全新的I/O類庫,簡稱NIO,其不但引入了全新的高效的I/O機制,同時,也引入了多路復用的異步模式。下面將介紹Java
        NIO類庫Selector機制的解析。

         

         

           

          一、 前言

          自從J2SE
          1.4版本以來,JDK發布了全新的I/O類庫,簡稱NIO,其不但引入了全新的高效的I/O機制,同時,也引入了多路復用的異步模式。NIO的包中主要包含了這樣幾種抽象數據類型:

          ◆  Buffer:包含數據且用于讀寫的線形表結構。其中還提供了一個特殊類用于內存映射文件的I/O操作。

          ◆  Charset:它提供Unicode字符串影射到字節序列以及逆映射的操作。

          ◆  Channels:包含socket,file和pipe三種管道,都是全雙工的通道。

          ◆  Selector:多個異步I/O操作集中到一個或多個線程中(可以被看成是Unix中select()函數的面向對象版本)。

          我的大學同學趙錕在使用NIO類庫書寫相關網絡程序的時候,發現了一些Java異常RuntimeException,異常的報錯信息讓他開始了對NIO的Selector進行了一些調查。當趙錕對我共享了Selector的一些底層機制的猜想和調查時候,我們覺得這是一件很有意思的事情,于是在伙同趙錕進行過一系列的調查后,我倆發現了很多有趣的事情,于是導致了這篇文章的產生。這也是為什么本文的作者署名為我們兩人的原因。

          先要說明的一點是,趙錕和我本質上都是出身于Unix/Linux/C/C++的開發人員,對于Java,這并不是我們的長處,這篇文章本質上出于對Java的Selector的好奇,因為從表面上來看Selector似乎做到了一些讓我們這些C/C++出身的人比較驚奇的事情。

          下面讓我來為你講述一下這段故事。

          二、 故事開始 : 讓C++程序員寫Java程序!

          沒有嚴重內存問題,大量豐富的SDK類庫,超容易的跨平臺,除了在性能上有些微辭,C++出身的程序員從來都不會覺得Java是一件很困難的事情。當然,對于長期習慣于使用操作系統API(系統調用System Call)的C/C++程序來說,面對Java中的比較“另類”地操作系統資源的方法可能會略感困惑,但萬變不離其宗,只需要對面向對象的設計模式有一定的了解,用不了多長時間,Java的SDK類庫也能玩得隨心所欲。

          在使用Java進行相關網絡程序的的設計時,出身C/C++的人,首先想到的框架就是多路復用,想到多路復用,Unix/Linux下馬上就能讓從想到select,
          poll,
          epoll系統調用。于是,在看到Java的NIO中的Selector類時必然會倍感親切。稍加查閱一下SDK手冊以及相關例程,不一會兒,一個多路復用的框架便呈現出來,隨手做個單元測試,沒啥問題,一切和C/C++照舊。然后告訴兄弟們,框架搞定,以后咱們就在Windows上開發及單元測試,完成后到運行環境Unix上集成測試。心中并暗自念到,跨平臺就好啊,開發活動都可以跨平臺了。

          然而,好景不長,隨著代碼越來越多,邏輯越來越復雜。好好的框架居然在Windows上單元測試運行開始出現異常,看著Java運行異常出錯的函數棧,異常居然由Selector.open()拋出,錯誤信息居然是Unable
          to establish loopback connection。

          “Selector.open()居然報loopback
          connection錯誤,憑什么?不應該啊?open的時候又沒有什么loopback的socket連接,怎么會報這個錯?”

          長期使用C/C++的程序當然會對操作系統的調用非常熟悉,雖然Java的虛擬機搞的什么系統調用都不見了,但C/C++的程序員必然要比Java程序敏感許多。

          三、 開始調查 : 怎么Java這么“傻”!

          于是,C/C++的老鳥從SystemInternals上下載Process Explorer來查看一下究竟是什么個Loopback Connection。
          果然,打開java運行進程,發現有一些自己連接自己的localhost的TCP/IP鏈接。于是另一個問題又出現了,“憑什么???為什么會有自己和自己的連接?我程序里沒有自己連接自己啊,怎么可能會有這樣的鏈接???而自己連接自己的端口號居然是些奇怪的端口。”

          問題變得越來越蹊蹺了。難道這都是Selector.open()在做怪?難道Selector.open()要創建一個自己連接自己的鏈接?寫個程序看看:

                                                           
          1. import java.nio.channels.Selector;
          2. import java.lang.RuntimeException;
          3. import java.lang.Thread;
          4. public class TestSelector {
          5. private static final int MAXSIZE=5;
          6. public static final void main( String argc[] ) {
          7. Selector [] sels = new Selector[ MAXSIZE];
          8. try{
          9. for( int i = 0 ;i< MAXSIZE ;++i ) {
          10. sels[i] = Selector.open();
          11. //sels[i].close();
          12. }
          13. Thread.sleep(30000);
          14. }catch( Exception ex ){
          15. throw new RuntimeException( ex );
          16. }
          17. }
          18. }
           

          這個程序什么也沒有,就是做5次Selector.open(),然后休息30秒,以便我使用Process
          Explorer工具來查看進程。程序編譯沒有問題,運行起來,在Process
          Explorer中看到下面的對話框:(居然有10個連接,從連接端口我們可以知道,互相連接, 如:第一個連第二個,第二個又連第一個)

          不由得贊嘆我們的Java啊,先不說這是不是一件愚蠢的事。至少可以肯定的是,Java在消耗寶貴的系統資源方面,已經可以趕的上某些蠕蟲病毒了。

          如果不信,不妨把上面程序中的那個MAXSIZE的值改成65535試試,不一會你就會發現你的程序有這樣的錯誤了:(在我的XP機器上大約運行到2000個Selector.open()
          左右)

          Exception in thread "main" java.lang.RuntimeException: java.io.IOException: Unable to establish loopback connection at Test.main(Test.java:18) Caused by: java.io.IOException: Unable to establish loopback connection at sun.nio.ch.PipeImpl$Initializer.run(Unknown Source) at java.security.AccessController.doPrivileged(Native Method) at sun.nio.ch.PipeImpl.(Unknown Source) at sun.nio.ch.SelectorProviderImpl.openPipe(Unknown Source) at java.nio.channels.Pipe.open(Unknown Source) at sun.nio.ch.WindowsSelectorImpl.(Unknown Source) at sun.nio.ch.WindowsSelectorProvider.openSelector(Unknown Source) at java.nio.channels.Selector.open(Unknown Source) at Test.main(Test.java:15) Caused by: java.net.SocketException: No buffer space available (maximum connections reached?): connect at sun.nio.ch.Net.connect(Native Method) at sun.nio.ch.SocketChannelImpl.connect(Unknown Source) at java.nio.channels.SocketChannel.open(Unknown Source) ... 9 more

          四、 繼續調查 : 如此跨平臺

          當然,沒人像我們這么變態寫出那么多的Selector.open(),但這正好可以讓我們來明白Java背著大家在干什么事。上面的那些“愚蠢連接”是在Windows平臺上,如果不出意外,Unix/Linux下應該也差不多吧。

          于是我們把上面的程序放在Linux下跑了跑。使用netstat
          命令,并沒有看到自己和自己的Socket連接。貌似在Linux上使用了和Windows不一樣的機制?!

          如果在Linux上不建自己和自己的TCP連接的話,那么文件描述符和端口都會被省下來了,是不是也就是說我們調用65535個Selector.open()的話,應該不會出現異常了。

          可惜,在實現運行過程序當中,還是一樣報錯:(大約在400個Selector.open()左右,還不如Windows)

          Exception in thread "main" java.lang.RuntimeException: java.io.IOException: Too many open files at Test1.main(Test1.java:19) Caused by: java.io.IOException: Too many open files at sun.nio.ch.IOUtil.initPipe(Native Method) at sun.nio.ch.EPollSelectorImpl.(EPollSelectorImpl.java:49) at sun.nio.ch.EPollSelectorProvider.openSelector(EPollSelectorProvider.java:18) at java.nio.channels.Selector.open(Selector.java:209) at Test1.main(Test1.java:15)

          我們發現,這個異常錯誤是“Too many open files”,于是我想到了使用lsof命令來查看一下打開的文件。

          看到了有一些pipe文件,一共5對,10個(當然,管道從來都是成對的)??梢?,Selector.open()在Linux下不用TCP連接,而是用pipe管道??磥?,這個pipe管道也是自己給自己的。所以,我們可以得出下面的結論:

          1)Windows下,Selector.open()會自己和自己建立兩條TCP鏈接。不但消耗了兩個TCP連接和端口,同時也消耗了文件描述符。

          2)Linux下,Selector.open()會自己和自己建兩條管道。同樣消耗了兩個系統的文件描述符。

          估計,在Windows下,Sun的JVM之所以選擇TCP連接,而不是Pipe,要么是因為性能的問題,要么是因為資源的問題。可能,Windows下的管道的性能要慢于TCP鏈接,也有可能是Windows下的管道所消耗的資源會比TCP鏈接多。這些實現的細節還有待于更為深層次的挖掘。

          但我們至少可以了解,原來Java的Selector在不同平臺上的機制。

          贊(0)
          分享到: 更多 (0)
          網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
          主站蜘蛛池模板: 亚洲午夜国产精品无码老牛影视| 亚洲精品自产拍在线观看| 四虎精品亚洲一区二区三区| 国产亚洲精品xxx| 一本久久精品一区二区| 成人国产精品秘 果冻传媒在线 | 亚洲精品午夜无码专区| 精品乱人伦一区二区三区| 亚洲av无码精品网站| 欧洲精品一区二区三区在线观看 | 久久夜色撩人精品国产小说| 91精品国产色综久久| 国产精品久久久久aaaa| 欧美精品久久久久久久自慰| 曰韩精品无码一区二区三区| 精品一久久香蕉国产线看播放 | 99免费精品视频| 精品国产乱码久久久久久郑州公司| 亚洲精品无码久久毛片| 日本精品视频在线观看| 国产精品自产拍在线观看花钱看| 日本精品一区二区三区在线观看| 97久久超碰国产精品旧版| 精品久久久久久无码中文字幕一区| 一本一本久久aa综合精品| 人妻无码久久精品| 亚洲精品国产高清不卡在线| 天天视频国产精品| 亚洲国产人成精品| 亚洲а∨天堂久久精品9966| 欧美精品整片300页| 日韩一区二区三区精品| 亚洲?V乱码久久精品蜜桃| 青春草无码精品视频在线观 | 影视网欧洲精品| 91精品国产福利在线观看麻豆| 国内精品久久久久久野外| 中文字幕精品一区二区日本| 99久久伊人精品综合观看| 国产久爱免费精品视频 | 亚洲精品线在线观看|