閱讀243 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Socket用法詳解

一、構造Socket

Socket的構造方法有以下幾種重載形式:

(1)Socket()

(2)Socket(InetAddress address, int port)throws UnknownHostException,IOException

(3)Socket(InetAddress address, int port, InetAddress localAddr, int localPort)throws IOException

(4)Socket(String host, int port) throws UnknownHostException,IOException

(5)Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException

各構造方法的用法如下:

1. 設定等待建立連接的超時時間:

Socket socket=new Socket();

SocketAddress remoteAddr=new InetSocketAddress("localhost",8000);

//等待建立連接的超時時間為1分鍾

socket.connect(remoteAddr, 60000);

2. 設定服務器的地址:

Socket(InetAddress address, int port)

Socket(String host, int port)

InetAddress類表示IP地址,其用法如下:

//返回本地主機的IP地址

InetAddress addr1=InetAddress.getLocalHost();

//返回代表"222.34.5.7"的IP地址

InetAddress addr2=InetAddress.getByName("222.34.5.7");

//返回域名為"www.javathinker.org"的IP地址

InetAddress addr3=InetAddress.getByName("www.javathinker.org");

3. 設定客戶端的地址:

在一個Socket對象中,既包含遠程服務器的IP地址和端口信息,也包含本地客戶端的IP地址和端口信息。默認情況下,客戶端的IP地址來自於客戶程序所在的主機,客戶端的端口則由操作係統隨機分配。Socket類還有兩個構造方法允許顯式的設置客戶端的IP地址和端口:

Socket(InetAddress address, int port, InetAddress localAddr, int localPort)throws IOException

Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException

4. 客戶連接服務器時可能拋出的異常:

當Socket的構造方法請求連接服務器時,可能會拋出以下異常:

l UnknownHostException:如果無法識別主機的名字或IP地址,就會拋出這種異常。

l ConnectException:如果沒有服務器進程監聽指定的端口,或者服務器進程拒絕連接,就會拋出這種異常。

l SocketTimeoutException:如果等待連接超時,就會拋出這種異常。

l BindException:如果無法把Socket對象與指定的本地IP地址或端口綁定,就會拋出這種異常。

二、獲取Socket的信息

以下方法用於獲取Socket的有關信息:

l getInetAddress():獲得遠程服務器的IP地址。

l getPort():獲得遠程服務器的端口。

l getLocalAddress():獲得客戶本地的IP地址。

l getLocalPort():獲得客戶本地的端口。

l getInputStream():獲得輸入流。如果Socket還沒有連接,或者已經關閉,或者已經通過shutdownInput()方法關閉輸入流,那麼此方法會拋出IOException。

l getOutputStream():獲得輸出流。如果Socket還沒有連接,或者已經關閉,或者已經通過shutdownOutput()方法關閉輸出流,那麼此方法會拋出IOException。

三、關閉Socket

1. 當客戶與服務器的通信結束,應該及時關閉Socket,以釋放Socket占用的包括端口在內的各種資源。Socket的close()方法負責關閉Socket。推薦代碼如下:

Socket socket=null;

try{

socket=new Socket("www.javathinker.org",80);

//執行接收和發送數據的操作

}catch(IOException e){

e.printStackTrace();

}finally{

try{

if(socket!=null)socket.close();

}catch(IOException e){e.printStackTrace();}

}

2. Socket類提供了三個狀態測試方法:

l isClosed()

l isConnected()

l isBound()

3. 如果要判斷一個Socket對象當前是否處於連接狀態,可采用以下方式:

boolean isConnected=socket.isConnected() && !socket.isClosed();

四、半關閉Socket

1. 有的時候,可能僅僅希望關閉輸出流或輸入流之一。此時可以采用Socket類提供的半關閉方法:

l shutdownInput():關閉輸入流。

l shutdownOutput(): 關閉輸出流。

2. 先後調用Socket的shutdownInput()和shutdownOutput()方法,僅僅關閉了輸入流和輸出流,並不等價於調用Socket的close()方法。在通信結束後,仍然要調用Socket的close()方法,因為隻有該方法才會釋放Socket占用的資源,比如占用的本地端口等。

3. Socket類還提供了兩個狀態測試方法,用來判斷輸入流和輸出流是否關閉:

l public boolean isInputShutdown()

l public boolean isOutputShutdown()

