Socket超時時間設置


你知道在 Java 中怎么對 Socket 設置超時時間嗎?他們的區別是什么?想一想和女朋友打電話的場景就知道了,如果實在想不到,那我們就一起來來看一下是咋回事吧

設置方式

主要有以下兩種方式,我們來看一下

方式1:

Socket s=new Socket(); 
s.connect(new InetSocketAddress(host,port),10000);

 

方式2:

Socket s=new Socket("127.0.0.1",8080);
s.setSoTimeout(10000);

實際測試

那么這兩種方式設置的超時時間各自代表了什么意義呢?有什么區別呢?

第1種方式

我們先來看一下第一種方式,我們來測試一下:

在main方法中我們創建 Socket 連接到 

ip :29.212.19.201,端口:2132

public static void main(String[] args) {
    Socket socket = new Socket();
    SocketAddress endpoint = new InetSocketAddress("29.212.19.201", 2132);
    long timeMillis = System.currentTimeMillis();
    try {
      socket.connect(endpoint, 10000);
    } catch (IOException e) {
      e.printStackTrace();
    }
    System.out.println(System.currentTimeMillis()-timeMillis);
    System.out.println("end");
  }

 

運行這段代碼,控制台10秒之前沒有任何信息輸出,10秒后打印如下信息:

10002
java.net.SocketTimeoutException: connect timed out
  at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
  at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85)
  at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
  at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
  at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
  at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
  at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
  at java.net.Socket.connect(Socket.java:589)
  at com.wakling.cn.SocketSever.main(SocketSever.java:33)
end

 

可以看出,我們嘗試連接到29.212.19.201:2132時,

連接了10秒都沒有連接上,

於是就報了 java.net.SocketTimeoutException: connect timed out 的異常。

 

解釋一下,上述的 IP 是一個未知的 IP ,即我的 IP 在當前網絡環境中訪問不到這個 IP ,這樣我們的這個 Socket 才會去一直嘗試連接到此 IP 直到超時。如果 IP 是一個已知的 IP ,例如本地 127.0.0.1 加上一個未知的端口,那么此 Socket 連接會立馬報錯。

 

另外,在不設置連接超時時間的情況下,Socket 默認大概是21s(測試了3次都是21020毫秒)連接超時。如下是不設置連接超時時間的代碼:

Socket socket = new Socket("29.212.19.201", 2132);

 

第2種方式

然后我們來看一下第2種方式,這時候我們需要在我們本地寫一套 Socket 服務以及客戶端來模擬這個場景。

我們讓客戶端設置 setSoTimeout 為10s,在服務端代碼拿到客戶端請求信息后,休眠10s后再處理客戶端請求,返回響應。

我們來看一下效果,關鍵代碼如下:

//服務端
System.out.println("進入休眠,10s后醒來");
Thread.sleep(10000);
System.out.println("休眠結束");
//返回響應
OutputStream outputStream = socket.getOutputStream();// 獲取一個輸出流,向服務端發送信息
PrintWriter printWriter = new PrintWriter(outputStream);// 將輸出流包裝成打印流
printWriter.print("你好,服務端已接收到您的信息");
printWriter.flush();
​
//客戶端
Socket socket = new Socket("127.0.0.1",2132);
socket.setSoTimeout(10000);//read的超時時間

運行后,等待客戶端輸出,10s后客戶端控制台輸出信息如下:

java.net.SocketTimeoutException: Read timed out
  at java.net.SocketInputStream.socketRead0(Native Method)
  at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
  at java.net.SocketInputStream.read(SocketInputStream.java:171)
  at java.net.SocketInputStream.read(SocketInputStream.java:141)
  at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
  at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
  at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
  at java.io.InputStreamReader.read(InputStreamReader.java:184)
  at java.io.BufferedReader.fill(BufferedReader.java:161)
  at java.io.BufferedReader.readLine(BufferedReader.java:324)
  at java.io.BufferedReader.readLine(BufferedReader.java:389)
  at com.wakling.cn.SocketClient.main(SocketClient.java:36)
10020
end

這里10s后客戶端報錯 java.net.SocketTimeoutException: Read timed out 

查看客戶端控制台信息正常輸出,即使客戶端已報超時,服務端仍然繼續往下走,只是客戶端已經收不到服務端10s后發給自己的消息。

另外經測試發現,服務端休眠很久很久,如500s,在客戶端不設置 setSoTimeout 時,客戶端默認120s超時。
對於 setSoTimeout 方法官方給的解釋是這樣的,我不知道超時時間設置為0是否真的為無窮大超時,感興趣的可以試一下。

setSoTimeout 

public void setSoTimeout(int timeout) 

   throws SocketException啟用/禁用帶有指定超時值

   SO_TIMEOUT,以毫秒為單位。將此選項設為非零的超時值時,

      在與此 Socket 關聯的 InputStream 上調用 read() 將只阻塞此時間長度

      如果超過超時值,將引發 java.net.SocketTimeoutException,雖然 Socket 仍舊有效。

      選項必須在進入阻塞操作前被啟用才能生效。 

   超時值必須是 > 0 的數。超時值為 0 被解釋為無窮大超時值

參數:timeout - 指定的以毫秒為單位的超時值。 

拋出:SocketException - 如果底層協議出現錯誤,例如 TCP 錯誤。

從以下版本開始:JDK 1.1 

另請參見:getSoTimeout()

區別和意義

下面我們就來說一說二者的意義和區別。

 

方式1是客戶端與服務端進行連接的超時時間,即10秒內建立不了連接就報 java.net.SocketTimeoutException: connect timed out 連接超時的異常.此時二者未建立連接,更別說服務端收到客戶端的消息了

 

方式2是設置 inputStream.read() 方法的阻塞時間,即客戶端發出請求后等待服務端返回響應的等待時長,超過這個時長將會引發 java.net.SocketTimeoutException: Read timed out 讀取超時的異常。此時二者正常建立連接,服務端接收到了客戶端的請求。

 

合理設置超時時間對增加程序的吞吐量和加強程序的健壯性有較為重大的意義。

 

兩種方式控制超時的側重點不同,就像女朋友給你打電話一樣,她是有小脾氣的。如果她按方法1對待你,那就是撥出去電話10秒內你不接電話她就掛了,如果她按方法2,那就是打電話接通后,假如你正在忙她就等你10秒,10秒內不說話就掛,10秒后說不說話她都聽不到了,你就悲催了。

 轉載請注明出處


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM