套接字超時
設置超時
API:java.net.Socket 1.0
- void setSoTimeout(int timeout) 1.1
設置該套接字上讀請求的阻塞時間。如果超過了給定時間,則拋出一個 InterruptedIOException 異常。
setSoTimeout 的底層代碼:
getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
服務器超時
ServerSocket#accept 等待連接超時
public class TimeoutSocketServer {
public static void main(String[] args) {
long startTime = 0L;
try {
ServerSocket serverSocket = new ServerSocket(8080);
serverSocket.setSoTimeout(1000);
while (true) {
startTime = System.currentTimeMillis();
serverSocket.accept();
}
} catch (IOException e) {
long timeout = System.currentTimeMillis() - startTime;
System.out.println(timeout);
e.printStackTrace();
}
}
}
控制台輸出:
read 讀超時
public class TimeoutSocketServer {
public static void main(String[] args) throws IOException {
long readTime = 0L;
ServerSocket serverSocket = new ServerSocket(8080);
while (true) {
Socket socket = serverSocket.accept();
socket.setSoTimeout(1000);
if (socket != null) {
System.out.println("客戶端連接上了");
try {
InputStream inStream = socket.getInputStream();
byte[] bytes = new byte[1024];
readTime = System.currentTimeMillis();
while (inStream.read(bytes) != 0) {
System.out.println(Arrays.toString(bytes));
}
} catch (IOException e) {
long timeout = System.currentTimeMillis() - readTime;
System.out.println(timeout);
e.printStackTrace();
}
}
}
}
}
輸入命令 telnet 127.0.0.1 8080
啟動客戶端連接,但是不發送內容。
控制台輸出:
客戶端超時
Socket#connect連接超時
通過先構建一個無連接的套接字,然后再使用一個超時來進行連接的方法。
public class TimeoutClient {
public static void main(String[] args) {
Socket socket = new Socket();
long startTime = System.currentTimeMillis();
try {
socket.connect(new InetSocketAddress("127.0.0.1", 8080), 1000);
} catch (IOException e) {
long timeout = System.currentTimeMillis() - startTime;
System.out.println(timeout);
e.printStackTrace();
}
}
}
控制台輸出:
當然,我在這個實驗中,沒有啟動服務端,如果客戶端不設置 timeout 超時參數的話,連接代碼改為下面這段:
socket.connect(new InetSocketAddress("127.0.0.1", 8080));
此時的控制台輸出為服務端拒絕連接:
讀超時
服務端代碼
public class Server {
public static void main(String[] args) throws IOException {
long readTime = 0L;
ServerSocket serverSocket = new ServerSocket(8080);
Socket socket = serverSocket.accept();
System.out.println("客戶端連接上了");
System.in.read();
}
}
客戶端代碼
public class TimeoutClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket();
socket.setSoTimeout(3000);
socket.connect(new InetSocketAddress("127.0.0.1", 8080));
long startTime = 0;
try {
InputStream inStream = socket.getInputStream();
startTime = System.currentTimeMillis();
while (inStream.read() != 0) {
System.out.println("接收到了信息");
}
} catch (IOException e) {
long timeout = System.currentTimeMillis() - startTime;
System.out.println(timeout);
e.printStackTrace();
}
}
}
先啟動服務端,再啟動客戶端,控制台輸出結果如下:
總結
Socket#setSoTimeout 可以設置讀超時時長。如果超過了給定時間,則拋出一個 InterruptedIOException 異常。
ServerSocket#setTimeout 可以設置 ServerSocket#accept 的等待連接的超時時間,如果超過了給定時間,則拋出一個 InterruptedIOException 異常。
Socket#connect 有一個 timeout 參數,可以設置連接超時時長。
InterruptedIOException 時 SocketTimeoutException 的父類。