分析下載HTML頁面出錯(cuò)!!

          Posted on 2007-11-09 01:49 dybjsun 閱讀(1445) 評論(1)  編輯  收藏 所屬分類: 技術(shù)隨筆

          ????? 今天運(yùn)行了寫好的程序,出現(xiàn)了錯(cuò)誤。java.net.BindException: Address in use: connect。查找網(wǎng)上資源,說主要原因是因?yàn)檫B接太多,socket綁定端口在短時(shí)間內(nèi)不能釋放。


          java.net.ConnectException: Address already in use
          ???????? at java.net.PlainSocketImpl.socketConnect(Native Method)
          ???????? at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:305)
          ???????? at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:171)
          ???????? at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:158)
          ???????? at java.net.Socket.connect(Socket.java:426)
          ???????? at com.nec.adams.app.mp.ups.Session.setup(Session.java:383)
          ???????? at com.nec.adams.app.mp.ups.StateActive.run(StateActive.java:197)
          ???????? at com.nec.adams.app.mp.ups.UPSServer.runService(UPSServer.java:248)
          ???????? at com.nec.adams.app.mp.ups.UPSServer.main(UPSServer.java:155)


          程序的流程如下:

          ?????? socket = new Socket();
          ?????? socket.setReuseAddress(true);
          ?????? socket.bind(new InetSocketAddress(127.0.0.1, 19760));
          ?????? socket.connect(new InetSocketAddress(192.168.0.5, 5111), 1000);


          ??????? 最開始的時(shí)候,沒有使用"socket.setReuseAddress(true);"這句,出現(xiàn)的是 "java.net.BindException: Address already in use"。仔細(xì)分析,引來對socket的bind和connect的調(diào)查。


          ??????? 普通情況下的socket關(guān)閉,兩個(gè)連接端點(diǎn)都需要發(fā)送FIN (final) 包,并且兩個(gè)端點(diǎn)都應(yīng)該回應(yīng)ACK (acknowledge)對方的FIN包,然后socket關(guān)閉完成。FIN包由應(yīng)用程序的close(),shutdown(),exit()這些發(fā) 起,而ACK包在close()完成后由系統(tǒng)內(nèi)核發(fā)送。

          ???????

          ??????? 上圖顯示了所有可能的正常關(guān)閉情況,根據(jù)事情發(fā)生的不同順序。注意到如果你發(fā)起關(guān)閉,另一端會出現(xiàn)一個(gè)“TIME_WAIT"的狀態(tài)。” TIME_OUT"狀態(tài)在這個(gè)過程完成后會幫定這個(gè)port幾分鈡。具體timeout的時(shí)間根據(jù)不同的操作系統(tǒng)而定。不過典型的時(shí)間是1到4分鐘。


          ??????? 為了避免綁定失敗,可以使用setReuseAddress(true)方法,這樣系統(tǒng)允許一個(gè)進(jìn)程綁定哪怕是處在TIME_WAIT狀態(tài)的端口。這是最簡單有效的消除“Address already in use"錯(cuò)誤的方法。


          ??????? 奇怪的是,這樣又帶來更復(fù)雜的問題。setReuseAddress(true)允許你用一個(gè)正在TIME_WAIT的端口,但是你仍然不能與上次你連接 的地址建立連接。什麼?假設(shè)我選擇了端口1010,去連接foobar.com的端口300,然后在本地關(guān)閉,讓那個(gè)端口處在TIME_WAIT狀態(tài)。這 個(gè)時(shí)候我立刻可以用端口1010去連接除了foobar.com的端口300。在這個(gè)時(shí)候出現(xiàn)的就是 "java.net.ConnectException:Address already in use"。在這個(gè)時(shí)候使用setReuseAddress(true)是無效的,應(yīng)該避免。


          ??????? 有些人不喜歡使用setReuseAddress(true)的另外一個(gè)原因是它帶來一個(gè)安全問題。在一些操作系統(tǒng)上它允許不同的進(jìn)程同時(shí)使用相同的端口 區(qū)連接不同的地址。這是一個(gè)問題,因?yàn)榇蠖鄶?shù)的服務(wù)器綁定在這個(gè)端口上,但是它并沒有幫定到一個(gè)地址(這就是為什麼netstat的輸出會出現(xiàn) *.8080這種情況)。於是如果這個(gè)服務(wù)器綁定*.8080,另外一個(gè)惡意的用戶能夠幫定local-machine.8080,去竊聽你的連接的特定 信息。


          ??????? 通過上面的圖,可以看到TIME_WAIT可以被避免,如果遠(yuǎn)程端口發(fā)起關(guān)閉。如是服務(wù)器能避免這個(gè)問題,通過讓客戶端首先關(guān)閉連接。應(yīng)用層協(xié)議必須被設(shè) 計(jì)成客戶端知道什麼時(shí)候關(guān)閉連接。服務(wù)器端能完全地關(guān)閉,通過客戶端的回應(yīng)EOF。 但是,它仍然需要設(shè)置一個(gè)timeout,如果客戶端不正常斷開了網(wǎng)絡(luò)。在多數(shù)情況下在服務(wù)器關(guān)閉之前等上幾秒就足夠了。


          參考文章: http://hea-www.harvard.edu/~fine/Tech/addrinuse.html


          ??????? 在讀了W. Richard Stevens 的《TCP/IP Illustated》之后,才明白,為什么會有這個(gè)TIME_WAIT狀態(tài),和為什么等待的時(shí)間是大約4分鐘,而且各個(gè)系統(tǒng)不一樣。


          2MSL連接
          ??????? TIME_WAIT狀態(tài)也稱為2MSL等待狀態(tài)。每個(gè)TCP必須選擇一個(gè)報(bào)文段最大生存時(shí)間MSL(Maximun Segment Lifetime)。它是任何報(bào)文段被丟棄前在網(wǎng)絡(luò)的最長時(shí)間。RFC 793(Postel 1981c)指出MSL為2分鐘。然而,實(shí)現(xiàn)中的常用值是30秒,1分鐘,或2分鐘。


          ??????? 對一個(gè)具體實(shí)現(xiàn)所給定的MSL值,處理的原則是:當(dāng)TCP執(zhí)行一個(gè)主動關(guān)閉,并發(fā)回最后一個(gè)ACK,該連接必須在TIME_WAIT狀態(tài)停留的時(shí)間為2倍的MSL。這樣可讓TCP再次發(fā)送最后的ACK以防這個(gè)ACK丟失(另一端超時(shí)并重發(fā)最后的FIN)。


          ??????? 這種2MSL等待的另一個(gè)結(jié)果是這個(gè)TCP連接在2MSL等待期間,定義這個(gè)連接的Socket(客戶的IP地址和端口號,服務(wù)器的IP地址和端口號)不能再被使用。這個(gè)連接只能在2MSL結(jié)束后才能被使用。


          ??????? 遺憾的是,大多數(shù)的TCP實(shí)現(xiàn)(如柏克利版)強(qiáng)加了更為嚴(yán)格的限制。在2MSL等待期間,Socket中使用的本地端口在默認(rèn)情況下不能被再次使用。


          ??????? 某些實(shí)現(xiàn)和API提供了一種避開這個(gè)限制的方法。使用Socket API時(shí),可說明其中的SO_REUSEADDR選項(xiàng)。它可讓調(diào)用者對處于2MSL等待的本地端口進(jìn)行賦值,但我們將看到TCP原則上仍將避免使用處于2MSL連接中的端口。


          ??????? 一個(gè)Socket對(即包含本地IP地址、本地端口、遠(yuǎn)端IP地址、遠(yuǎn)端端口的4元組)在它處于2MSL等待時(shí),將不能再被使用。盡管許多具體的實(shí)現(xiàn)中允 許一個(gè)進(jìn)程重新使用仍處于2MSL等待的端口(通常是設(shè)置選項(xiàng)SO_REUSEADDR),但TCP不能允許一個(gè)新的連接建立在相同的Socket對上。


          評論

          # re: 分析下載HTML頁面出錯(cuò)!!  回復(fù)  更多評論   

          2007-12-02 12:11 by web
          在任務(wù)管理器中把相關(guān)的進(jìn)程關(guān)閉,然后在重新啟動tomcat
          主站蜘蛛池模板: 清河县| 丹寨县| 雷山县| 永福县| 申扎县| 合作市| 磴口县| 宣化县| 综艺| 乌兰察布市| 临邑县| 福泉市| 津南区| 双江| 岗巴县| 张家界市| 龙门县| 庆云县| 通河县| 同心县| 利川市| 汉寿县| 凌海市| 丹凤县| 法库县| 阳朔县| 收藏| 南乐县| 杂多县| 苏州市| 弋阳县| 华池县| 洪洞县| 江西省| 烟台市| 阳城县| 大城县| 旬邑县| 延津县| 樟树市| 凌海市|