五、設置Socket的選項

Socket有以下幾個選項:

n TCP_NODELAY:表示立即發送數據。

n SO_RESUSEADDR:表示是否允許重用Socket所綁定的本地地址。

n SO_TIMEOUT:表示接收數據時的等待超時時間。

n SO_LINGER:表示當執行Socket的close()方法時,是否立即關閉底層的Socket。

n SO_SNFBUF:表示發送數據的緩衝區的大小。

n SO_RCVBUF:表示接收數據的緩衝區的大小。

n SO_KEEPALIVE:表示對於長時間處於空閑狀態的Socket,是否要自動把它關閉。

n OOBINLINE:表示是否支持發送一個字節的TCP緊急數據。

1. TCP_NODELAY選項

1) 設置該選項:public void setTcpNoDelay(boolean on) throws SocketException

2) 讀取該選項:public boolean getTcpNoDelay() throws SocketException

3) TCP_NODEALY的默認值為false,表示采用Negale算法。如果調用setTcpNoDelay(true)方法,就會關閉Socket的緩衝,確保數據及時發送:

if(!socket.getTcpNoDelay()) socket.setTcpNoDelay(true);

4) 如果Socket的底層實現不支持TCP_NODELAY選項,那麼getTcpNoDelay()和setTcpNoDelay()方法會拋出SocketException。

2. SO_RESUSEADDR選項

1) 設置該選項:public void setResuseAddress(boolean on) throws SocketException

2) 讀取該選項:public boolean getResuseAddress() throws SocketException

3) 為了確保一個進程關閉了Socket後,即使它還沒釋放端口,同一個主機上的其他進程還可以立刻重用該端口,可以調用Socket的setResuseAddress(true)方法:

if(!socket.getResuseAddress()) socket.setResuseAddress(true);

4) 值得注意的是socket.setResuseAddress(true)方法必須在Socket還沒有綁定到一個本地端口之前調用,否則執行socket.setResuseAddress(true)方法無效。因此必須按照以下方式創建Socket對象,然後再連接遠程服務器:

Socket socket = new Socket(); //此時Socket對象未綁定到本地端口,並且未連接遠程服務器

socket.setResuseAddress(true);

SocketAddress remoteAddr = new InetSocketAddress("remotehost",8000);

socket.connect(remoteAddr); //連接遠程服務器,並且綁定匿名的本地端口

或者:

Socket socket = new Socket(); //此時Socket對象未綁定到本地端口,並且未連接遠程服務器

socket.setResuseAddress(true);

SocketAddress localAddr = new InetSocketAddress("localhost",9000);

SocketAddress remoteAddr = new InetSocketAddress("remotehost",8000);

socket.bind(localAddr); //與本地端口綁定

socket.connect(remoteAddr); //連接遠程服務器,並且綁定匿名的本地端口

3. SO_TIMEOUT選項

1) 設置該選項:public void setSoTimeout(int milliseconds) throws SocketException

2) 讀取該選項:public int getSoTimeOut() throws SocketException

3) 當通過Socket的輸入流讀數據時,如果還沒有數據,就會等待。Socket類的SO_TIMEOUT選項用於設定接收數據的等待超時時間,單位為毫秒,它的默認值為0,表示會無限等待,永遠不會超時。

4) Socket的setSoTimeout()方法必須在接收數據之前執行才有效。此外,當輸入流的read()方法拋出SocketTimeoutException後,Socket仍然是連接的,可以嚐試再次讀取數據。

4. SO_LINGER選項

1) 設置該選項:public void setSoLinger(boolean on, int seconds) throws SocketException

2) 讀取該選項:public int getSoLinger() throws SocketException

3) SO_LINGER選項用來控製Socket關閉時的行為。

l socket.setSoLinger(true,0):執行Socket的close()方法時,該方法也會立即返回,但底層的Socket也會立即關閉,所有未發送完的剩餘數據被丟棄。

l socket.setSoLinger(true,3600):執行Socket的close()方法時,該方法不會立即返回,而進入阻塞狀態,同時,底層的Socket會嚐試發送剩餘的數據。隻有滿足以下兩個條件之一,close()方法才返回:

n 底層的Socket已經發送完所有的剩餘數據。

n 盡管底層的Socket還沒有發送完所有的剩餘數據,但已經阻塞了3600秒。close()方法的阻塞時間超過3600秒,也會返回,剩餘未發送的數據被丟棄。

