Java網絡編程入門:從基礎原理到實踐(二)

目錄

1. 網絡編程基礎:搞懂設備通信的底層邏輯

1.1?為啥需要網絡編程?—— 讓設備 “互通有無”

1.2 什么是網絡編程?—— 給數據 “定規矩、找路線”

1.3?網絡編程的基本概念:理清通信里的角色和流程

1.3.1?發送端和接收端 —— 數據的 “發信人” 和 “收信人”

1.3.2 請求和響應 —— 通信的 “一問一答”?

1.3.3?客戶端和服務端 —— 穩定的 “需求方” 和 “服務方”?

1.3.4 常見的客戶端服務端模型

2. Socket 套接字:網絡通信的 “連接器”?

2.1?概念:網絡通信的 “電話”

2.2?分類:兩種通信 “風格

2.2.1?數據報套接字

2.2.2?流套接字

2.3?Java數據報套接字通信模型

2.4?Java流套接字通信模型

2.5 Socket 編程注意事項:避坑要點?

3. UDP 數據報套接字編程:簡單高效的 “快傳” 實踐?

3.1?API 介紹:核心工具

3.1.1 DatagramSocket

3.1.2 DatagramPacket?

3.1.3?InetSocketAddress

3.2 代碼示例:UDP 通信全流程?

3.2.1 UDP Echo Server

3.2.2?UDP Echo Client

3.2.3?3. UDP Dict Serve 字典服務器

4.?TCP 流套接字編程:可靠傳輸的 “保障”

4.1?API 介紹:構建可靠連接

4.1.1?ServerSocket

4.1.2?Socket

?編輯4.2?代碼示例:TCP 通信實踐

4.2.1 TCP Echo Server

4.2.2?TCP Echo Client

5. 長短連接:按需選擇通信模式

5.1 短連接與長連接的定義

5.2 短連接與長連接的核心區別

5.2.1 連接建立與關閉的耗時差異

5.2.2 主動請求的發起方差異

5.2.3 適用場景差異

5.3 長連接的 “擴展痛點” 與優化方向

5.3.1 BIO 長連接的資源瓶頸

5.3.2 NIO 優化長連接的思路

5.4 總結:按需選型,平衡效率與資源


????????網絡編程聽著高深,其實就是解決 “設備之間咋傳數據” 的問題。想象一下,你手機刷短視頻,本質是手機(客戶端)和短視頻服務器(服務端)在傳數據;玩聯機游戲,是你電腦和游戲服務器、隊友設備在傳數據。這篇就把網絡編程最基礎的邏輯和核心工具 Socket,掰開揉碎了講,保證像嘮家常一樣好懂 。

1. 網絡編程基礎:搞懂設備通信的底層邏輯

1.1?為啥需要網絡編程?—— 讓設備 “互通有無”

????????用手機點外賣,手機得把 “我要點宮保雞丁” 的需求發給外賣平臺服務器;玩聯機游戲,你操控角色的動作得傳給隊友的設備;智能手表測的心率數據,得傳到手機 App 上顯示……網絡編程就是讓這些 “需求、動作、數據”,能在不同設備(或同一設備的不同程序)之間準確、高效傳遞的技術

簡單說:沒有網絡編程,所有跨設備的功能全廢!手機只能當計算器,電腦連不上網頁,智能設備數據也傳不出去,所有的網絡資源都無法訪問,世界直接 “斷網癱瘓” 。

  • 所謂的網絡資源,其實就是在網絡中可以獲取的各種數據資源。
  • 而所有的網絡資源,都是通過網絡編程來進行數據傳輸的。

1.2 什么是網絡編程?—— 給數據 “定規矩、找路線”

????????網絡編程,指網絡上的主機,通過不同的進程,以編程的方式實現網絡通信(或稱為網絡數據傳輸)。

????????當然,我們只要滿足進程不同就行;所以即便是同一個主機,只要是不同進程,基于網絡來傳輸數據,也屬于網絡編程。?

????????特殊的,對于開發來說,在條件有限的情況下,一般也都是在一個主機中運行多個進程來完成網絡編程。

????????但是,我們一定要明確,我們的目的是提供網絡上不同主機,基于網絡來傳輸數據資源:

  • 進程A:編程來獲取網絡資源
  • 進程B:編程來提供網絡資源

????????網絡編程的核心,就是控制程序按照 “網絡協議”(比如 TCP、UDP),把數據打包、發送、接收、解析。舉個例子:你用微信發消息 “吃了嗎”,手機里的微信程序會:

  1. 打包:把文字轉成符合網絡協議的 “數據包”(類似把信裝進信封,寫上收件人地址);
  2. 發送:通過網絡(WiFi、基站)把數據包傳輸出去(類似快遞小哥把信運到目的地);
  3. 接收:對方的微信程序收到數據包(類似收件人拿到信);
  4. 解析:把數據包還原成 “吃了嗎” 的文字(類似拆信封讀內容)。

