神奇好望角 The Magical Cape of Good Hope

          庸人不必自擾,智者何需千慮?
          posts - 26, comments - 50, trackbacks - 0, articles - 11
            BlogJava :: 首頁(yè) ::  :: 聯(lián)系 :: 聚合  :: 管理

          ServerSocket 類(lèi)和 Socket 類(lèi)都提供了多個(gè)公共構(gòu)造方法。不同的構(gòu)造方法不僅帶的參數(shù)不同,所具有的意義也不一樣。下面分別解析這兩個(gè)類(lèi)的實(shí)例初始化過(guò)程。

          ServerSocket 實(shí)例的初始化

          ServerSocket 類(lèi)提供了四個(gè)構(gòu)造器:

          public ServerSocket(int port) throws IOException
          public ServerSocket(int port, int backlog) throws IOException
          public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException
          public ServerSocket() throws IOException

          帶參構(gòu)造器用來(lái)創(chuàng)建已綁定的服務(wù)器套接字,也就是說(shuō)構(gòu)造成功后它就已經(jīng)開(kāi)始偵聽(tīng)指定的端口,且能夠調(diào)用 accept() 方法來(lái)接受客戶端連接。默認(rèn)構(gòu)造器則會(huì)創(chuàng)建未綁定的服務(wù)器套接字,構(gòu)造成功后必須手動(dòng)將其綁定到一個(gè)本地地址才能用,在綁定之前可以進(jìn)行一些選項(xiàng)配置。

          帶參構(gòu)造器

          總的來(lái)說(shuō),帶參構(gòu)造器提供了三個(gè)參數(shù):

          port
          指定該服務(wù)器套接字所要偵聽(tīng)的本地端口。如果為 0,則由系統(tǒng)自動(dòng)分配一個(gè)端口號(hào),這必須以另外的方式讓客戶端獲取端口號(hào)。
          backlog
          這個(gè)名詞目前還沒(méi)有合適的譯名。底層系統(tǒng)的 TCP 實(shí)現(xiàn)會(huì)維護(hù)一個(gè)連接隊(duì)列,該隊(duì)列緩存了已被 TCP 處理完畢,但還沒(méi)有被服務(wù)器套接字接受的客戶端連接。一旦某個(gè)連接被接受(通過(guò)調(diào)用 accept() 方法),它就會(huì)被從隊(duì)列中移除。backlog 參數(shù)就用于指定隊(duì)列的最大長(zhǎng)度,默認(rèn)值為 50,但這個(gè)值只是一個(gè)建議,底層系統(tǒng)可能根據(jù)需要自動(dòng)調(diào)整。如果隊(duì)列滿了,則其行為是平臺(tái)相關(guān)的:微軟的 WINSOCK 會(huì)拒絕新的連接,其他實(shí)現(xiàn)則什么都不做。嚴(yán)格地說(shuō),微軟沒(méi)有遵守規(guī)范,破壞了游戲規(guī)則……
          bindAddr
          一臺(tái)機(jī)器可能會(huì)有多個(gè)本地 IP 地址,例如同時(shí)使用多塊網(wǎng)卡。使用其他兩個(gè)帶參構(gòu)造器時(shí),該參數(shù)為 null,服務(wù)器套接字會(huì)在所有的本地 IP 地址(0.0.0.0::0)上偵聽(tīng)。如果希望只偵聽(tīng)一個(gè)地址,則可使用該參數(shù)。

          默認(rèn)構(gòu)造器

          如果使用默認(rèn)構(gòu)造器,在綁定地址前,還可以做些配置。綁定操作由兩個(gè) bind 方法定義,參數(shù)類(lèi)似于帶參構(gòu)造器。配置項(xiàng)包括以下方面(都必須在綁定前配置):

          設(shè)置是否重用本地地址
          該選項(xiàng)由 setReuseAddress(boolean on) 方法配置,對(duì)應(yīng)底層系統(tǒng)的 SO_REUSEADDR 套接字選項(xiàng)。JDK 沒(méi)有定義該選項(xiàng)的默認(rèn)值。如果該選項(xiàng)為 false,則在關(guān)閉 TCP 連接時(shí),為了保證可靠性,該連接可能在關(guān)閉后的一段時(shí)間(大約兩分鐘)內(nèi)保持超時(shí)狀態(tài)(通常稱(chēng)為 TIME_WAIT 狀態(tài)或 2MSL 等待狀態(tài)),這段時(shí)間里無(wú)法將新建的服務(wù)器套接字綁定到同一個(gè)地址。在開(kāi)發(fā)階段,服務(wù)器可能不斷重啟,打開(kāi)改選項(xiàng)會(huì)非常有用。
          設(shè)置接收緩沖區(qū)大小
          該選項(xiàng)由 setReceiveBufferSize(int size) 方法配置,對(duì)應(yīng)底層系統(tǒng)的 SO_RCVBUF 套接字選項(xiàng),單位是字節(jié)。《RFC 1323 - TCP Extensions for High Performance》將緩沖區(qū)大小定義為 64KB。該選項(xiàng)只是一個(gè)建議值,底層系統(tǒng)可能根據(jù)需要自行調(diào)整。
          設(shè)置超時(shí)值
          該選項(xiàng)由 setSoTimeout(int timeout) 方法配置,對(duì)應(yīng)底層系統(tǒng)的 SO_TIMEOUT 套接字選項(xiàng),單位是毫秒。默認(rèn)值為 0。該選項(xiàng)影響 accept 方法的阻塞時(shí)間長(zhǎng)度,如果超時(shí)將引發(fā) SocketTimeoutException。如果設(shè)為 0,則表示永不超時(shí)。
          設(shè)置性能首選項(xiàng)
          性能首選項(xiàng)包括連接時(shí)間、延遲和帶寬三個(gè)選項(xiàng),由 setPerformancePreferences(int connectionTime, int latency, int bandwidth) 方法配置。這三個(gè)數(shù)值分別表示短連接時(shí)間、低延遲和高帶寬的相對(duì)重要性,數(shù)值越大則越重要;其各自的絕對(duì)值沒(méi)有意義。該方法的初衷是為了讓 Java 能在用非 TCP/IP 實(shí)現(xiàn)的套接字環(huán)境下工作得更好,某些需要對(duì)網(wǎng)絡(luò)進(jìn)行調(diào)優(yōu)的程序也可以將這三個(gè)首選項(xiàng)作為配置參數(shù)提供給用戶。

          Socket 實(shí)例的初始化

          Socket 類(lèi)提供了六個(gè)公共構(gòu)造器(已過(guò)時(shí)的除外):

          public Socket(String host, int port) throws UnknownHostException, IOException
          public Socket(InetAddress address, int port) throws IOException
          public Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException
          public Socket(InetAddress address, int port, InetAddress localAddr, int localPort) throws IOException
          public Socket()
          public Socket(Proxy proxy)

          前四個(gè)構(gòu)造器創(chuàng)建已連接的客戶端套接字,也就是說(shuō)構(gòu)造的時(shí)候就會(huì)去連接服務(wù)器。前兩個(gè)構(gòu)造器需要提供服務(wù)器的地址和端口作為參數(shù),本地地址和端口由系統(tǒng)自動(dòng)分配;后兩個(gè)允許手動(dòng)指定本地地址和端口,但極少使用。后兩個(gè)構(gòu)造器創(chuàng)建未連接的套接字,創(chuàng)建后需要調(diào)用 connect 方法手動(dòng)連接,連接之前可以做一些配置。最后一個(gè)構(gòu)造器接受一個(gè)代表代理服務(wù)其的 Proxy 對(duì)象,JDK 支持 HTTP 和 SOCKS(V4 或 V5)兩種代理類(lèi)型。

          連接前的配置

          在連接前,客戶端套接字不僅像服務(wù)器套接字那樣可以設(shè)置是否重用本地地址、緩沖區(qū)大小、超時(shí)值和性能首選項(xiàng),還能夠配置以下各項(xiàng)(都必須在連接前配置):

          設(shè)置是否保持活躍
          該選項(xiàng)由 setKeepAlive(boolean on) 方法配置,對(duì)應(yīng)底層系統(tǒng)的 SO_KEEPALIVE 套接字選項(xiàng)。默認(rèn)值為 false。如果打開(kāi)該選項(xiàng),則套接字會(huì)定期自動(dòng)發(fā)送保持活躍的探測(cè)性消息,類(lèi)似于心跳檢測(cè)。根據(jù)《RFC 1122 - Requirements for Internet Hosts》的規(guī)定,保持活躍機(jī)制只是 TCP 的一個(gè)可選功能,如果支持的話,默認(rèn)必須為 false,而且這種機(jī)制默認(rèn)在成功建立連接后,且連續(xù)兩小時(shí)沒(méi)有數(shù)據(jù)傳輸?shù)那闆r下才會(huì)被激活。從另一方面來(lái)看,通過(guò)套接字的 I/O 操作完全可以知道連接是否還有效,所以該選項(xiàng)的實(shí)用價(jià)值不大。
          設(shè)置是否收發(fā)帶外數(shù)據(jù)
          該選項(xiàng)由 setOOBInline(boolean on) 方法配置,對(duì)應(yīng)底層系統(tǒng)的 SO_OOBINLINE 套接字選項(xiàng)。默認(rèn)值為 off。帶外數(shù)據(jù)(Out-of-band Data)也叫做緊急數(shù)據(jù),表示數(shù)據(jù)很重要,需要使用不同于發(fā)送普通數(shù)據(jù)的一個(gè)專(zhuān)用通道來(lái)發(fā)送。打開(kāi)該選項(xiàng)后,就可以調(diào)用 sendUrgentData(int data) 方法發(fā)送一個(gè)字節(jié)的緊急數(shù)據(jù)。JDK 對(duì)帶外數(shù)據(jù)只提供了有限支持,緊急數(shù)據(jù)將會(huì)和普通數(shù)據(jù)一起被收到,并且無(wú)法自動(dòng)區(qū)分。該選項(xiàng)對(duì)應(yīng)用開(kāi)發(fā)人員意義不大。
          設(shè)置是否從容關(guān)閉連接
          該選項(xiàng)由 setSoLinger(boolean on, int linger) 方法配置,對(duì)應(yīng)底層系統(tǒng)的 SO_LINGER 套接字選項(xiàng)。默認(rèn)為 false。該選項(xiàng)只會(huì)影響套接字的關(guān)閉,其中的 linger 參數(shù)表示超時(shí)時(shí)間,單位為秒。如果打開(kāi)改選項(xiàng):如果將 linger 設(shè)為 0,則關(guān)閉套接字的時(shí)候,未發(fā)送的數(shù)據(jù)會(huì)被丟棄,且另一端會(huì)出現(xiàn)連接被同位體重置的異常;如果 linger 非 0,則關(guān)閉套接字的線程將被阻塞,直到數(shù)據(jù)全部發(fā)送或超時(shí),超時(shí)后的行為與底層系統(tǒng)相關(guān),JDK 無(wú)法控制。如果關(guān)閉該選項(xiàng),則套接字正常關(guān)閉,數(shù)據(jù)也會(huì)全部發(fā)送。由于底層實(shí)現(xiàn)的差異性,不提倡應(yīng)用開(kāi)發(fā)人員打開(kāi)該選項(xiàng)。
          設(shè)置是否延遲發(fā)送數(shù)據(jù)
          該選項(xiàng)由 setTcpNoDelay(boolean on) 方法配置,對(duì)應(yīng)底層系統(tǒng)的 TCP_NODELAY TCP 選項(xiàng)。默認(rèn)值為 off。打開(kāi)該選項(xiàng)將禁用 Nagle 算法,TCP 包會(huì)立即發(fā)送;關(guān)閉該選項(xiàng)則會(huì)啟用 Nagle 算法,多個(gè)較小的 TCP 包會(huì)被組合成一個(gè)大包一起發(fā)送,雖然發(fā)送延遲了,但有利于避免網(wǎng)絡(luò)擁塞。默認(rèn)為 false。該選項(xiàng)對(duì)實(shí)時(shí)性很強(qiáng)的程序可能有用,但一般的程序不需要關(guān)心。
          設(shè)置流量類(lèi)別
          該選項(xiàng)由 setTrafficClass(int tc) 方法配置,對(duì)應(yīng)底層系統(tǒng)的“流量類(lèi)別”套接字屬性。該選項(xiàng)用于向網(wǎng)絡(luò)(例如路由器)提示從該套接字發(fā)送的包需要獲取哪些服務(wù)類(lèi)型,對(duì)本地 TCP 協(xié)議棧沒(méi)有影響。IPv4 和 IPv6 分別定義了多個(gè)不同的值,例如 IPv4 將 0x08 定義為最大吞吐量,0x10 定義為最小延遲,等等。可以用或運(yùn)算將多個(gè)值合并為一個(gè)選項(xiàng)。該選項(xiàng)用來(lái)調(diào)整性能,需要根據(jù)實(shí)際情況設(shè)置。由于只是建議值,可能被網(wǎng)絡(luò)忽略。

          評(píng)論

          # re: Java 網(wǎng)絡(luò)編程從菜鳥(niǎo)到叫獸 3:套接字初始化詳解  回復(fù)  更多評(píng)論   

          2012-02-15 12:57 by Jacklondon Chen
          以下有錯(cuò)誤:
          ServerSocket 類(lèi)提供了四個(gè)構(gòu)造器:
          public Socket(String host, int port) throws UnknownHostException, IOException
          public Socket(InetAddress address, int port) throws IOException
          public Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException
          public Socket(InetAddress address, int port, InetAddress localAddr, int localPort) throws IOException
          public Socket()
          public Socket(Proxy proxy)
          這些構(gòu)造函數(shù)都不是 ServerSocket 的。另外,這里的數(shù)量也不對(duì),明明是六個(gè),怎么變成了四個(gè)?
          ----歡迎大家試用我們的單點(diǎn)登錄 http://zheguisoft.com

          # re: Java 網(wǎng)絡(luò)編程從菜鳥(niǎo)到叫獸 3:套接字初始化詳解  回復(fù)  更多評(píng)論   

          2012-02-16 15:34 by 蜀山兆孨龘
          @Jacklondon Chen
          復(fù)制粘貼搞出來(lái)的低級(jí)錯(cuò)誤……已更正,謝謝提醒!
          主站蜘蛛池模板: 稻城县| 兴海县| 景德镇市| 兰考县| 怀集县| 泰安市| 天气| 山东省| 舞钢市| 北海市| 平江县| 新宾| 桑日县| 漾濞| 达州市| 玉山县| 鄯善县| 五常市| 石柱| 南溪县| 离岛区| 黎川县| 山阳县| 洪泽县| 綦江县| 九台市| 鱼台县| 哈巴河县| 简阳市| 鸡泽县| 图们市| 莒南县| 孝感市| 宁南县| 临夏县| 乾安县| 太原市| 尤溪县| 延寿县| 观塘区| 定结县|