Java實(shí)現(xiàn)tcp通信核心在于serversocket與socket類,通過多線程可支持并發(fā)連接。1. tcp是面向連接、可靠傳輸,適用于網(wǎng)頁瀏覽等場景;udp無連接、速度快,適合視頻會議等實(shí)時性要求高的場景。2. 服務(wù)端使用serversocket監(jiān)聽端口并接受連接,客戶端使用socket發(fā)起連接,雙方通過輸入輸出流通信。3. 多線程處理多個客戶端時,每當(dāng)有新連接,服務(wù)端創(chuàng)建新線程獨(dú)立處理該連接。4. 注意事項(xiàng)包括避免端口沖突、處理輸入流為空、統(tǒng)一字符編碼、及時關(guān)閉資源以防止內(nèi)存泄漏。掌握這些基礎(chǔ)流程后,可進(jìn)一步擴(kuò)展功能如協(xié)議解析、心跳機(jī)制等。
Java 實(shí)現(xiàn)網(wǎng)絡(luò)編程主要依賴于 java.net 包中的類,其中最常用的就是基于 TCP 和 UDP 的 Socket 編程。想要實(shí)現(xiàn)兩個設(shè)備之間的通信,Socket 是基礎(chǔ)也是核心。
一、TCP 和 UDP 的區(qū)別
在開始寫代碼之前,先了解下 TCP 和 UDP 的基本區(qū)別:
- TCP:面向連接,可靠傳輸,適合需要確保數(shù)據(jù)完整性的場景,比如網(wǎng)頁瀏覽、文件下載。
- UDP:無連接,不保證送達(dá),速度快,適合對實(shí)時性要求高的場景,比如視頻會議、游戲。
選擇哪種方式取決于你的應(yīng)用場景。本文以 TCP 為例講解 Socket 通信的實(shí)現(xiàn)。
立即學(xué)習(xí)“Java免費(fèi)學(xué)習(xí)筆記(深入)”;
二、使用 ServerSocket 和 Socket 建立 TCP 通信
Java 中通過 ServerSocket 表示服務(wù)器端,Socket 表示客戶端,兩者配合完成通信。
1. 服務(wù)端代碼(簡單回聲服務(wù)器)
import java.io.*; import java.net.*; public class TCPServer { public static void main(String[] args) { try (ServerSocket serverSocket = new ServerSocket(8888)) { System.out.println("服務(wù)器已啟動,等待連接..."); Socket socket = serverSocket.accept(); // 阻塞等待客戶端連接 System.out.println("客戶端已連接"); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream(), true); String inputLine; while ((inputLine = in.readLine()) != null) { System.out.println("收到消息:" + inputLine); out.println("服務(wù)器回應(yīng):" + inputLine); // 回應(yīng)客戶端 } socket.close(); } catch (IOException e) { e.printStackTrace(); } } }
2. 客戶端代碼
import java.io.*; import java.net.*; public class TCPClient { public static void main(String[] args) { try (Socket socket = new Socket("localhost", 8888)) { PrintWriter out = new PrintWriter(socket.getOutputStream(), true); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in)); String userInput; while ((userInput = stdIn.readLine()) != null) { out.println(userInput); System.out.println("服務(wù)器回復(fù):" + in.readLine()); } } catch (IOException e) { e.printStackTrace(); } } }
這段代碼實(shí)現(xiàn)了最基本的一問一答式通信,你可以在此基礎(chǔ)上擴(kuò)展成多線程處理多個客戶端。
三、多線程處理多個客戶端連接
一個常見的需求是服務(wù)器能同時處理多個客戶端請求。這時就需要為每個連接創(chuàng)建一個線程。
修改服務(wù)端代碼如下:
public class MultiThreadTCPServer { public static void main(String[] args) { try (ServerSocket serverSocket = new ServerSocket(8888)) { System.out.println("服務(wù)器已啟動,等待連接..."); while (true) { Socket socket = serverSocket.accept(); new ClientHandler(socket).start(); // 每個客戶端連接開啟一個線程 } } catch (IOException e) { e.printStackTrace(); } } } class ClientHandler extends Thread { private Socket socket; public ClientHandler(Socket socket) { this.socket = socket; } public void run() { try { BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream(), true); String inputLine; while ((inputLine = in.readLine()) != null) { System.out.println("收到消息:" + inputLine); out.println("你發(fā)送的是:" + inputLine); } socket.close(); } catch (IOException e) { e.printStackTrace(); } } }
這樣就可以讓服務(wù)器支持多個客戶端并發(fā)訪問了。
四、常見問題和注意事項(xiàng)
- 端口沖突:運(yùn)行前確認(rèn)端口未被占用,否則會拋出異常。
- 輸入流讀取為空:可能是客戶端斷開連接或者沒有正確發(fā)送數(shù)據(jù)。
- 字符編碼問題:建議統(tǒng)一使用 UTF-8 編碼避免亂碼。
- 資源未關(guān)閉:記得關(guān)閉 Socket、輸入輸出流,否則容易造成內(nèi)存泄漏。
基本上就這些。Socket 編程雖然不算復(fù)雜,但細(xì)節(jié)很多,尤其是涉及并發(fā)、異常處理時更容易出錯。只要掌握基本流程,后續(xù)可以根據(jù)實(shí)際需求擴(kuò)展功能,比如加入?yún)f(xié)議解析、心跳機(jī)制等。