????????整個過程,就是網絡編程在 “暗中操作”,讓數據能跨設備 “跑來跑去”。

1.3?網絡編程的基本概念:理清通信里的角色和流程

????????這些概念看著抽象,對應生活場景就秒懂了,一個個看:

1.3.1?發送端和接收端 —— 數據的 “發信人” 和 “收信人”

  • 發送端:數據的發送方進程,稱為發送端,它是主動發數據的一方。比如你給朋友發微信,你手機就是發送端;游戲里你開槍,你的設備就是發送端(把 “開槍動作” 發出去)。發送端主機即網絡通信的源主機。
  • 接收端:數據的接收方進程,稱為接收端,它是被動收數據的一方。朋友的手機收你的微信、隊友的設備收你 “開槍動作”,它們就是接收端。接收端主機即網絡通信中的目的主機。
  • 收發端:發送端和接收端兩端,也簡稱為收發端

注意:發送端和接收端只是相對的,角色會切換!只是一次網絡數據傳輸產生數據流向后的概念。比如你和朋友互相發消息,你們的手機會輪流當 “發送端” 和 “接收端”,像打乒乓球一樣來回傳數據。

1.3.2 請求和響應 —— 通信的 “一問一答”?

????????一般來說,獲取一個網絡資源,涉及到兩次網絡數據傳輸:

? ? ? ? ? ? ? ? ?? 第一次:請求數據的發送。

?????????????????? 第二次:響應數據的發送。

請求(Request):發送端主動提的 “需求”。比如你打開抖音,抖音 App 會給服務器發 “請求”:“給我推薦點搞笑視頻”;你登錄微信,微信 App 會發 “請求”:“驗證這個賬號密碼對不對”。

響應(Response):接收端針對請求的 “回復”。服務器收到抖音的請求,回復 “這是搞笑視頻列表”;收到微信登錄請求,回復 “密碼正確,登錄成功”(或 “密碼錯誤,失敗” )

生活 analogy:你去餐廳(客戶端)喊 “來份牛肉面”(請求),服務員(服務端)回復 “好的,馬上做”(響應),就是典型的 “請求 - 響應”。

1.3.3?客戶端和服務端 —— 穩定的 “需求方” 和 “服務方”?

  • 客戶端(Client):主動找別人獲取服務的程序 / 設備。手機 App(抖音、微信)、電腦上的瀏覽器(Chrome、Edge)、智能手表的 App,都是客戶端。特點是 “按需連接”:需要服務時才主動連服務器,不用服務時就 “躺平”。
  • 服務端(Server):長期在線、專門給別人提供服務的程序 / 設備。抖音的后臺服務器、微信的認證服務器、游戲的對戰服務器,都是服務端。特點是 “7×24 小時待命”:不管有沒有客戶端找它,它都開著提供服務,隨時準備響應請求。

再舉個生活例子:你用美團 App(客戶端)點外賣,美團的服務器(服務端)負責接收訂單、分配騎手,就是 “客戶端 - 服務端” 的典型交互。

1.3.4 常見的客戶端服務端模型

最常見的場景,客戶端是指給用戶使用的程序,服務端是提供用戶服務的程序:

  1. 客戶端先發送請求到服務端
  2. 服務端根據請求數據,執行相應的業務處理
  3. 服務端返回響應:發送業務處理結果
  4. 客戶端根據響應數據,展示處理結果(展示獲取的資源,或提示保存資源的處理結果)

  • C/S 模型(客戶端 / 服務端 ):需安裝專門客戶端軟件(如微信 App )。優點是功能定制強,能利用本地資源;缺點是客戶端需手動更新 。
  • B/S 模型(瀏覽器 / 服務端 ):通過瀏覽器訪問(如知乎網頁版 )。優點是使用方便、跨設備易訪問;缺點是受瀏覽器功能限制,復雜交互體驗弱于 C/S 。

2. Socket 套接字:網絡通信的 “連接器”?

2.1?概念:網絡通信的 “電話”

????????Socket套接字,是由系統提供用于網絡通信的技術,是基于TCP/IP協議的網絡通信的基本操作單元,是程序實現網絡通信的基礎載體。基于Socket套接字的網絡程序開發就是網絡編程。把它想象成 “網絡電話”。程序通過 Socket 建立與其他設備的連接,在連接上發送和接收數據,就像通過電話線路實現雙方通話。無論是 UDP 還是 TCP 通信,都得依靠 Socket 搭建數據傳輸的通道 。

2.2?分類:兩種通信 “風格

2.2.1?數據報套接字

????????使用傳輸層UDP協議,UDP,即User Datagram Protocol(用戶數據報協議),傳輸層協議。類似 “發短信”,發送端把數據打包成 “數據報” 直接發,不管接收端狀態。

優點:傳輸速度快,無需建立連接開銷;

