【JavaEE】網絡(2)

一、網絡編程套接字

1.1 基礎概念

【網絡編程】指網絡上的主機,通過不同的進程,以編程的方式實現網絡通信;當然,我們只要滿足進程不同就行,所以即便是同一個主機,只要是不同進程,基于網絡來傳輸數據,也屬于網絡編程
套接字其實是socket的直譯,套接字就是傳輸層給應用層提供的網絡編程API(接口)通過這個接口,應用層程序可以通過這個接口使用傳輸層提供的服務,而不需要知道它的具體實現

套接字分為兩類:流式套接字數據報套接字

流式套接字是基于TCP協議(一個傳輸層協議)實現的,TCP是一種面向連接型可靠傳輸型面向字節流全雙工的傳輸層協議,流式套接字利用這些特性為應用層提供了一個簡單的接口,用于發送和接收數據流

數據報套接字是基于UDP協議(也是一個傳輸層協議)實現的,UDP是一種面向無連接型不可靠傳輸型面向數據報全雙工的傳輸層協議

1.2 協議特點

接下來講解以下上述提到的 TCP協議和UDP協議的特點

1)面向有連接型 vs 面向無連接型:通過網絡發送數據分為面向有連接和面向無連接

有連接指在發送數據之前,發送端要先和接收端建立一條邏輯意義上的連接,連接建好后才能真正發送數據,數據發送完畢后要斷開連接;

就好比打電話,在說話之前,對方要先同意接聽,接聽并說完話后再掛斷電話

無連接則無需考慮建立連接和斷開連接,發送端可以在任何時候發送數據,接收端不知道自己會在何時收到數據,所以要時常檢查是否收到數據;

這個就像發送電子郵件,發送端可以隨時發送,無需讓接收端同意,接收端則要時常檢查是否有收到郵件

2)可靠傳輸 vs 不可靠傳輸

可靠傳輸指將要傳輸的數據盡可能的傳輸給對方,在網絡通信的過程中,會存在"丟包"的情況:A給B傳輸10個數據報,B收到了9個;

原因是A傳輸給B,中間可能會經歷很多交換機和路由器,這些交換機和路由器不只是轉發你的數據,要轉發很多數據,當數據很多時,可能會超過它們自身的硬件水平,此時多出來的數據無法轉發,會被直接丟棄掉。

TCP為了對抗丟包,內部實現了一些機制(重發)來實現可靠傳輸(機制后面會詳細講)

不可靠傳輸指再出現丟包后,也不負責重發,不可靠傳輸更注重效率,在一些注重效率,對準確性要求不高的場景使用不可靠傳輸,可靠傳輸能盡可能保證數據傳給接收端,但效率上會大打折扣

3)面向字節流 vs 面向數據報

面向字節流指傳輸的數據以字節為單位

面向數據報指傳輸的數據以數據報為單位,傳輸數據是一個一個數據報,一次讀寫只能讀寫完整的數據報,不能讀寫半個

4)全雙工 vs 半雙工

全雙工指一條鏈路,能夠進行雙向通信,后續代碼創建socket對象,既可以讀(接收)也可以寫(發送)

半雙工指一條鏈路,只能進行單向通信

二、UDP-數據報套接字編程

socket API 是由傳輸層給應用層提供的API,傳輸層是封裝于操作系統內核態的,由操作系統內核直接管理,所以可以理解為socket api是由操作系統內核管理的,而Java對于系統這些API進行了封裝,所以使得用戶程序可以直接使用這些API

UDP的socket API 有兩個重要的類

2.1 DatagramSocket

屬于UDP Socket,創建DatagramSocket的對象就可以發送和接收UDP數據報,先來看構造方法

構造方法描述
DatagramSocket( )創建一個UDP數據報套接字的Socket,綁定到本機任意一個隨機端口
DatagramSocket( int port )創建一個UDP數據報套接字的Socket,綁定到本機指定的端口號

普通方法:

普通方法描述
void receive (DatagramPacket p)接收數據報,如果沒有接收到,該方法就會阻塞等待
void send(DatagramPacket p)發送數據報,不會阻塞等待,直接發送(無連接)
void close( )關閉此數據報套接字

當創建一個套接字時,系統會為其分配資源綁定端口號,如果用完不關閉則會導致資源持續被占用

2.2 DatagramPacket

表示UDP Socket發送和接收的數據報,一個DatagramPacket對象就相當于一個UDP數據報

構造方法描述
DatagramPacket (byte[] buf, int length)構造?個DatagramPacket以用來接收數據報,接收的數據保存在字節數組(第?個參數buf)中,接收指定長度(第?個參數length)

DatagramPacket(byte[] buf, int offset, int length,?

SocketAddress address)

構造?個DatagramPacket以用來發送數據報,發送的數據為字節數組(第?個參數buf)中,從0到指定? 度(第?個參數length)address指定?的主機的IP 和端?號

上述方法可以結合下述代碼理解

2.3 模擬回顯服務器

回顯服務器指客戶端發送一個請求給服務端,服務端將這個請求原封不動的作為相應返回給客戶端,這就叫回顯(請求啥相應就是啥),接下來先編寫服務器程序:

public class UdpEchoServer {public DatagramSocket socket = null;public UdpEchoServer(int port) throws SocketException {socket =  new DatagramSocket(port); //創建 UDP Socket 并綁定一個端口號}}

服務器需要在程序啟動的時候,把在服務器程序的端口號確定下來,客戶端發送請求時需要知道服務器的IP地址(服務器所在主機的IP)、端口號port

服務器要能夠接收客戶端發送的數據,socket? receive( );需要向receive傳入一個UDP數據報

public class UdpEchoServer {public DatagramSocket socket = null;public UdpEchoServer(int port) throws SocketException {socket =  new DatagramSocket(port);}public void start() throws IOException {//1) 接收請求DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);//此時創建好的requestPacket 是一個空的數據包//requestPacket包含兩個部分1.報頭 2.載荷//字節數組用來存儲數據socket.receive(requestPacket); //客戶端會send一個數據包, 就會跳轉到這里//此時由requestPacket 是一個預留好空間的空數據包// 為了方便在 java 代碼中處理 (尤其是后面進行打印) 可以把上述數據報中的二進制數據, 拿出來, 構造成 StringString request = new String(requestPacket.getData(), 0, requestPacket.getLength());}}

接收來自客戶端的請求后,經過處理后將響應返回給客戶端,那么該如何知道應該給哪個客戶端返回響應,在我們receive接收到的數據包里就包含了這個數據包來自于哪個IP,來自于哪個端口號(客戶端)

// 2) 根據請求計算響應
String response = this.process(request);
// 3) 把響應寫回到客戶端
DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), 0, response.getBytes().length, requestPacket.getSocketAddress());
socket.send(responsePacket);

requestPacket.getSocketAddress() 這個方法返回的對象里就包含了客戶端的IP地址和端口號

上述代碼干的事情就是將字符串類型的二進制數據再構造會UDP數據包并發送給客戶端

服務端完整代碼如下:

public class UdpEchoServer {private DatagramSocket socket = null;public UdpEchoServer(int port) throws SocketException {socket = new DatagramSocket(port);}public void start() throws IOException {Scanner scanner = new Scanner(System.in);System.out.println("服務器啟動!");while (true) { // 服務器需要7*24小時持續接收并處理請求// 1) 讀取請求并解析DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);socket.receive(requestPacket);//receive方法中的requestPacket是一個空的數據包,客戶端程序通過send方法發送有數據的數據包后//會直接跳轉到這里的receive方法,而這里的requestPacket是一個預留好空間的空數據包// 為了方便在 java 代碼中處理 (尤其是后面進行打印) 可以把上述數據報中的二進制數據, 拿出來, 構造成 StringString request = new String(requestPacket.getData(), 0, requestPacket.getLength());//將字節數組構造成String類的對象// 2) 根據請求計算響應String response = this.process(request);// 3) 把響應寫回到客戶端DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), 0, response.getBytes().length,requestPacket.getSocketAddress());socket.send(responsePacket);System.out.printf("[%s:%d] req=%s, resp=%s\n", requestPacket.getAddress(), requestPacket.getPort(),request, response); // 從左到右依次為: IP地址,端口號,請求,響應}}// 由于當前寫的是 "回顯服務器"public String process(String request) {return request;}public static void main(String[] args) throws IOException {UdpEchoServer server = new UdpEchoServer(9090);server.start();}
}

接下來寫客戶端代碼:

首先客戶端需要知道服務器的IP和端口號,端口號是我們之前就設置的9090,IP用127.0.0.1,當服務器和客戶端在一個主機上,就用環回IP,這是系統提供的特殊的IP

public class UdpEchoClient {private DatagramSocket socket = null;private String serverIp;private int serverPort;public UdpEchoClient(String serverIp, int serverPort) throws SocketException {socket = new DatagramSocket();// 這倆信息需要額外記錄下來, 以備后續使用.this.serverIp = serverIp;this.serverPort = serverPort;}
}

上述構造socket對象沒有指定端口號,這樣操作系統會分配一個空閑的端口號,這個端口號每次重新啟動程序都不一樣

// 1. 從控制臺讀取用戶輸入
String request = scanner.next();
// 2. 構造請求并發送
// 構造請求數據報的時候, 不光要有數據, 還要有 "目標 "
DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), 0, request.getBytes().length, InetAddress.getByName(serverIp), serverPort);
socket.send(requestPacket); //發送數據包

上述InetAddress.getByName(serverIp)是將字符串格式的IP地址轉成Java能識別的InetAddress對象

發送完數據包,服務器經過處理返回響應,客戶端就要接收響應

// 3. 讀取響應數據
//構造一個空的數據包負責接收服務器返回的響應
DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);socket.receive(responsePacket);
// 4. 顯示響應到控制臺上.
String response = new String(responsePacket.getData(), 0, responsePacket.getLength());
System.out.println(response);

在第2步執行完send后,客戶端程序緊接著到第三步的receive,由于從發送請求到返回響應需要些時間,所以這里receive會阻塞,阻塞到接收到服務器返回響應

完整的客戶端代碼如下:

public class UdpEchoClient {private DatagramSocket socket = null;private String serverIp;private int serverPort;public UdpEchoClient(String serverIp, int serverPort) throws SocketException {socket = new DatagramSocket();// 這倆信息需要額外記錄下來, 以備后續使用.this.serverIp = serverIp;this.serverPort = serverPort;}public void start() throws IOException {System.out.println("客戶端啟動!");Scanner scanner = new Scanner(System.in);while (true) {System.out.print("請輸入要發送的請求: ");// 1. 從控制臺讀取用戶輸入String request = scanner.next();// 2. 構造請求并發送// 構造請求數據報的時候, 不光要有數據, 還要有 "目標"DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), 0, request.getBytes().length,InetAddress.getByName(serverIp), serverPort);socket.send(requestPacket);// 3. 讀取響應數據DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);socket.receive(responsePacket);// 4. 顯示響應到控制臺上.String response = new String(responsePacket.getData(), 0, responsePacket.getLength());System.out.println(response);}}public static void main(String[] args) throws IOException {UdpEchoClient client = new UdpEchoClient("127.0.0.1", 9090);// UdpEchoClient client = new UdpEchoClient("139.155.74.81", 9090);client.start();}
}

接下來啟動服務器程序和客戶端程序:

客戶端可以不斷發送請求并得到響應

服務端會不斷處理客戶端的請求

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

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

相關文章

RANS(Reynolds-Averaged Navier-Stokes) 湍流模型類型

RANS(Reynolds-Averaged Navier-Stokes) 湍流模型有多種不同的類型,除了標準的 kkk-ω 湍流模型,還有其他一些常用的湍流模型。RANS 模型的核心思想是對 Navier-Stokes 方程進行 雷諾平均,通過將流動場的瞬時變量分解為…

JS中this的值詳細講解以及面試指向練習

this 的值取決于它出現的上下文:函數、類或全局。 在函數內部,this 的值取決于函數如何被調用,this 是語言在函數體被執行時為你創建的綁定 對于典型的函數,this 的值是函數被訪問的對象。換句話說,如果函數調用的形…

2024年河南省高等職業教育技能大賽 大數據分析與應用賽項競賽方案

2024年河南省高等職業教育技能大賽 大數據分析與應用賽項競賽方案 一、賽項名稱 賽項名稱:大數據分析與應用 賽項編號:HN033 賽項組別:專業核心基本技能賽項 專業大類:電子與信息等 競賽形式:學生組(團體賽…

vue繞過rules自定義編寫動態校驗

今天犯了個低級錯誤,雖然走了很多彎路,但這個過程還是值得記錄一下 例子如下,有兩個輸入框: 第一個是套餐選擇下拉框,可以下拉選擇三個內容 第二個要根據上面的套餐選擇三個選項來決定怎么顯示,使用v-if&…

數字化招聘系統如何幫助企業實現招聘效率翻倍提升?

眾所周知,傳統的招聘方式已經難以滿足現代企業對人才的需求,而數字化招聘系統的出現,為企業提供了全新的解決方案。通過數字化招聘系統,企業可以自動化處理繁瑣的招聘流程,快速篩選合適的候選人,從而大幅提…

短視頻矩陣源碼開發部署全流程解析

在當今的數字化時代,短視頻已成為人們娛樂、學習和社交的重要方式。短視頻矩陣系統的開發與部署,對于希望在這一領域脫穎而出的企業和個人而言,至關重要。本文將詳細闡述短視頻矩陣源碼的開發與部署流程,并附上部分源代碼示例&…

華為云云原生中間件DCS DMS 通過中國信通院與全球IPv6測試中心雙重能力檢測

近日,中國信息通信研究院(以下簡稱“中國信通院”)與全球IPv6測試中心相繼宣布,華為云的分布式緩存服務(Distributed Cache Service,簡稱DCS)和分布式消息服務(Distributed Message …

關閉WPS在線功能資源和功能推薦

Kingsoft\WPS Office\12.1.0.18912\office6 選擇 【高級】 點擊 【確定】

Polars數據聚合與旋轉實戰教程

在這篇博文中,我們的目標是解決數據愛好者提出的一個常見問題:如何有效地從Polars DataFrame中創建匯總視圖,以便在不同時間段或類別之間輕松進行比較。我們將使用一個實際的數據集示例來探索實現這一目標的各種方法。 Polars簡介 Polars 是…

2024154讀書筆記|《帶著詩歌上街去》——我不長葉子,不開花,也不必要什么結果

2024154讀書筆記|《帶著詩歌上街去》——我不長葉子🌿,不開花🌼,也不必要什么結果 《帶著詩歌上街去》作者隔花人,作者很有巧思,在拍攝的照片上做詩,詩不是很有感覺,但是在墻上、風景…

建立基于TCP的客戶端和服務端

函數介紹: 1.socket() 作用:創建套接字 domain: AF_INET:IPv4 Internet 協議族。AF_INET6:IPv6 Internet 協議族。AF_UNIX:Unix 域協議族,用于在同一臺主機上的進程間通信。 type: SOCK_STREAM&#xff1a…

CNCF云原生生態版圖-分類指南(三)- 運行時

CNCF云原生生態版圖-分類指南(三)- 運行時 CNCF云原生生態版圖-分類指南三、運行時(Runtime)(一)云原生存儲(Cloud Native Storage)1. 是什么?2. 解決什么問題&#xff1…

機器學習經典算法

機器學習經典算法學習和分享。 k近鄰算法 線性回歸 梯度下降法 PCA主成分分析法 多項式回歸 邏輯回歸 支撐向量機SVM 決策樹 隨機森林 評價分類指標

MVC基礎——市場管理系統(三)Clean Architecture

文章目錄 項目地址五、Clean Architecture5.1 user cage driven5.1.1創建CoreBusiness 5.2 創建UseCases5.2.1 創建CategoriesUseCases1. 創建VeiwCategoriesUseCase獲取所有Cagegory 5.2.2. 實現ICategoryRepository接口3. 實現獲取所有Category的方法4. 實現獲取一個Cagegory…

手機上和電腦上都能觀看的翻頁電子書是如何制作的?

想知道手機上和電腦上都能觀看的翻頁電子書是都是如何制作的? 想知道這樣的電子書是怎樣呈現出來的? 那收藏這篇文章,我來跟大家說說該如何實現。 操作方法 一、登錄FLBOOK 二、開始制作,有多種創建方式,分別是&…

ABAP時間戳與日期時間轉換及時區處理

一、時間戳轉換為日期時間 1. 基本轉換 CONVERT TIME STAMP <fs_back>-lastchangedatetime TIME ZONE sy-zonloINTO DATE DATA(lv_date)TIME DATA(lv_time).2. 解決8小時時差問題的方案 方案1&#xff1a;直接使用UTC時區&#xff08;推薦&#xff09; CONVERT TIME …

Java 實現給pdf文件指定位置蓋章功能

Java 實現給pdf文件指定位置蓋章功能 開發中遇到一個需求, 需要給用戶上傳的的pdf文件, 指定位置上蓋公章的功能, 經過調研和對比, 最終確定實現思路. 這里是使用pdf文件中的關鍵字進行章子的定位, 之所以這樣考慮是因為如果直接寫死坐標的話, 可能會出現因pdf大小, 縮放, 蓋章…

ASP.NET Core API + MySql

環境 數據庫&#xff1a; mysql8.0 后端&#xff1a; vs2022 ASP.NET Core API .net 8 前端&#xff1a; Hbuilderx bootstrap 5.3.0 jquery v3.7.1 bootstrap-table 1.23.5 創建項目 添加資源包 AutoMapper Microsoft.EntityFrameworkCore.Tools 8.0.0 Pomelo.EntityFramew…

RFDiffusion 計算鍵角函數get_ang解讀

get_ang 函數&#xff08;kinematics.py包中&#xff09;計算三組原子 a,b,c 所形成的平面角&#xff08;planar angle&#xff09;&#xff0c;即 b 為頂點&#xff0c; a,b,c 所確定的角度。 源代碼&#xff1a; def get_ang(a, b, c):"""calculate planar …

Bananna Pi開源社區聯合矽昌通信打造開源的低成本Wifi5路由器

香蕉派 BPI-Wifi5 路由器采用矽昌SF19A2890S2芯片方案設計。它是一款高性能無線路由器&#xff0c;適用于小微企業、家庭和其他網絡環境。Banana Pi開源社區提供整體解決方案。所有代碼開源&#xff0c;用戶可以在上面自由開發自己的應用。 Banana Pi wifi5 路由器github代碼: …