在 Java 網路程式設計中,Socket 類的諸多方法在聲明時都拋出 IOException 或其子類異常。掌握這些異常的繼承體系與觸發場景,是編寫健壯網路應用的關鍵。本文將系統梳理 Socket 相關異常,幫助開發者精準捕獲、處理網路錯誤。
所有 Socket 方法拋出的異常最終都繼承自 IOException。其中 SocketException 是最常見的基類,代表各類網路層面的錯誤。若需針對具體錯誤類型處理,則需捕獲更細粒度的子類異常。繼承關係如下:
IOException — 所有 Socket 異常的根父類,捕獲它可統一處理所有 I/O 錯誤。SocketException extends IOException — 最頻繁出現的網路異常基類。ConnectException extends SocketException — 連接被拒或超時(如服務端未監聽、端口未開放)。BindException extends SocketException — 端口綁定衝突(同一端口被多個 Socket 佔用且未啟用 SO_REUSEADDR)。NoRouteToHostException extends SocketException — 防火牆攔截或路由不可達。UnknownHostException extends IOException — 域名解析失敗(DNS 無法解析主機名)。ProtocolException extends IOException — TCP/IP 協議層面錯誤(數據包損壞)。SocketTimeoutException extends InterruptedIOException — 連接或讀取超時(connect()、read() 超過設定時限)。當嘗試連接的服務端未啟動、端口未監聽或防火牆阻擋時拋出:
Socket socket = new Socket("www.example.com", 1234); // 若 1234 端口無服務,拋出 ConnectException
多個 Socket 嘗試綁定同一本地端口且未設 SO_REUSEADDR:
Socket socket1 = new Socket();
Socket socket2 = new Socket();
socket1.bind(new InetSocketAddress("127.0.0.1", 1234));
socket2.bind(new InetSocketAddress("127.0.0.1", 1234)); // 第二次綁定拋出 BindException
傳入的主機名不存在或 DNS 故障:
Socket socket = new Socket("invalid.domain.xyz", 80); // 拋出 UnknownHostException
透過 setSoTimeout(ms) 設定讀取超時;connect(address, timeout) 設定連接超時。超時發生時拋出此異常,流未關閉,可重試:
Socket socket = new Socket();
socket.setSoTimeout(5000); // 5 秒讀取超時
socket.connect(new InetSocketAddress("host", 80), 3000); // 3 秒連接超時
ConnectException、BindException 等),再捕獲 SocketException,最後捕獲 IOException。finally 塊或 try-with-resources 中關閉 Socket,避免洩漏。掌握這些異常特性,能讓你的網路程式在面對不穩定網路環境時更加穩健、可控。