缺點:可能丟數據、數據無序。適合實時性要求高、容忍少量丟包的場景(如在線視頻直播、游戲實時位置同步 )

  • 無連接
  • 不可靠傳輸
  • 面向數據報
  • 有接收緩沖區,無發送緩沖區
  • 大小受限:一次最多傳輸64k

????????對于數據報來說,可以簡單的理解為,傳輸數據是一塊一塊的,發送一塊數據假如100個字節,必須一次發送,接收也必須一次接收100個字節,而不能分100次,每次接收1個字節。

2.2.2?流套接字

????????使用傳輸層TCP協議,TCP,即Transmission Control Protocol(傳輸控制協議),傳輸層協議。如同 “打電話”,通信前需三次握手建立連接,保證數據可靠、有序傳輸,傳輸完四次揮手斷開連接

優點:數據傳輸可靠;

缺點:建立 / 斷開連接有額外耗時,速度稍慢。適合文件傳輸(需完整數據 )、登錄驗證(關鍵數據不能丟 )等場景 。

  • 有連接
  • 可靠傳輸
  • 面向字節流
  • 有接收緩沖區,也有發送緩沖區
  • 大小不限

????????對于字節流來說,可以簡單的理解為,傳輸數據是基于IO流,流式數據的特征就是在IO流沒有關閉的情況下,是無邊界的數據,可以多次發送,也可以分開多次接收。

2.3?Java數據報套接字通信模型

????????對于UDP協議來說,具有無連接,面向數據報的特征,即每次都是沒有建立連接,并且一次發送全部數據報,一次接收全部的數據報。

????????java中使用UDP協議通信。主要基于 DatagramSocket(收發器 )和 DatagramPacket(數據報載體 )實現。發送時,把數據轉字節數組,構建 DatagramPacket 并指定目標地址 / 端口,通過 DatagramSocket 發送;接收時,創建空 DatagramPacket 當緩沖區,用 DatagramSocket 接收,再解析數據 。對于一次發送及接收UDP數據報的流程如下:

????????以上只是一次發送端的UDP數據報發送,及接收端的數據報接收,并沒有返回的數據。也就是只有請求,沒有響應。對于一個服務端來說,重要的是提供多個客戶端的請求處理及響應,流程如下:?

2.4?Java流套接字通信模型

? ? ? ? java中使用TCP通信協議,主要依賴 ServerSocket(服務端 “大門”,監聽客戶端連接 )和 Socket(客戶端 / 服務端連接后的數據通道 )。服務端用 ServerSocket 綁定端口監聽,如 ServerSocket serverSocket = new ServerSocket(9999); ;客戶端用 Socket 連服務端,如 Socket clientSocket = new Socket("127.0.0.1", 9999); 。連接建立后,通過 Socket 的輸入輸出流(像水管 )收發數據,保證數據有序、可靠傳輸 。

2.5 Socket 編程注意事項:避坑要點?

在 Socket 編程開發中,這些關鍵問題得留意,避免踩坑:

  1. 客戶端與服務端部署場景
    開發調試時,常在同一主機開兩個進程模擬客戶端、服務端,但真實環境里,客戶端和服務端一般分屬不同主機 。開發要考慮跨主機通信的網絡差異(如防火墻、網段限制),別只依賴本地調試邏輯。

  2. 目標標識:IP + 端口
    數據傳輸得明確 “終點”,目的 IP?定位目標主機,目的端口號?定位主機內接收數據的進程。編程時要準確設置這兩個參數,否則數據發錯地方,通信直接失敗。

  3. 套接字類型與協議層
    Socket 編程用?流套接字(基于 TCP)?或?數據報套接字(基于 UDP)?開發,對應傳輸層 TCP/UDP 協議。但光有傳輸層還不夠,應用層協議得自己設計(比如定義數據包格式、指令含義),這部分后續會詳細講怎么規劃。

  4. 端口占用沖突問題? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 如果一個進程A已經綁定了一個端口,再啟動一個進程B綁定該端口,就會報錯,這種情況也叫端口被占用。對于java進程來說,端口被占用的常見報錯信息如下:?此時需要檢查進程B綁定的是哪個端口,再查看該端口被哪個進程占用。

解決端口被占用的問題:

  • 如果占用端口的進程A不需要運行,就可以關閉A后,再啟動需要綁定該端口的進程B
  • 如果需要運行A進程,則可以修改進程B的綁定端口,換為其他沒有使用的端口。

3. UDP 數據報套接字編程:簡單高效的 “快傳” 實踐?

3.1?API 介紹:核心工具

3.1.1 DatagramSocket

????????UDP 通信的 “收發器”,用于發送和接收UDP數據報。服務端常綁定固定端口(如 DatagramSocket serverSocket = new DatagramSocket(8888); ),方便客戶端定位;客戶端一般不綁定固定端口(DatagramSocket clientSocket = new DatagramSocket(); ),由系統分配 。

構造方法:

常用方法:?

3.1.2 DatagramPacket?

