Java網絡學習筆記2:設置Socket選項

  1. Socket有如下幾個選項:java

TCP_NODELAY 表示當即發送數據。
SO_RESUSEADDR 表示是否容許重用Socket所綁定的本地地址。
SO_TIMEOUT 表示接受數據時的等待超時時間。
SO_LINGER 表示當執行Socket的close()方法時,是否當即關閉底層的Socket。
SO_SNFBUF 表示發送數據的緩衝區的大小。
SO_RCVBUF 表示接受數據的緩衝區的大小。
SO_KEEPALIVE 表示對於長時間處於空閒狀態的Socket,是否要自動把他關閉。
OOBINLINE 表示是否支持發送一個字節的TCP緊急數據。


    2.TCP_NODELAY選算法

//設置該選項:
public void setTcpNoDelay(boolean on) throws SocketException //底層實現不支持,則拋出異常。

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

    默認狀況下,發送數據採用Negale算法。Negale算法是指發送方發送的數據不會馬上發出,而是先放在緩衝區內,等待緩衝區滿了在發出。 發送完一批數據後,會等待接收方對這批數據的迴應,而後在發送下一批數據。(適用於發送方須要發送大批量數據,而且接收方會及時做出迴應的場合,而若是持續發送小批量數據,且接收方不必定會看當即發送響應數據,則使發送方會運行很慢。)數組

TCP_NODELAY的默認值爲false,表示使用Negale算法, 若 setTcpNoDelay(true)方法,就會關閉Socket的緩衝,讓數據及時發送。服務器

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


    3.SO_RESUSEADDR選項:網絡

//設置該選項:
public void setResuseAddress(boolean on) throws SocektException

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

    當接收方經過Socket的colse()方法關閉Socket時,若是網絡上還有發送到這個Socket的數據,那麼底層的Socket不會馬上釋放而本地端口,而是會等待一段時間,確保接收到了網絡上發送過來的延遲數據,而後再釋放端口。但接收到延遲數據後,不會對這些數據作任何處理,只是確保這些數據不會被其餘碰巧綁定到一樣端口的新進程接收到。
socket

    而當服務器程序關閉後,有可能它的端口還會被佔用一段時間,若是此時馬上在同一個主機上重啓服務器程序,因爲端口已經被佔用,使得服務器程序沒法綁定到該端口,啓動失敗。url

    爲使同一個主機上的其餘進程還能夠馬上重用該端口,能夠調用Socket的setReuseAddress(true);spa

if( !socket.getReuseAddress() ){
    socket.setReuseAddress(true);
}

    但值得注意的是 socket.setReuseAddress(true)方法必須在Socket尚未綁定到一個本地端口以前調用,不然執行該方法就無效。所以必須按下方式建立Socket對象,在鏈接遠程服務器。.net

    Socket socket = new Socket(); //此時Socket對象未綁定本地端口,而且未鏈接遠程服務器
    socket.setReuseAddress(true);  // 會拋出SocketException
    // 若是不寫如下這句話,則客戶程序通常採用隨機端口,那麼救護綁定匿名的本地端口。
    SocketAddress localAddr = new InetSocketAddress("localhost",9999);  
    SocketAddress remoteAddr = new InetSocketAddress("remotehost",8888);
    socket.bind(localAddr);  //與本地端口綁定
    socket.connect(remoteAddr);  // 鏈接遠程服務器
    //兩個共用同一個端口的進程必須都調用該方法才能使得一個進程關閉Socket後,另外一個進程的Socket可以馬上重用相同的端口。

    

    4.SO_TIMEOUT選項:code

//設置該選項:
public void setSoTimeout(int timeout) throws SocketException
//讀取該選項:
public int getSoTimeOut() throws SocketException

    當經過Socket的輸入流讀數據時,若是尚未數據,就會等待。例如:

byte[] buff = new byte[1024];
InputStream in = socket.getInputStream();
in.read(buff);

    對於上述代碼,若是輸入流中沒有數據,in.read(buff)就會等待對方發送數據,知道知足如下狀況才結束等待:

    a.    輸入流中有1024個字節,read()方法吧這些字節讀入到buff中,在返回讀取的字節數。

    b.    當寂靜塊接近輸入流的末尾,距離末尾還有小於1024個字節時,read()方法會把這些字節讀入到buff中,在返回讀取的字節數。

    c.    已經讀到輸入流的末尾,正常結束,返回-1.

    d。 鏈接已經斷開,拋出IOException。

    e.    若是經過Socket的setSoTimeout()方法設置了等待超時時間,單位爲毫秒,超過該時間後就拋出SocketTimeoutException。 它的默認值爲0,表示會無限等待,永遠不會超時。

public class ReceiveServer {
	public static void main(String[] args) throws IOException,SocketException{
		ServerSocket server = new ServerSocket(9999);
		Socket s = server.accept();
		s.setSoTimeout(1000*20); //設置超時時間爲5秒
		InputStream in = s.getInputStream();
		ByteArrayOutputStream buffer = new ByteArrayOutputStream();
		byte[] buff = new byte[1024];
		int length = -1;
		do{
			try {
				length = in.read(buff);
				if( length != -1 ){
					buffer.write( buff,0,length );
				}
			} catch (SocketTimeoutException e) {
				//e.printStackTrace();
				System.out.println("等待超時...");
			}
		}while( length != -1 );
		System.out.println(   new String( buffer.toByteArray()) ); // 將字節數組轉換爲字符串
	}
}


////////////////////////

public class SendClient {
	public static void main(String[] args) throws Exception {
		Socket socket = new Socket("localhost",9999);
		OutputStream out = socket.getOutputStream();
		out.write( "Hello ".getBytes() );
		out.write("EveryOne".getBytes() );
		Thread.sleep(1000*60);
		socket.close();
		
	}

}


//下一篇是對本篇博文的稍做補充:設置Socket選項(補充)

相關文章
相關標籤/搜索