Socket超時時間設置

你知道在 Java 中怎麼對 Socket 設置超時時間嗎?他們的區別是什麼?想想和女友打電話的場景就知道了,若是實在想不到,那咱們就一塊兒來看一下是咋回事吧。java

設置方式

主要有如下兩種方式網絡

方式1:socket

Socket socket = new Socket(); 
socket.connect(new InetSocketAddress(host,port),10000);
複製代碼

方式2:測試

Socket socket = new Socket("127.0.0.1",8080);
socket.setSoTimeout(10000);
複製代碼

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

實際測試

第1種方式.net

咱們先來看一下第一種方式,咱們來測試一下:在main方法中咱們建立 Socket 鏈接到 ip :29.212.19.201,端口:2132code

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秒後打印以下信息:ip

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 鏈接超時的異常。get

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

另外,在不設置鏈接超時時間的狀況下,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);//休眠10秒
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);//超時時間,10秒
複製代碼

運行後,等待客戶端輸出,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)
10002
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秒後說不說話她都聽不到了,你就悲催了。

【END】

封圖來源於網絡,侵權聯繫刪除。

相關文章
相關標籤/搜索