????????“數據報載體”,包含數據、目標地址(發送時 )或源地址(接收時 )。發送時,構建 DatagramPacket 需指定數據字節數組、目標地址 / 端口;接收時,創建空 DatagramPacket 當緩沖區,用 DatagramSocket 接收后解析數據 。

構造方法:

常用方法:?

????????構造UDP發送的數據報時,需要傳入 SocketAddress ,該對象可以使用 InetSocketAddress
來創建。?

3.1.3?InetSocketAddress

????????InetSocketAddress 是 SocketAddress 的子類。

構造方法:

3.2 代碼示例:UDP 通信全流程?

3.2.1 UDP Echo Server

public class UdpEchoServer {// 用于網絡通信的套接字對象,就像服務器的"通信接口"private DatagramSocket socket = null;// 服務器構造方法,需要指定一個端口號來啟動服務// 端口號就像快遞柜的編號,方便客戶端找到對應的服務public UdpEchoServer(int port) throws SocketException {// 綁定指定端口,啟動服務器的通信接口socket = new DatagramSocket(port);}// 服務器的啟動方法,一旦調用就開始工作public void start() throws IOException {System.out.println("服務器啟動成功!正在等待客戶端連接...");// 服務器需要一直運行,用死循環來保持工作狀態while (true) {// 每次循環處理一個客戶端的請求和響應// 1. 創建一個數據包對象,用來接收客戶端發來的數據// 就像準備一個"收件盒",指定最大能裝4096字節的數據DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);// 等待接收客戶端的數據,這一步會"卡住"直到有數據到來socket.receive(requestPacket);// 把接收到的字節數據轉換成字符串,方便處理// 注意:只轉換實際收到的長度,避免多余的空字符String request = new String(requestPacket.getData(), 0, requestPacket.getLength());// 2. 處理請求,得到響應結果// 對于回顯服務器來說,直接把收到的內容返回即可String response = process(request);// 3. 把響應結果發回給客戶端// 準備一個"發件盒",裝著要發送的內容,以及客戶端的地址和端口DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),  // 要發送的內容(轉換為字節數組)response.getBytes().length,  // 內容的長度requestPacket.getSocketAddress()  // 客戶端的地址和端口(從請求中獲取));// 發送響應數據socket.send(responsePacket);// 打印日志,記錄通信詳情System.out.printf("[客戶端 %s:%d] 收到: %s, 回復: %s\n",requestPacket.getAddress().toString(),  // 客戶端IP地址requestPacket.getPort(),  // 客戶端端口request,  // 客戶端發送的內容response  // 服務器回復的內容);}}// 處理請求的方法// 這里實現的是回顯功能:輸入什么,就返回什么public String process(String request) {return request;}// 程序入口:啟動服務器public static void main(String[] args) throws IOException {// 創建服務器實例,指定端口號9090UdpEchoServer server = new UdpEchoServer(9090);// 啟動服務器server.start();}
}

3.2.2?UDP Echo Client

public class UdpEchoClient {// 客戶端的通信接口,就像打電話用的"手機"private DatagramSocket socket = null;// 服務器的IP地址,類似對方的"電話號碼"private String serverIp;// 服務器的端口號,類似對方"手機上的某個APP"private int serverPort;// 客戶端構造方法:需要知道服務器的IP和端口才能連接// IP地址格式是"點分十進制",比如"192.168.1.1"public UdpEchoClient(String serverIp, int serverPort) throws SocketException {this.serverIp = serverIp;this.serverPort = serverPort;// 初始化客戶端的通信接口(不用指定端口,系統會自動分配一個)socket = new DatagramSocket();}// 客戶端啟動方法:開始和服務器通信public void start() throws IOException {System.out.println("客戶端啟動成功!可以開始發送消息了...");// 創建Scanner對象,用于讀取用戶在控制臺輸入的內容Scanner scanner = new Scanner(System.in);// 循環處理:不斷讀取用戶輸入并和服務器交互while (true) {// 顯示提示符號,告訴用戶可以輸入內容了System.out.print("-> ");// 檢查用戶是否還有輸入(如果輸入結束就退出循環)if (!scanner.hasNext()) {break;}// 讀取用戶輸入的內容(這就是要發給服務器的請求)String request = scanner.next();// 構造要發送的數據包:相當于把消息裝進"信封"DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),  // 要發送的內容(轉成字節數組)request.getBytes().length,  // 內容的長度InetAddress.getByName(serverIp),  // 服務器的IP地址(把字符串轉成網絡地址)serverPort  // 服務器的端口號);// 發送數據包:相當于把信封"寄出去"socket.send(requestPacket);// 準備接收服務器的回復:創建一個"收件盒"DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);// 等待接收服務器的回復:這一步會"卡住"直到收到消息socket.receive(responsePacket);// 把服務器回復的字節數據轉成字符串String response = new String(responsePacket.getData(), 0, responsePacket.getLength());// 在控制臺顯示服務器的回復內容System.out.println(response);}}// 程序入口:啟動客戶端public static void main(String[] args) throws IOException {// 創建客戶端實例,連接到本機(127.0.0.1)的9090端口服務器UdpEchoClient client = new UdpEchoClient("127.0.0.1", 9090);// 啟動客戶端client.start();}
}

