Java Socket 提供 6 個重載構造方法與 2 個 connect() 重載,支援自動選擇本地 IP、手動綁定本地 IP、超時控制等多樣化連接策略。本文系統歸類並對比各種方式的適用場景。
多網卡/多 IP 機器上,系統自動選擇可達目標的出口 IP。
| 構造方法 | 參數 | 異常 | 說明 |
|---|---|---|---|
Socket(String host, int port) | 域名/IP + 端口 | UnknownHostException, IOException | 最常用,域名會自動 DNS 解析 |
Socket(InetAddress addr, int port) | InetAddress + 端口 | IOException | 預解析 InetAddress,重複連接同一主機效率更高 |
Socket(String host, int port, boolean stream) | + boolean stream | UnknownHostException, IOException | @Deprecated stream=false 曾用於 UDP,現棄用 |
Socket(InetAddress addr, int port, boolean flag) | + boolean flag | IOException | @Deprecated 同上,不建議使用 |
需指定本地 InetAddress 與本地端口(0 表示系統自動分配)。
| 構造方法 | 參數 | 適用場景 |
|---|---|---|
Socket(String host, int port, InetAddress localAddr, int localPort) | 目標 host/port + 本地 IP/port | 多網卡指定出口 IP,或需固定本地端口 |
Socket(InetAddress addr, int port, InetAddress localAddr, int localPort) | 目標 InetAddress + 本地 IP/port | 同上,目標預解析為 InetAddress |
// 假設本機有兩個 IP:200.200.200.200 (連接內網 Server) 和 192.168.18.252 (連接 Internet 經由網關 192.168.18.254)
InetAddress lanIp = InetAddress.getByName("200.200.200.200");
InetAddress wanIp = InetAddress.getByName("192.168.18.252");
// 連接內網服務 200.200.200.4:80 必須用 lanIp
new Socket("200.200.200.4", 80, lanIp, 0).connect(); // 成功
// 連接 Internet www.example.com:80 必須用 wanIp (與網關同網段)
new Socket("www.example.com", 80, wanIp, 0).connect(); // 成功
// 錯誤示範:用 lanIp 連 Internet -> 找不到路由 -> Connection timed out
new Socket("www.example.com", 80, lanIp, 0).connect(); // 失敗
先 new Socket() 創建未連接對象,再調用 connect(),支援綁定本地地址與超時控制。
Socket socket = new Socket();
socket.connect(new InetSocketAddress("host", 80));
Socket socket = new Socket();
socket.bind(new InetSocketAddress("192.168.1.100", 0)); // 先綁定本地 IP
socket.connect(new InetSocketAddress("host", 80), 2000); // 2秒連接超時
Socket s1 = new Socket();
s1.connect(new InetSocketAddress("200.200.200.4", 80)); // 自動選 IP 連接
Socket s2 = new Socket();
s2.bind(new InetSocketAddress("200.200.200.200", 0)); // 綁定特定本地 IP
s2.connect(new InetSocketAddress("200.200.200.4", 80));
Socket s3 = new Socket();
s3.bind(new InetSocketAddress("192.168.18.252", 0));
s3.connect(new InetSocketAddress("200.200.200.4", 80), 2000); // 超時 2秒,快速失敗
| 場景 | 推薦方式 | 理由 |
|---|---|---|
| 簡單客戶端,單網卡 | new Socket(host, port) | 最簡潔,自動處理 DNS 與路由 |
| 高頻連接同一主機 | InetAddress addr = ...; new Socket(addr, port) | 避免重複 DNS 解析 |
| 多網卡指定出口 IP | 構造方法帶 localAddr 或 bind() + connect() | 精確控制源 IP |
| 需連接超時控制 | connect(address, timeout) | 構造方法無超時參數 |
| 連接前需設置 Socket 選項 | new Socket() -> setOption -> connect() | 構造方法直連無法預先設置選項 |
| 非阻塞連接 (NIO) | SocketChannel.open() -> connect() | 屬於 NIO 範疇,非本文範圍 |
boolean stream 參數的構造方法已 @Deprecated,嚴禁在新代碼使用。localPort=0 讓系統自動分配(1024~65535),避免衝突。bind() 必須在 connect() 前調用,且只能調用一次。try-catch 或拋出 IOException。靈活掌握這些連接方式,能讓你的網路客戶端適應從簡單單機到複雜多網卡、高可用、低延遲的各種部署拓撲。