以上兩種情況內,當close()方法返回後,底層的Socket會被關閉,斷開連接。

4) setSoLinger(boolean on ,int second)方法中的seconds參數以秒為單位,而不是以毫秒為單位。

5. SO_RCVBUF選項

1) 設置該選項:public void setReceiveBufferSize(int size) throws SocketException

2) 讀取該選項:public int getReceiveBufferSize() throws SocketException

3) SO_RCVBUF表示Socket的用於輸入數據的緩衝區的大小。

4) 如果底層Socket不支持SO_RCVBUF選項,那麼setReceiveBufferSize()方法會拋出SocketException。

6. SO_SNDBUF選項

1) 設置該選項:public void setSendBufferSize(int size) throws SocketException

2) 讀取該選項:public int getSendBufferSize() throws SocketException

3) SO_SNDBUF表示Socket的用於輸出數據的緩衝區的大小。

4) 如果底層Socket不支持SO_SNDBUF選項,setSendBufferSize()方法會拋出SocketException。

7. SO_KEEPALIVE選項

1) 設置該選項:public void setKeepAlive(boolean on) throws SocketException

2) 讀取該選項:public int getKeepAlive() throws SocketException

3) 當SO_KEEPALIVE選項為true,表示底層的TCP實現會監視該連接是否有效。

4) SO_KEEPALIVE選項的默認值為false,表示TCP不會監視連接是否有效,不活動的客戶端可能會永久存在下去,而不會注意到服務器已經崩潰。

8. OOBINLINE選項

1) 設置該選項:public void setOOBInline(int size) throws SocketException

2) 讀取該選項:public int getOOBInline () throws SocketException

3) 當OOBINLINE為true時,表示支持發送一個字節的TCP緊急數據。Socket類的sendUrgentDate(int data)方法用於發送一個字節的TCP緊急數據。

4) OOBINLINE的默認值為false,在這種情況下,當接收方收到緊急數據時不作任何處理,直接將其丟棄。如果用戶希望發送緊急數據,應該把OOBINLINE設為true:socket.setOOBInline(true); 此時接收方會把接收到的緊急數據與普通數據放在同樣的隊列中。值得注意的是,除非使用一些更高層次的協議,否則接收方處理緊急數據的能力非常有限,當緊急數據到來時,接收方不會得到任何通知,因此接收方很難區分普通數據與緊急數據,隻好按照同樣的方式處理它們。

9. 服務類型選項

1) IP規定了四種服務類型,用來定性的描述服務的質量:

l 低成本:發送成本低。

l 高可靠性:保證把數據可靠的送達目的地。

l 最高吞吐量:一次可以接收或發送大批量的數據。

l 最小延遲:傳輸數據的速度快,把數據快速送達目的地。

2) 這四種服務類型還可以進行組合,例如,可以同時要求獲得高可靠性和最小延遲。Socket類中提供了設置和讀取服務類型的方法:

l 設置服務類型:public void setTrafficClass(int trafficClass) throws SocketException

l 讀取服務類型:public int getTrafficClass() throws SocketException

3) Socket類用四個整數表示服務類型:

l 低成本:0x02 (二進製的倒數第二位為1)

l 高可靠性:0x04(二進製的倒數第三位為1)

l 最高吞吐量:0x08(二進製的倒數第四位為1)

l 最小延遲:0x10(二進製的倒數第五位為1)

10. 設定連接時間、延遲和帶寬的相對重要性

public void setPerformancePreferences(int connectionTime,int latency,int bandwidth)

以上方法的三個參數表示網絡傳輸數據的三項指標:

n 參數connectionTime:表示用最少時間建立連接。

n 參數latency:表示最小延遲。

n 參數bandwidth:表示最高帶寬。

setPerformancePreferences()方法用來設定這三項指標之間的相對重要性。可以為這些參數賦予任意的整數,這些整數之間的相對大小就決定了相應參數的相對重要性。例如,如果參數connectionTime為2,參數latency為1,而參數bandwidth為3,就表示最高帶寬最重要,其次是最少連接時間,最後是最小延遲。

最後更新:2017-04-03 16:49:03

  上一篇:go Android雙向滑動菜單 實現雙向滑動特效
  下一篇:go 關於在android源碼編譯時引用第三方jar寶--需要在android.mk中配置