3.2.3?3. UDP Dict Serve 字典服務器

思路:客戶端發單詞,服務器查字典(用 Map 存單詞 - 翻譯 )返回翻譯。只需要重寫 process。比如初始化 Map<String, String> dict = new HashMap<>(); ,存入 dict.put("apple", "蘋果"); 等。服務器接收單詞后,在 dict 中查找,把翻譯當響應發回;客戶端發請求、收翻譯并展示。通過這個示例,能更靈活理解 UDP 套接字的應用 。

4.?TCP 流套接字編程:可靠傳輸的 “保障”

4.1?API 介紹:構建可靠連接

4.1.1?ServerSocket

????????ServerSocket 是創建TCP服務端Socket的API。是服務端 “大門”,監聽客戶端連接。創建時綁定端口,如ServerSocket serverSocket = new ServerSocket(9090);然后通過 serverSocket.accept() 阻塞等客戶端連接,有連接時返回 Socket 用于通信 。

構造方法:

其它方法:?

4.1.2?Socket

????????Socket 是客戶端發起連接或服務端通過 ServerSocket.accept () 響應連接后得到的通信端點,雙方建立連接后,用其保存的對端信息收發數據,客戶端創建時需指定服務端 IP 和端口 ,服務端通過該 Socket 的輸入輸出流交互 。

構造方法:

其它方法:

4.2?代碼示例:TCP 通信實踐

4.2.1 TCP Echo Server

public class TcpEchoServer {// 服務器的"總機",負責接聽客戶端的連接請求ServerSocket serverSocket = null;// 構造方法:創建服務器并指定端口號(就像給總機分配一個電話號碼)public TcpEchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);}// 啟動服務器的方法public void start() throws IOException {System.out.println("服務器啟動成功!等待客戶端連接...");// 創建一個線程池,用來處理多個客戶端的請求(相當于多個接線員)// newCachedThreadPool表示可以根據需要自動創建新線程ExecutorService pool = Executors.newCachedThreadPool();// 服務器一直運行,不斷接收新的客戶端連接while (true) {// 等待客戶端連接(總機接聽電話)// 這一步會"卡住",直到有客戶端來連接Socket clientSocket = serverSocket.accept();// 收到連接后,交給線程池處理(安排一個接線員專門服務這個客戶端)pool.submit(new Runnable() {@Overridepublic void run() {processConnection(clientSocket);}});}}// 處理單個客戶端連接的方法(接線員和客戶的通話過程)private void processConnection(Socket clientSocket) {// 打印客戶端上線信息:包含客戶端的IP和端口System.out.printf("[%s:%d] 客戶端上線啦\n", clientSocket.getInetAddress(), clientSocket.getPort());// try-with-resources語法:自動關閉資源,不用手動寫close()try (// 獲取輸入流:用來讀取客戶端發送的消息(相當于聽客戶說話)InputStream inputStream = clientSocket.getInputStream();// 獲取輸出流:用來向客戶端發送消息(相當于跟客戶說話)OutputStream outputStream = clientSocket.getOutputStream()) {// 創建Scanner對象,方便讀取輸入流中的文本Scanner scanner = new Scanner(inputStream);// 循環處理客戶端的請求while (true) {// 判斷客戶端是否還有數據發送(如果沒有,說明客戶端要下線了)if (!scanner.hasNext()) {System.out.printf("[%s:%d] 客戶端下線啦\n", clientSocket.getInetAddress(), clientSocket.getPort());break;}// 1. 讀取客戶端發送的請求內容String request = scanner.next();// 2. 處理請求(回顯服務器直接返回相同內容)String response = process(request);// 3. 把響應寫回給客戶端// 創建PrintWriter方便寫入文本PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(response);// 刷新緩沖區:確保數據立刻發送出去(不然可能留在緩存里)printWriter.flush();// 打印日志:記錄這次通信的詳情System.out.printf("[%s:%d] 收到: %s, 回復: %s\n",clientSocket.getInetAddress(),clientSocket.getPort(),request,response);}} catch (IOException e) {// 捕獲并打印異常信息(比如網絡中斷等問題)e.printStackTrace();}}// 處理請求的核心方法(回顯邏輯:輸入什么返回什么)private String process(String request) {return request;}// 程序入口:啟動服務器public static void main(String[] args) throws IOException {// 創建服務器實例,綁定9090端口TcpEchoServer server = new TcpEchoServer(9090);// 啟動服務器server.start();}
}

4.2.2?TCP Echo Client

