首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 網路程式設計入門:InetAddress、Socket 基礎與 TCP 連線建立流程

     編輯:Java 相關知識

網路通訊基石:Socket 抽象

Socket 是兩個程序通訊連線的端點抽象。程式寫入 Socket → 網路協議棧封裝 → NIC 發送 → 對方 NIC 接收 → 協議棧解封 → 對方 Socket 讀取。核心三要素:

  1. IP 位址:識別主機 (IPv4 32-bit, IPv6 128-bit)。
  2. 埠號:識別進程 (0-65535,<1024 保留給系統服務)。
  3. 協議:TCP (可靠串流) 或 UDP (不可靠資料包)。

InetAddress:IP 位址封裝與解析

工廠方法建立實例 (無 public 建構子)

方法用途異常
getByName(String host)主機名/域名 → IP (單一結果)UnknownHostException
getAllByName(String host)域名 → 所有 IP 陣列 (負載平衡/輪詢)UnknownHostException
getLocalHost()本機 IP (可能回傳 127.0.0.1 需謹慎)UnknownHostException
getByAddress(byte[] addr)原始位元組陣列 → InetAddress (IPv4=4 bytes, IPv6=16 bytes)UnknownHostException

常用查詢方法

InetAddress ia = InetAddress.getByName("www.example.com");
System.out.println("Canonical Host: " + ia.getCanonicalHostName()); // DNS 規範名
System.out.println("IP Address: " + ia.getHostAddress());          // 數值 IP (如 93.184.216.34)
System.out.println("Host Name: " + ia.getHostName());              // 原查詢名或反解名
System.out.println("Is Loopback: " + ia.isLoopbackAddress());      // 127.0.0.1 / ::1
System.out.println("Is Multicast: " + ia.isMulticastAddress());    // 224.0.0.0/4
System.out.println("Is AnyLocal: " + ia.isAnyLocalAddress());      // 0.0.0.0 / ::
System.out.println("Address Bytes: " + Arrays.toString(ia.getAddress())); // 原始位元組

InetAddressDemo.java 完整範例

import java.net.*;

public class InetAddressDemo {
    public static void main(String[] args) {
        String host = (args.length > 0) ? args[0] : "localhost";
        try {
            InetAddress ia = InetAddress.getByName(host);
            System.out.println("=== " + host + " ===");
            System.out.println("Canonical: " + ia.getCanonicalHostName());
            System.out.println("IP: " + ia.getHostAddress());
            System.out.println("Host: " + ia.getHostName());
            System.out.println("Loopback: " + ia.isLoopbackAddress());
            System.out.println("Multicast: " + ia.isMulticastAddress());
            System.out.println("Reachable (5s): " + ia.isReachable(5000)); // ICMP Ping
        } catch (Exception e) {
            System.err.println("Error: " + e.getMessage());
        }
    }
}

TCP 連線建立完整流程 (三次交握視角)

Client                          Server
  |                                |
  |--- SYN (seq=x) --------------->|  ServerSocket.accept() 阻塞
  |                                |  內核建立半連線佇列
  |<-- SYN+ACK (seq=y, ack=x+1) ---|  內核回應
  |                                |
  |--- ACK (ack=y+1) ------------->|  連線建立完成
  |                                |  accept() 返回新 Socket (全連線佇列移出)
  |                                |
  |==== 數據傳輸階段 =============>|
  |                                |
  |--- FIN ----------------------->|  主動關閉
  |<-- ACK ------------------------|
  |<-- FIN ------------------------|  被動關閉
  |--- ACK ----------------------->|
  |                                |

Socket 與 ServerSocket 核心 API

Client 端:Socket

// 連線建立即發生三次交握,失敗拋 IOException
Socket socket = new Socket("www.example.com", 80); // 阻塞直到連線成功/超時/拒絕

// 進階:綁定本地 IP/埠 (多網卡/防火牆需求)
Socket socket = new Socket();
socket.bind(new InetSocketAddress("192.168.1.100", 0)); // 0=系統自動分配
socket.connect(new InetSocketAddress("www.example.com", 80), 5000); // 5秒連線超時

// 取得串流
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();

Server 端:ServerSocket

// 綁定監聽埠,backlog=50 (半連線佇列大小,Linux 預設 50/128)
ServerSocket server = new ServerSocket(8080, 50, InetAddress.getByName("0.0.0.0"));

// 核心迴圈
while (!shutdown) {
    try {
        Socket client = server.accept(); // 從全連線佇列取出已建立連線
        // 處理 client (新執行緒/執行緒池/NIO)
    } catch (SocketTimeoutException e) {
        // accept() 超時,檢查 shutdown 旗標
    }
}

常見連線失敗異常對照表

異常原因排查方向
ConnectException: Connection refused對方埠未監聽/防火牆拒絕netstat -an | grep PORT、telnet/ nc 測試、防火牆規則
ConnectException: Connection timed out封包丟失/防火牆靜默丟棄/路由不可達ping、traceroute、防火牆日誌、抓包分析
BindException: Address already in use埠被佔用/TIME_WAIT 狀態lsof -i:PORT、SO_REUSEADDR、等待 2MSL
UnknownHostExceptionDNS 解析失敗/etc/hosts、DNS 伺服器、拼寫錯誤

IPv6 相容性注意事項

  • Java 預設支援 IPv6,InetAddress.getByName 可能回傳 IPv6 位址 (Inet6Address)。
  • 雙棧環境下,ServerSocket(0) 綁定 :: 同時監聽 IPv4/IPv6 (取決於 java.net.preferIPv4Stack 系統屬性)。
  • 客戶端連線時,new Socket(host, port) 會嘗試所有解析到的位址 (Happy Eyeballs 演算法優化)。

Socket 程式設計的核心難點不在 API,而在於異常處理、超時控制、資源洩漏防護、編碼一致性、半包/粘包處理。建議生產環境直接使用 Netty、gRPC、Spring WebFlux 等成熟框架,專注於業務邏輯。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved