實現伺服器和客戶端資料互動,Java Socket有妙招
本文分享自華為雲社群《Java Socket 如何實現伺服器和客戶端資料互動》,作者 : jackwangcumt 。
GoodMai 好買網
IT技術交易平臺
1 Socket概述
根據百度百科的定義,Socket 譯為套接字,它是對網路中不同主機上的應用程式之間進行雙向通訊的端點的抽象。一個Socket例項就是網路上程式通訊的一端,提供了應用層程式利用網路協議交換資料的機制。Socket向上連線各種應用程式,向下連線各種網路協議,是應用程式透過網路協議進行通訊的介面。其示意圖如下下圖所示:
(來自《Java TCP/IP Socket程式設計》)
從上圖可知,套接字Socket在OSI七層模型中處於應用層和傳輸層之間,是一個重要的介面。一般來說,傳輸層協議有TCP協議和UDP協議。這兩個協議底層都基於IP網路層協議。
2 Java Socket 實現
在Java SDK中,對於Socket原生提供了支援,它分為ServerSocket和Socket,其中ServerSocket發起一個服務端的Socket,其中需要提供一個埠號,如果給定0,則自動申請可用的埠。當然了,也可以指定具體的埠號(有一定的範圍,不超過 65535 )。不過這裡需要注意,傳入的埠不能被其他應用佔用,否則啟動服務失敗。下面給出一個簡單的ServerSocket示例,程式碼如下:
package com.example.demo.network; import java.io.IOException; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class MyServer { //<= 65535 private static final int PORT = 65535; public static void main(String[] args) throws Exception { try (ServerSocket listener = new ServerSocket(PORT)) { System.out.println("Server Started"); //執行緒池大小,它根據客戶端數來決定,當大於10時,則之前的10個執行緒仍然可以工作, // 而超過的執行緒則進入佇列中,等待。 //當之前的客戶端釋放量後,則在佇列中的執行緒仍然可以工作。 ExecutorService pool = Executors.newFixedThreadPool(10); while (true) { //多執行緒 pool.execute(new MyServerDemo01(listener.accept())); System.out.println(pool); } } } //Runnable介面的實現物件可以被執行緒Thread呼叫 private static class MyServerDemo01 implements Runnable { private Socket socket; MyServerDemo01(Socket socket) { this.socket = socket; } public void run() { System.out.println("Client [" + socket.getRemoteSocketAddress().toString()+" ] Connected"); try { //輸入 Scanner in = new Scanner(socket.getInputStream()); //輸出 PrintWriter out = new PrintWriter(socket.getOutputStream(), true); while (in.hasNextLine()) { String msg = in.nextLine(); System.out.println("Client [" + socket.getRemoteSocketAddress().toString()+" ] : " + msg); out.println(msg.toUpperCase()); } } catch (Exception e) { System.out.println("Error:" + socket+ e.getMessage()); } finally { try { //關閉socket socket.close(); } catch (IOException e) { e.printStackTrace(); } System.out.println("Closed: " + socket); } } } }
啟動該Server端,並開始監聽客戶端的連線。當客戶端沒有連線時,伺服器執行緒池pool並未啟動單獨的執行緒。下面給出客戶端的Java Socket實現,具體的示例程式碼如下:
package com.example.demo.network; import java.io.PrintWriter; import java.net.Socket; import java.util.Scanner; public class MyClient { //<= 65535 private static final int PORT = 65535; //伺服器地址 private static final String IP = "127.0.0.1"; public static void main(String[] args) throws Exception { try (Socket socket = new Socket(IP, PORT)) { System.out.println("Client ["+socket.getRemoteSocketAddress().toString()+" ] Started"); Scanner scanner = new Scanner(System.in); Scanner in = new Scanner(socket.getInputStream()); PrintWriter out = new PrintWriter(socket.getOutputStream(), true); while (scanner.hasNextLine()) { out.println(scanner.nextLine()); System.out.println("Server Response:"+ in.nextLine()); } }catch (Exception ex){ System.out.println("Error : "+ ex.getMessage()); } } }
從程式碼可知,try (Socket socket = new Socket(IP, PORT)) 是一種包含資源釋放的try-with-resource機制,它會自動進行資源釋放,而不需要手動進行釋放。Socket物件要想和伺服器通訊,必須要明確伺服器的IP地址和埠,否則不能正確通訊,Socket啟動時,也會在主機上佔用自己的埠。我們首先啟動Server端,然後可以同時啟動10個以上的Client端,比如13個,那麼超過Executors.newFixedThreadPool(10)限定的數量10後,將進入queued tasks佇列中進行排隊等待。透過列印pool物件,可以看出當前的狀態,比如[Running, pool size = 4, active threads = 4, queued tasks = 0, completed tasks = 0]說明當前在執行狀態,執行緒池大小為10,啟用的執行緒為10,等待的任務執行緒queued tasks為0。
下面給出Server端相關輸出示例:
Server Started java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0] Client [/127.0.0.1:64590 ] Connected java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 2, active threads = 2, queued tasks = 0, completed tasks = 0] Client [/127.0.0.1:64597 ] Connected java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0] Client [/127.0.0.1:64603 ] Connected Client [/127.0.0.1:64590 ] : hello Client [/127.0.0.1:64590 ] : hello Client [/127.0.0.1:64597 ] : world Client [/127.0.0.1:64597 ] : world Client [/127.0.0.1:64603 ] : python Client [/127.0.0.1:64597 ] : python02 java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 4, active threads = 4, queued tasks = 0, completed tasks = 0] Client [/127.0.0.1:57806 ] Connected java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 0] Client [/127.0.0.1:57814 ] Connected java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 6, active threads = 6, queued tasks = 0, completed tasks = 0] Client [/127.0.0.1:57820 ] Connected java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 7, active threads = 7, queued tasks = 0, completed tasks = 0] Client [/127.0.0.1:57827 ] Connected java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 8, active threads = 8, queued tasks = 0, completed tasks = 0] Client [/127.0.0.1:57833 ] Connected java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 9, active threads = 9, queued tasks = 0, completed tasks = 0] Client [/127.0.0.1:57839 ] Connected java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 10, active threads = 10, queued tasks = 0, completed tasks = 0] Client [/127.0.0.1:57845 ] Connected java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 10, active threads = 10, queued tasks = 1, completed tasks = 0] java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 10, active threads = 10, queued tasks = 2, completed tasks = 0] java.util.concurrent.ThreadPoolExecutor@256216b3[Running, pool size = 10, active threads = 10, queued tasks = 3, completed tasks = 0] Closed: Socket[addr=/127.0.0.1,port=64590,localport=65535] Client [/127.0.0.1:57854 ] Connected Client [/127.0.0.1:57814 ] : t2 Client [/127.0.0.1:57814 ] : tw2 ```
客戶端相關輸入輸出介面如下:
Client [/127.0.0.1:65535 ] Started world Server Response:WORLD world Server Response:WORLD python02 Server Response:PYTHON02
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70008135/viewspace-2839263/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- php原生socket實現客戶端與服務端資料傳輸PHP客戶端服務端
- netty系列之:自建客戶端和HTTP伺服器互動Netty客戶端HTTP伺服器
- 如何用Java Socket實現一個簡單的Redis客戶端JavaRedis客戶端
- Linux下簡單的ACE socket客戶端和伺服器端Linux客戶端伺服器
- Web端與Client客戶端資料互動方案選擇Webclient客戶端
- C語言透過socket實現TCP客戶端C語言TCP客戶端
- Python socket的客戶端Python客戶端
- C/S(socket、執行緒 實現多個客戶端、伺服器端簡易通訊)執行緒客戶端伺服器
- php與ethereum客戶端互動PHP客戶端
- RMAN之客戶端互動(一)客戶端
- RMAN之客戶端互動(二)客戶端
- socket.io 客戶端與伺服器應用客戶端伺服器
- Java與WCF互動(一):Java客戶端呼叫WCF服務 (轉)Java客戶端
- 2020-09-30Socket 一個伺服器監聽多個客戶端 功能實現伺服器客戶端
- Java UDP伺服器和客戶端原始碼 -javarevisitedJavaUDP伺服器客戶端原始碼
- socket實現服務端多執行緒,客戶端重複輸入服務端執行緒客戶端
- Redis 6.0 客戶端快取的伺服器端實現Redis客戶端快取伺服器
- JAVA通訊(二)——實現客戶機和伺服器通訊Java伺服器
- C#Socket伺服器與客戶端的開發(3)C#伺服器客戶端
- Socket最簡單的客戶端與服務端通訊-Java客戶端服務端Java
- 主流資料庫和 NoSQL 的 Rust 客戶端驅動程式資料庫SQLRust客戶端
- 客戶端骨架屏實現客戶端
- 002 Rust 網路程式設計,實現 UDP 伺服器和客戶端Rust程式設計UDP伺服器客戶端
- Spring Boot+Socket實現與html頁面的長連線,客戶端給伺服器端發訊息,伺服器給客戶端輪詢傳送訊息,附案例原始碼Spring BootHTML客戶端伺服器原始碼
- locust 新手問下 locust 自定義一個 socket 客戶端該如何實現客戶端
- 前後端資料的互動--如何實現資料加密?--02後端加密
- HHDESK埠轉發監控服務獲取客戶端和資料庫之間的互動資訊客戶端資料庫
- 實現服務端和客戶端的實時雙向資料傳輸-WebSocket簡單瞭解服務端客戶端Web
- MQTT伺服器搭建服務端和客戶端MQQT伺服器服務端客戶端
- Java的oauth2.0 服務端與客戶端的實現JavaOAuth服務端客戶端
- .net socket.io客戶端使用過程客戶端
- 在 WPF 客戶端實現 AOP 和介面快取客戶端快取
- jQuery實現客戶端CheckAll功能jQuery客戶端
- java websocket 客戶端JavaWeb客戶端
- java netty 實現 websocket 服務端和客戶端雙向通訊 實現心跳和斷線重連 完整示例JavaNettyWeb服務端客戶端
- 記筆記:C# Socket客戶端監聽伺服器端處理方案【同步】筆記C#客戶端伺服器
- python實現兩臺不同主機之間進行通訊(客戶端和服務端)——SocketPython客戶端服務端
- 使用Netty實現HTTP2伺服器/客戶端的原始碼和教程 - BaeldungNettyHTTP伺服器客戶端原始碼