public class TcpEchoClient {// 客戶端的"電話",用來和服務器建立連接并通話private Socket clientSocket = null;// 構造方法:初始化客戶端,需要知道服務器的IP和端口(相當于知道對方的電話號碼)public TcpEchoClient(String serverIp, int serverPort) throws IOException {// 連接服務器:就像撥打指定的電話號碼clientSocket = new Socket(serverIp, serverPort);}// 啟動客戶端:開始和服務器通信public void start() {System.out.println("客戶端啟動成功!可以開始聊天啦...");// try-with-resources語法:自動關閉輸入輸出流,不用手動關閉try (// 輸入流:用來接收服務器發過來的消息(相當于耳朵,聽服務器說話)InputStream inputStream = clientSocket.getInputStream();// 輸出流:用來向服務器發送消息(相當于嘴巴,跟服務器說話)OutputStream outputStream = clientSocket.getOutputStream()) {// 掃描器1:用來讀取用戶在控制臺輸入的內容(從鍵盤讀)Scanner scannerConsole = new Scanner(System.in);// 掃描器2:用來讀取服務器發送過來的消息(從網絡讀)Scanner scannerNetwork = new Scanner(inputStream);// 打印器:用來向服務器發送消息(包裝輸出流,方便寫文本)PrintWriter writer = new PrintWriter(outputStream);// 循環聊天:不斷讀取用戶輸入并發送給服務器,再接收服務器回復while (true) {// 顯示提示符號,告訴用戶可以輸入內容了System.out.printf("-> ");// 檢查用戶是否還有輸入(如果沒有輸入,就退出循環)if (!scannerConsole.hasNext()) {break;}// 1. 讀取用戶在控制臺輸入的內容(要發給服務器的消息)String request = scannerConsole.next();// 2. 把消息發送給服務器writer.println(request);// 刷新緩沖區:確保消息立刻發出去(不然可能存在緩存里沒發送)writer.flush();// 3. 等待并讀取服務器的回復String response = scannerNetwork.next();// 4. 在控制臺顯示服務器的回復內容System.out.println(response);}} catch (IOException e) {// 捕獲并打印異常(比如網絡斷開等問題)e.printStackTrace();} finally {// 最后一定要關閉客戶端的"電話",釋放資源try {clientSocket.close();} catch (IOException e) {e.printStackTrace();}}}// 程序入口:啟動客戶端public static void main(String[] args) throws IOException {// 創建客戶端實例,連接到本機(127.0.0.1)的9090端口服務器TcpEchoClient client = new TcpEchoClient("127.0.0.1", 9090);// 啟動客戶端,開始通信client.start();}
}

5. 長短連接:按需選擇通信模式

????????在 TCP 通信體系里,連接的建立與關閉時機,直接界定了短連接和長連接兩種模式。合理選用,能讓程序在效率、資源占用間找到平衡,適配不同業務場景。

5.1 短連接與長連接的定義

TCP 傳輸數據依賴先建立連接,“何時關閉連接” 是區分短、長連接的核心

  • 短連接:每次完成 “接收數據 + 返回響應” 后,立即關閉連接 。如同 “一錘子買賣”,一次連接僅支撐單次收發數據,下次交互需重新建連。
  • 長連接:保持連接狀態不關閉,允許雙方持續收發數據 。像 “持續對話”,一次建連可支撐多次數據交互,直至主動斷開或網絡異常。

5.2 短連接與長連接的核心區別

對比短、長連接,從建連開銷到適用場景,差異顯著:

5.2.1 連接建立與關閉的耗時差異

  • 短連接:每次請求 - 響應,都要經歷 “建連→傳數據→關連” 全流程 。頻繁交互時,建連、關連的耗時會疊加,拖慢整體效率。
  • 長連接:僅首次需完整建連,后續請求 - 響應直接復用已連通道 。省掉重復建連、關連的耗時,高頻交互場景下效率優勢明顯。

5.2.2 主動請求的發起方差異

  • 短連接:通常由客戶端主動發起請求,服務端被動響應 。典型如瀏覽器訪問靜態網頁,客戶端發請求,服務端回數據后關連,服務端很少主動 “推送”。
  • 長連接:支持雙向主動通信 。既允許客戶端主動發請求(如聊天時發消息 ),也支持服務端主動推送數據(如即時通訊的新消息通知、實時行情更新 )。

5.2.3 適用場景差異

  • 短連接:適配客戶端請求頻率低的場景 。如瀏覽新聞網頁(單次請求即可獲取內容 )、查詢靜態數據接口(查天氣、物流信息 ),無需持續保持連接,“即用即關” 省資源。
  • 長連接:專為客戶端與服務端高頻通信設計 。像聊天室(持續收發消息 )、實時游戲(同步玩家操作、狀態 )、金融行情推送(秒級更新數據 ),依賴長連接實現低延遲、高實時性交互。

5.3 長連接的 “擴展痛點” 與優化方向

????????長連接雖高效,但若基于傳統 BIO(同步阻塞 IO )實現,會面臨系統資源占用過高問題:

5.3.1 BIO 長連接的資源瓶頸

