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

Java 網路程式設計入門:Socket 客戶端完整實作指南

     編輯:Java 相關知識

Socket 基礎概念

java.net.Socket 是 Java 傳統阻塞式 I/O(BIO)的核心類,封裝 TCP 連線。若需非阻塞高併發,請改用 NIO 的 SocketChannel。本文以 BIO 為例,示範完整的客戶端開發流程。

建立連線

IP 位址直連

Socket socket = new Socket("78.46.84.171", 80);

域名解析連線

Socket socket = new Socket("jb51.net", 80);

建構子會阻塞直到三向交握完成或拋出 IOException(連線超時、拒絕、DNS 失敗等)。生產環境建議設定連線逾時:

Socket socket = new Socket();
socket.connect(new InetSocketAddress("jb51.net", 80), 5000); // 5秒連線逾時

發送資料

Socket socket = new Socket("jb51.net", 80);
OutputStream out = socket.getOutputStream();

out.write("GET / HTTP/1.1\r\nHost: jb51.net\r\n\r\n".getBytes(StandardCharsets.UTF_8));
out.flush(); // 強制刷新輸出緩衝區,將資料交給作業系統 TCP 發送緩衝區
out.close(); // 關閉輸出流,發送 FIN 封包,但輸入流仍可讀取回應

關鍵提醒:flush() 僅將資料推送至作業系統核心緩衝區,不保證已發送至網路。TCP 何時真正發送取決於 Nagle 演算法、視窗大小等因素。

接收資料

Socket socket = new Socket("jb51.net", 80);
InputStream in = socket.getInputStream();

byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
    String chunk = new String(buffer, 0, bytesRead, StandardCharsets.UTF_8);
    System.out.print(chunk);
    // 實際應用需依協定解析:定長、分隔符、長度前綴等
}
in.close();
socket.close();

讀取陷阱與解決方案

  • 阻塞特性:read() 無資料時阻塞,對方關閉連線才回傳 -1
  • 訊息邊界:TCP 是位元組流,無訊息邊界,必須自行實作協定幀化:

關閉連線

socket.close(); // 同時關閉輸入/輸出流,發送 FIN,進入 TIME_WAIT 狀態

優雅關閉建議:

  1. 呼叫 socket.shutdownOutput() 發送 FIN,告知對方不再發送資料
  2. 繼續讀取輸入流直到 -1,確保接收完對方回應
  3. 最後 socket.close() 釋放資源

完整範例:簡易 HTTP 客戶端

public class SimpleHttpClient {
    public static void main(String[] args) throws IOException {
        try (Socket socket = new Socket()) {
            socket.connect(new InetSocketAddress("httpbin.org", 80), 5000);
            socket.setSoTimeout(10000); // 讀取逾時 10秒

            // 發送請求
            String request = "GET /get HTTP/1.1\r\n" +
                             "Host: httpbin.org\r\n" +
                             "Connection: close\r\n\r\n";
            try (OutputStream out = socket.getOutputStream()) {
                out.write(request.getBytes(StandardCharsets.ISO_8859_1));
                out.flush();
            }

            // 接收回應
            try (InputStream in = socket.getInputStream();
                 BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    System.out.println(line);
                }
            }
        }
    }
}

進階主題預告

  • NIO SocketChannel + Selector 非阻塞模式
  • 連線池管理(HikariCP 風格)
  • SSL/TLS 安全通訊(SSLSocketFactory)
  • HTTP/2、WebSocket 升級協定處理
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
幀化方式範例適用場景
定長每則固定 1024 位元組簡單二進位協定
分隔符以 \n、\r\n 結尾文本協定(HTTP 頭部、SMTP)
長度前綴前 4 位元組標示主體長度高效能二進位協定(Protobuf、Thrift)