????????BIO 模式下,每個長連接對應一個阻塞線程?。連接需持續 “阻塞等待” 數據,若有 1 萬長連接,服務端需創建 1 萬線程,內存、線程切換開銷會直接 “壓垮” 系統。

5.3.2 NIO 優化長連接的思路

????????為解決 BIO 缺陷,Java 引入?NIO(同步非阻塞 IO )?,通過?Selector(多路復用器 )?實現:

  • 少量線程管理大量連接,線程無需阻塞等待,而是由 Selector 監聽 “哪些連接有數據可讀 / 可寫”,按需處理。
  • 極大降低資源消耗,支撐高并發長連接場景(如百萬級在線的即時通訊系統 ),主流框架(Netty )也基于 NIO 封裝,簡化長連接開發。

5.4 總結:按需選型,平衡效率與資源

????????短連接 “簡單輕量”,適合低頻交互;長連接 “高效持久”,適配高頻、實時場景 。實際開發中,需結合業務需求:

  • 若做新聞網站、靜態數據接口,選短連接省心省力;
  • 若開發聊天、實時游戲,長連接是必選項,且建議基于 NIO/Netty 優化資源占用。
    理解長短連接的本質差異,才能讓網絡通信既高效又穩定,貼合業務需求 。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/915934.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/915934.shtml
英文地址,請注明出處:http://en.pswp.cn/news/915934.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

XSS內容分享

反射型XSS &#xff1a;反射型XSS 是非持久性、參數型的跨站腳本。反射型XSS 的JS 代碼在Web 應用的參數&#xff08;變量&#xff09;中&#xff0c;如搜索框的反射型XSS。在搜索框中&#xff0c;提交PoC[scriptalert(/xss/)/script]&#xff0c;點擊搜索&#xff0c;即可觸發…

電線桿距離居民區的安全距離【重要!!!】

10kV架空電線安全距離購房指南 中國大陸地區10kV架空電線距居民住宅需要滿足1.5米水平安全距離&#xff08;裸導線&#xff09;和6.5米垂直安全距離的國家強制標準。根據現行法規&#xff0c;10kV系統的電磁輻射水平極低&#xff0c;對居民健康影響可忽略不計&#xff0c;但購房…

河南萌新聯賽2025第(二)場:河南農業大學

我看到花兒在綻放 我聽到鳥兒在歌唱 我看到人們匆匆忙忙 我看到云朵在天上 我聽到小河在流淌 我看到人們漫步在路上 河南萌新聯賽2025第&#xff08;二&#xff09;場&#xff1a;河南農業大學 河南萌新聯賽2025第&#xff08;二&#xff09;場&#xff1a;河南農業大學_ACM/N…

unixbench系統性能測試

unixbench系統性能測試 環境&#xff1a; UnixBench: 6.0.0(2025-05-21)簡介 UnixBench 是一款經典的 Unix/Linux 系統性能測試工具&#xff0c;主要用于評估系統的CPU 運算能力、內存性能、多線程處理能力以及部分系統調用&#xff08;如進程創建、文件操作&#xff09;的效率…

上線了,自己開發的刷題小程序,vue3.0

嘿&#xff0c;最近我搞了個Java刷題的小程序&#xff0c;用Vue寫的&#xff0c;界面和功能都還挺完整的。今天就來跟大家聊聊這個小程序是怎么實現的&#xff0c;代碼里都藏著哪些小細節。 先看整體結構&#xff0c;我把整個頁面分成了幾個大塊&#xff1a;頂部導航欄、題目內…

嵌入式開發學習———Linux環境下數據結構學習(三)

單向循環鏈表單向循環鏈表是一種特殊的單向鏈表&#xff0c;尾節點的指針指向頭節點&#xff0c;形成一個閉環。適用于需要循環訪問的場景&#xff0c;如輪詢調度。結構特點&#xff1a;每個節點包含數據域和指向下一個節點的指針&#xff0c;尾節點的指針指向頭節點而非空值。…

【華為機試】684. 冗余連接

文章目錄684. 冗余連接描述示例 1示例 2提示解題思路核心分析問題轉化算法選擇策略1. 并查集 (Union-Find) - 推薦2. 深度優先搜索 (DFS)3. 拓撲排序算法實現詳解方法一&#xff1a;并查集 (Union-Find)方法二&#xff1a;深度優先搜索 (DFS)數學證明并查集算法正確性證明時間復…

Ⅹ—6.計算機二級綜合題7---10套

目錄 第7套 【填空題】 【修改題】 【設計題】 第8套 【填空題】 【修改題】 【設計題】 第9套 【填空題】 【修改題】 【設計題】 第10套 【填空題】 【修改題】 【設計題】 第7套 【填空題】 題目要求:給定程序中,函數fun的功能是:將形參s所指字符串中所…

【三橋君】大語言模型計算成本高,MoE如何有效降低成本?

? 你好&#xff0c;我是 ?三橋君? &#x1f4cc;本文介紹&#x1f4cc; >> 一、引言 在AI技術飛速發展的當下&#xff0c;大語言模型&#xff08;LLM&#xff09;的參數規模不斷增長&#xff0c;但隨之而來的計算成本問題也日益凸顯。如何在保持高效推理能力的同時擴…

Python游戲開發利器:Pygame從入門到實戰全解析

引言 Pygame是Python中最受歡迎的2D游戲開發庫之一&#xff0c;基于SDL&#xff08;Simple DirectMedia Layer&#xff09;構建&#xff0c;支持圖形渲染、音效處理、事件響應等核心功能。無論是開發簡單的休閑游戲&#xff0c;還是復雜的交互式應用&#xff0c;Pygame都能提供…

行為型模式-協作與交互機制

行為型模式聚焦于對象間的行為交互&#xff0c;通過規范對象協作方式提升系統的靈活性與可擴展性。在分布式系統中&#xff0c;由于多節點異步通信、網絡不可靠性及狀態一致性挑戰&#xff0c;行為型模式需針對分布式特性進行適應性設計。本文從觀察者、策略、命令、責任鏈、狀…

spring boot 整合 Spring Cloud、Kafka 和 MyBatis菜鳥教程

環境準備確保項目中已引入 Spring Boot、Spring Cloud、Kafka 和 MyBatis 的依賴。以下是一個典型的 Maven 依賴配置&#xff1a;<dependencies><!-- Spring Boot Starter --><dependency><groupId>org.springframework.boot</groupId><artif…

20 BTLO 藍隊靶場 Sticky Situation 解題記錄

難度&#xff1a;5/10考察技能: Windows admin, Autopsy 使用場景&#xff1a;分析USB設備使用情況Autopsy使用注意&#xff1a;用管理員打開&#xff0c;在實際分析時注意先復制一個鏡像文件&#xff0c;保存好原文件常用的Windows USB 取證的位置:Windows XP:Registry Key: U…

安裝及配置Go語言開發環境與VSCode集成指南

安裝Go語言開發 安裝Go語言開發環境是第一步。訪問Go官網&#xff0c;下載適合操作系統的安裝包&#xff0c;如果進不去可以訪問Go官方鏡像站。 根據自己的系統選擇對應的安裝包&#xff0c;我這邊是Windows系統就點擊安裝第一個即可。 點擊下一步即可。 驗證安裝是否成功可以…

專題:2025微短劇行業生態構建與跨界融合研究報告|附100+份報告PDF匯總下載

原文鏈接&#xff1a; https://tecdat.cn/?p43384 分析師&#xff1a;Boyu Wang 在此對 Boyu Wang 對本文所作的貢獻表示誠摯感謝&#xff0c;他在武漢大學完成了數據科學與大數據技術專業的學習。擅長 R 語言、Python、機器學習、數據可視化。 中國短視頻行業在經歷爆發式增…

配置NGINX

Nginx環境配置與前端VUE部署安裝nginx&#xff1a;命令sudo yum update && sudo yum install nginx部署:拷貝前端到目錄/home/publish/idasweb/下修改nginx配置&#xff1a;進入到/etc/nginx目錄下&#xff0c;修改nginx.conf中user www-data為user root&#xff0c;不…

MySQL深度理解-MySQL索引優化

1.Order by與Group by優化1.1Case1employees表中建立了name&#xff0c;position和age索引&#xff0c;并且使用了order by age進行排序操作&#xff1a;EXPLAIN SELECT * FROM employees WHERE name LiLei and position dev order by age最終explain的結果發現使用了idx_nam…

「Linux命令基礎」用戶和用戶組實訓

用戶與用戶組關系管理 在Linux系統中,用戶和用戶組的關系就像班級里的學生和小組。一個用戶可以同時屬于多個組,這種靈活的成員關系為權限管理提供了便利。創建用戶時,系統會自動生成一個與用戶同名的主組,這個組會成為用戶創建文件時的默認屬組。 理解用戶和用戶組的關系…

Https以及CA證書

目錄 1. 什么是 HTTPS 通信機制流程 證書驗證過程 CA證書 瀏覽器如何校驗證書合法性呢&#xff1f; 1. 什么是 HTTPS HTTP 加上加密處理和認證以及完整性保護后即是 HTTPS。 它是為了解決 HTTP 存在的安全性問題&#xff0c;而衍生的協議&#xff0c;那使用 HTTP 的缺點有…

數字圖像處理(四:圖像如果當作矩陣,那加減乘除處理了矩陣,那圖像咋變):從LED冬奧會、奧運會及春晚等等大屏,到手機小屏,快來挖一挖里面都有什么

數字圖像處理&#xff08;四&#xff09;三、&#xff08;準備工作&#xff1a;玩具咋玩&#xff09;圖像以矩陣形式存儲&#xff0c;那矩陣一變、圖像立刻跟著變&#xff1f;原圖發揮了鈔能力之后的圖上述代碼包含 10 個圖像處理實驗&#xff0c;每個實驗會生成對應處理后的圖…