淺談網絡通信(1)

文章目錄

  • 一、認識一些網絡基礎概念
    • 1.1、ip地址
    • 1.2、端口號
    • 1.3、協議
    • 1.4、協議分層
    • 1.5、協議分層的2種方式
      • 1.5.1、OSI七層模型
      • 1.5.2、TCP/IP五層模型[!]
        • 1.5.2.1、TCP/IP五層協議各層的含義及功能
  • 二、網絡中數據傳輸的基本流程——封裝、分用
    • 2.1、封裝
    • 2.2、分用
      • 2.2.1、5元組
  • 三、進行網絡編程
    • 3.1、UDP
      • 3.1.1、UDP 的特點
    • 3.2、TCP
      • 3.2.1、TCP 的特點
    • 3.3 TCP、UDP特點解析
    • 3.4、使用傳輸層協議 TCP/UDP 提供的 socket api 進行網絡通信
      • 3.4.1、UDP—— DatagramSocket、DatagramPacket
        • 3.4.1.1 使用UDP協議編寫回顯服務器

一、認識一些網絡基礎概念

1.1、ip地址

使用 ip 地址,來描述網絡上一個設備所在的位置。

1.2、端口號

區分一個主機上不同的應用程序。
一個網絡程序,在啟動時,都需要綁定一個或多個端口號,因為后續的通信都需要依賴端口來展開。

1.3、協議

協議描述了網絡通信時傳輸的數據的含義。

1.4、協議分層

協議就只是表示一種約定,這樣的約定可以是任意的,由于網絡通信協議是復雜的,因此在經過了多年的發展后,行業標準、專家已經規定出了現成的協議,我們只需要學習好規定出的現成協議即可。

那為什么要約定好這么一份通用的協議呢?

這是由于在網絡通信中,電腦種類很多,制作設備的廠商也很多,必須有一份統一的協議標準,讓大家都按照同樣的標準研發設備,以確保不同的廠商研發出的東西都能夠在一起相互通信。

但由于網絡通信確實是十分復雜的,故會涉及到一系列非常繁瑣、細節的工作,因此僅靠一個協議就解決所有問題,就導致這個協議就會十分龐大、復雜,因此此時就需要對協議進行分層。

上層協議 調用 下層協議,下層協議 給 上層協議提供服務。

例子:
在這里插入圖片描述
協議也是如此。

1.5、協議分層的2種方式

1.5.1、OSI七層模型

OSI七層模型一般只存在于教科書中。
在這里插入圖片描述

1.5.2、TCP/IP五層模型[!]

TCP/IP五層模型是如今網絡通信最常用的模型,很重要!
在這里插入圖片描述

1.5.2.1、TCP/IP五層協議各層的含義及功能

第一層:物理層
含義: 負責在物理媒介上發送和接收原始比特流。
功能: 為網絡通信提供物理連接,定義了如網卡、網口、網線等物理設備的標準。
第二層:數據鏈路層
含義: 為相鄰節點提供端到端的直接鏈接服務,以幀的形式傳輸數據。
功能: 錯誤檢測和修正,管理幀數據。
第三層:網絡層
含義: 負責數據在網絡中的路由選擇和轉發,確保數據從源 ip 地址傳送到 目的 ip 地址。
功能: 路由選擇,數據包的封裝與分用。
第四層:傳輸層
含義:直接提供端到端的服務,只關注起點和終點,不關注中間的實現過程。
功能: 對端口號進行管理
第五層:應用層
含義: 為應用程序提供網絡通信服務。
功能: 允許應用程序與網絡交互,實現數據傳輸、文件共享、電子郵件…等網絡通信功能。

在這里插入圖片描述
舉個例子加深對TCP/IP五層模型中各層的理解:
1、物理層 :約定網絡通信中的一些基礎設施需要遵守的規范,如約定這些信息:網線、網口、網口… 就像快遞車行駛在公路上運送快遞時,公路、信號燈、公路上的綠化形式…都有一定的制定標準。
2、數據鏈路層 :相鄰節點之間,數據是如何傳輸的。快遞公司運送快遞時,確定好快遞的運輸路線之后,假設此時快遞車運送快遞的路線是:廣東——>柳州——>南寧,那么此時就需要考慮該條路線中的相鄰節點之間是怎么走的,如從廣東——>柳州,快遞是怎么運送的,到底是水運、還是航運…,而從柳州——>南寧,快遞是怎么運送的,到底是陸運、還是航運…
3、網絡層 :與路徑規劃有關。j就像當前快遞車運送快遞的路線是怎么規劃的:俗話說,條條大路通羅馬,因此運送快遞到達目的地其實可以有很多條不同的路線能夠到達目的地。譬如說有,廣東——>柳州——>南寧、廣東——>桂林——>南寧…究竟選擇哪條路線運送快遞,由網絡層負責。
4、傳輸層:只關注起點和終點,不關注中間過程。譬如網購時,需要告知賣家自己的收件地址,那此時賣家去快遞公司寄快遞給用戶時,就會告知快遞公司當前所寄商品是從哪里寄出,要寄往哪里,此時就行了,至于快遞公司將此快遞從哪里運輸到哪里,怎么打包、運輸、運輸的過程產生的油費、運輸的路徑規劃…都不需要我們關心,是由快遞公司負責,我們只需要在規定時間內能收到自己的快遞即可。
5、應用層:拿到這個數據之后我們要干什么。即獲取到數據之后是要進行文件傳輸、郵件發送、還是…其他的,是由應用層說了算的。

對于我們程序員來說,我們和傳輸層、應用層打的交道比較多,因此必須重點掌握傳輸層、應用層的含義、功能、api、使用。

二、網絡中數據傳輸的基本流程——封裝、分用

2.1、封裝

以QQ發送消息為例子:主機A發送消息給主機B,介紹網絡中傳輸數據的基本流程。

主機A的情況:

1、應用層:

QQ應用程序,從輸入框中獲取到我們要傳送的數據,根據應用層協議,構造成應用層數據報,應用層含有很多現成的協議,但很多應用程序中會自定義應用層協議,那么QQ自定義的應用層協議是啥樣的?咱們不知道,只有開發者才知道,因此此處QQ自定義的應用層協議我們通過假設進行舉例子。

假設QQ的應用層協議是這樣自定義的:
發件人的QQ號、接收人的QQ號、時間、消息內容

那么此時就需要將自定義好的應用層協議,構造成應用層數據報構造應用層數據報的過程,就是按照一定格式進行字符串拼接
在這里插入圖片描述

發送方和接收方需要達成一致,發送方使用什么樣的應用層協議進行發送數據,接受方就要使用什么樣的應用層協議接收數據。

應用程序自定義的好應用層協議后,并且構造好應用層數據報后,就會調用傳輸層提供的接口,把應用層數據報(攜帶了應用程序所想發送的消息)交給傳輸層進行處理

2、傳輸層:
傳輸層的現成協議很多,最常用的就是 TCP 協議、UDP 協議,此處假設使用 UDP 協議處理應用層傳過來的的數據報。

UDP 協議就會按照自己的協議格式,生成一個 UDP 數據報:該 UDP 數據報,會將應用層數據報作為自己的載荷部分,并且在載荷部分的前面添加一個 UDP 報頭。

在這里插入圖片描述
UDP 協議不關心應用層數據報里含有什么數據,是什么內容,只是把應用層數據報當作一個字符串,再構造出一個傳輸層數據報。

就像發快遞一樣,假設你想寄的快遞是衣服,你拿到快遞站之后,交給快遞員,快遞員會把你的衣服包裝成一個包裹,然后在上面貼上快遞單,此時你要寄的衣服(相當于應用層數據報)就已經變了一個樣子,變成了一個快遞包裹件,上面有快遞單(此時這個貼了快遞單的包裹,就相當于 UDP 數據報)。只要你郵寄的東西,不管是衣服、還是其他的,只要不違禁,快遞是不會關心你要寄什么東西的,他只負責給你包裝,然后貼單子(這個單子上面就含有快遞的發件人、收件人…這里的發件人、收件人就相當于一個 源端口、目的端口),發出去。

3、網絡層:
網絡層中也含有眾多現成的網絡層協議,最主要的協議的是 IP 協議。 IP協議會根據從傳輸層中收到的 UDP 數據報,構造出 IP 數據報,IP數報中就包含 源IP地址 和 目的IP地址,來確保數據能夠從 源IP地址 正確傳輸到 目的IP 地址。

在這里插入圖片描述
就像我們發快遞一樣,在快遞上貼的快遞單上的發件人地址和收件人地址,就相當于 源IP地址 和 目的IP地址,都是為了確保正確傳輸。

4、數據鏈路層:
數據鏈路層也提供了許多現成的協議,最主要的是 以太網 協議,以太網,又會針對網絡層傳輸來的數據報進行封裝,為IP數據報添上幀頭、幀尾。

以太網也不關心載荷里是啥,只是把載荷當作字符串,進一步的拼接上幀頭、幀尾,構造成以太網數據幀,然后進一步再將以數據鏈路層數據報發送給物理層。
在這里插入圖片描述

5、物理層:
物理層是硬件設備(如網卡),硬件設備需要將上述數據進行轉換,將拼接好的字符串數據轉成二進制數據,通過光信號/電信號/電磁波傳輸。

此時,將數據進行了多層封裝,最終將信號轉成了光信號,在網絡中進行傳輸,主機A就完成了發送過程。

2.2、分用

主機B的情況。

1、物理層:
硬件設備(網卡),收到網絡方傳輸來的光信號/電信號/電磁波,那此時就需要通過調制解調器(貓),針對光信號進行調制解調。

調制:把你要傳輸的信息放到光電信號中。
解調:從光電信號中把信息取出來。

那此時,物理層就通過調制解調器器,將光電信號中的數據取出來,即:以太網的數據幀,這個數據就要被交給上一層,數據鏈路層。

在這里插入圖片描述

2、數據鏈路層
數據鏈路層的以太網協議,就會針對這個數據進行解析,即:將以太網數據幀的幀頭、幀尾去掉,取出其載荷部分,交給上層——網絡層。
在這里插入圖片描述

3、網絡層:
IP協議針對這個數據進行解析:即去掉IP報頭,取出載荷,進一步交給傳輸層。
在這里插入圖片描述

4、傳輸層:
根據IP報頭中的字段,就知道當前這個載荷是一個 UDP 數據報,故將此數據報交給 UDP 協議處理,此時UDP也要針對數據報進行解析,去掉報頭。
在這里插入圖片描述
5、應用層:
UDP報頭中,有一個字段——>目的端口,根據目的端口找到關聯的應用程序,然后將此應用層數據報交給這個程序即可,該程序會根據自定義的應用層協議解析該數據報,然后將數據顯示到界面上。
在這里插入圖片描述
此時,完成上述一系列分用步驟后,QQ中對應的頭像就開始閃爍,點進去,就能顯示出這個消息,以及消息的接收時間等信息…

主機A,從上到下,依次添加報頭的過程,稱為 “封裝”,主機B,從下到上,依次解析報頭的過程,稱為 “分用”,每次網絡傳輸,都需要經歷這個過程。封裝就像是在打包快遞,分用,就像是在拆快遞。

消息轉發到某個設備,每個設備的處理流程都是和上面的封裝分用是一致的。

如果消息轉發到的設備是一個交換機,交換機封裝分用到數據鏈路層即可:交換機解析出以太網數據幀,進一步獲取到幀頭中的 “mac”地址,根據 "mac"地址查詢交換機內部的轉發表,確定接下來數據從哪個網口發出去,在發送之前又會把以太網數據幀封裝好。

如果消息轉發到的設備是一個路由器,路由器封裝分用到網絡層即可:路由器解析出IP數據報,進一步獲取到IP報頭中的I目的P地址,根據目的IP地址進一步規劃接下來要走的路線,然后在發送之前又會把IP數據報封裝好。

2.2.1、5元組

使用 5元組 來描述一次網絡通信:1、源 IP 地址 2、目的 IP 地址 3、源端口號 4、目的端口號。5、協議類型。

三、進行網絡編程

寫一個應用程序,這個應用程序可以使用網絡通信,就需要依靠操作系統給傳輸層協議對外提供的api。傳輸層主要的協議有:TCP、UDP,這兩個協議關于網絡通信方面,提供了兩套完全不同的 api。

傳輸層用于網絡通信的 api 叫做 socket api。

3.1、UDP

3.1.1、UDP 的特點

1、無連接
2、不可靠傳輸
3、面向數據報
4、半雙工

3.2、TCP

3.2.1、TCP 的特點

1、有連接
2、可靠傳輸
3、面向字節流
4、全雙工

3.3 TCP、UDP特點解析

1、什么叫做 無連接?有連接?
譬如說我們在javase時學過的JDBC編程,JDBC是:先創建一個數據源 DataSource,再通過 DataSource 創建 Connection 連接,那么這就是一種 有連接,該連接是抽象的,連接是用來通信時保存對方信息的。

再譬如說,打電話。當我們打電話時,首先按下撥號鍵,直到對方接通為止,才算是完成連接,這也是一種有連接的表現。

那么客戶端與服務器之間進行通信時,使用 內存(本本)保存對端的信息,雙方都保存這個信息,此時 “連接” 就出現了,那么與JDBC的連接、打電話的連接不同的是,一個客戶端可以連接多個服務器,一個服務器也可以對應多個客戶端。

那么像QQ、微信進行發送消息時,是不需要建立連接的,就能直接發送消息進行通信,這是一種 無連接 的變現。

其實除了連接,還有一種叫做 鏈接 的情況,鏈接與連接不同,鏈接相當于一種快捷方式,即:通過一個文件,讓該文件的內容保存另一個文件的路徑,實現的鏈接,一般是軟鏈接(軟件的鏈接)。

2、什么叫 可靠傳輸?什么叫 不可靠傳輸?
可靠傳輸,不是說A給B發消息,100%能到,這個要求太難了,可靠傳輸,就是說,A給B發消息時,會盡可能地將消息傳給B,并且傳輸失敗的時候,A能感知到、或者在傳輸的時候,A能知道自己是否傳輸成功!

譬如說,對于應用程序:釘釘、飛書、企業微信…這些應用程序用到的就是可靠傳輸,即當用戶A給用戶B發消息時,用戶A能夠清楚地感知到用戶B是否接收到消息,如果消息旁邊出現 “已讀”,那就說明用戶B已經收到該消息并且查看了;如果消息旁邊什么都沒有出現,說明當前消息已經通過網絡傳輸到給了用戶B,但是用戶B并沒有點擊查看該消息。

不可靠傳輸即:就像我們平常所用的QQ、微信…這些軟件,當用戶A給用戶B發送了一條消息,無論用戶是否點擊查看了該條消息,該消息的是輸入框旁邊,都不會出現 “已讀” 的提示,因此,用戶A此時就無法判斷當前消息的發送情況。

TCP的特點就是可靠傳輸,但是可靠傳輸的前提是TCP犧牲了傳輸效率,UDP的特點是不可靠傳輸,因此UDP的傳輸效率比TCP高,但是UDP并不能保證消息傳輸過程的可靠性,極易出現丟包、順序顛倒、數據包重復的情況。

3、什么叫做 面向數據報?面向字節流?
面向數據報、面向字節流 這樣的特點是跟代碼的編寫息息相關的,務必要重視的去掌握該知識點。對于 UDP 來說,其在網絡中傳輸數據的基本單位是 數據報,那么一個UDP數據報的格式,是十分重要的,后續會介紹。而TCP在網絡中傳輸數據的基本單位是 字節,就跟文件操作類似,都是 “流” 式的。譬如說,通過 TCP 讀寫 100字節數據,可以一次讀寫 100 字節,也可以分2次讀寫,分別讀寫50字節;也可以分10次讀寫,每次讀寫10字節。

[易錯題]:TCP是可靠傳輸、UDP是不可靠傳輸,因此TCP比UDP更安全?這是正確的還是錯誤的?[錯誤的],談到網絡安全,指的是:你傳輸的數據是否容易被黑客截獲,以及如果被截獲之后是否會泄露一些重要信息,網絡安全是和 安全、入侵、加密、反編譯…有關,而不是和可靠傳輸與否有關。

4、什么叫做 全雙工?半雙工?
全雙工:進行網絡通信的通道可以雙向傳遞數據。
半雙工:進行網絡通信的通道只能單向傳遞數據。

3.4、使用傳輸層協議 TCP/UDP 提供的 socket api 進行網絡通信

3.4.1、UDP—— DatagramSocket、DatagramPacket

UDP提供兩個不同的核心類進行網絡通信:

一、DatagramSocket:

操作系統是使用 文件 這樣的概念,來管理一些軟硬件資源,我們使用一些硬件的網絡設備進行網絡通信時(網卡…),操作系統也是使用 文件 這樣的方式管理網卡這樣的硬件設備,而我們將表示網卡的這類文件,稱為 socket 文件。

Java中的 socket 對象,就對應系統里的 socket 文件,最終落到網卡這樣用于進行網絡通信的硬件設備。

還有一些其他的硬件設備,譬如說:鍵盤、鼠標、顯示器等硬件設備插入電腦上使用時,操作系統也是將這些硬件設備當作 一個一個的 文件 管理起來。

因此,如果我們程序員寫的應用程序,想要進行網絡通信,就必須在代碼中先有 socket 對象。

那么,上述的 DatagramSocket 就是一個 socket 對象。

DatagramSocket 的構造方法:

1、DatagramSocket()
此構造方法是在客戶端處使用,客戶端想要進行網絡通信,也是需要先有一個 socket 對象。客戶端使用哪個端口,不需要客戶端自己指定,而是由系統自動分配,這是因為客戶端大部分是計算機小白,他們自己指定端口號,極易發生端口沖突,造成網絡通信失敗。

2、DatagramSocket(int port)
此構造方法是在服務器端使用的,服務器端需要自己指定端口號,以便客戶端能夠找到當前服務器來進行網絡通信。那為什么服務器端又能夠進行手動指定端口號??此時不怕端口沖突了??這是因為對于服務器端來說,服務器端是由程序員掌控的,因此此時程序員對于服務器上的應用程序的端口號分配情況了如指掌,因此此時指定的端口號是經過考察才分配的,此時就不會造成端口沖突,以至于網絡通信失敗這樣的情況發生了。

當客戶端給服務器發送消息時,對于客戶端來說,客戶端的端口號是源端口號,服務器的端口號是目的端口號;當服務器給客戶端發消息時,對于服務器來說,服務器的端口號是源端口號,客戶端的端口號是目的端口號。

舉個例子理解端口號在網絡通信中的重要作用:
有一天,我去城中街道58號餐廳吃飯。那么這個地址:城中街道58號 就唯一標識了一條街道上的某一家餐廳,因為一個城市,會有許多條街道,一條街道上,會有許許多多的餐館(那么對于一個服務器端來說,一個服務器上,也會有許多應用程序)。此時的 城中街道 就相當于服務器的 IP地址,58號 就相當于 服務器的端口號,而慕名而來吃飯的客人,就相當于客戶端,假如我第一次到這個餐廳里,坐的位置是10號桌,那么下一次來這個餐廳,坐的還是10號桌嗎??不一定了,這個位置是隨機分配的。因此此時 10號 桌 就相當于 客戶端的端口號,不需要客戶端自己指定,而是由系統自動分配即可。

3、DatagramSocket 中提供的用于網絡通信的方法:

1)、void receive(DatagramPacket p)
使用該方法讀取請求并解析,該方法的參數是一個 數據報,**因為 UDP 協議在網絡傳輸數據的基本單位的 數據報。

2)、void send( DatagramPacket p)
使用該方法發送一個數據報,該方法的參數也是一個 數據報。

3)、void close()
通過該方法,關閉 socket 文件,防止出現 文件資源泄露 問題。

二、DatagramPacket

DatagramPacket 表示一個 數據報。

DatagramPacket 的構造方法:

1、DatagramPacket(byte[] buf,int length)
該構造方法代表了系統中設定的 UDP 數據報的二進制結構。該構造方法使用 byte數組來接受數據,因為 DatagramPacket 作為 UDP 數據報,必然要能夠承載一些數據,我們需要通過手動指定 byte[] 作為數據存儲的空間。

2、DatagramPacket(byte[] buf,intt length,SocketAddress address)
該構造方法一般用于發送數據,參數有 byte 數組,用來為發送的數據作承載空間,length表示數據的實際長度,address表示IP地址以及端口號。

3.4.1.1 使用UDP協議編寫回顯服務器

回顯服務器:客戶端發什么、服務器就返回什么。

服務器端代碼:

package UDP.network;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.concurrent.ExecutorService;//回顯服務器
public class UDPEchoServer {private DatagramSocket socket = null;ExecutorService executorService = null;
//    參數是:服務器的端口號,客戶端通過這個服務器的端口號與服務器進行網絡通信public UDPEchoServer(int port) throws SocketException {socket = new DatagramSocket(port);}//    啟動服務器public void start() throws IOException {
//        通過 while 循環反復處理 不知道何時與服務器進行通信的 眾多客戶端System.out.println("[UDPEchoServer] 服務器啟動!");while (true){//            服務器做的3步:
//            1、讀取請求并解析DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);try {socket.receive(requestPacket);} catch (IOException e) {e.printStackTrace();}
//            通過 getData() 獲取數據報中的數據String request = new String(requestPacket.getData(),0,requestPacket.getLength());
//            2、根據請求計算出響應   通過 process() 方法,完成根據請求計算出響應,這一步是最復雜最關鍵的,不同的服務器不同的功能,就是這一步不同String response = process(request);
//            3、返回響應   requestPacket.getSocketAddress():通過這個獲取到客戶端的ip地址以及端口號,這樣就可以將響應返回給特定的客戶端DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,requestPacket.getSocketAddress());try {socket.send(responsePacket);} catch (IOException e) {e.printStackTrace();}
//            打印日志信息System.out.printf("[%s:%d] req:%s,resp:%s\n",requestPacket.getAddress().toString(),requestPacket.getPort(),request,response);}}public String process(String request) {return request;}public static void main(String[] args) throws IOException {UDPEchoServer server = new UDPEchoServer(8909);server.start();}
}

客戶端代碼:

package UDP.network;import java.io.IOException;
import java.net.*;
import java.util.Scanner;//客戶端
public class UDPEchoClient {private DatagramSocket socket = null;private String serverIp;private int serverPort;//    服務器的ip地址,端口號public UDPEchoClient(String ip,int port) throws SocketException {serverIp = ip;serverPort = port;socket = new DatagramSocket();}public void start() throws IOException {System.out.println("[UDPEchoClient] 客戶端啟動!");while (true){
//            從控制臺輸入用戶信息System.out.println("請輸入信息:-> ");Scanner sc = new Scanner(System.in);String request = sc.next();//            再將用戶輸入的信息構造成一個UDP數據報,發送給服務器處理DatagramPacket requestPacket =  new DatagramPacket(request.getBytes(),request.getBytes().length,InetAddress.getByName(serverIp),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 {UDPEchoClient client = new UDPEchoClient("127.0.0.1",8909);
//        UDPEchoClient client = new UDPEchoClient("42.192.83.143",9090);client.start();}
}

端口號,是用來區分主機上不同的應用程序,**一個應用程序可以占據主機上的多個端口號,一個端口只能被一個進程占有(**其實是有特例的,但是一般情況下是在這樣的)。如果應用程序在網絡通信中出現通信異常:SocketException ,一般都是因為當前端口號已經被別的進程占用,此時再嘗試創建這個 socket 對象,占用該端口,就會報錯——編寫網絡通信代碼時,此類異常會很常見!

解析使用UDP編寫回顯服務器代碼:
在這里插入圖片描述
在服務器端的 start() 方法中,使用 while循環來等待并循環處理客戶端的請求,因為一個服務器需要給很多的客戶端提供服務,服務器不知道客戶端什么時候來,服務器只能 “時刻準備著”處理客戶端的請求。

而 socket.receive() 方法中,參數是DatagramPacket,是一個 “輸出型參數”,傳入 receive 的是一個空的 DatagramPacket 對象,receive() 內部會將這個空的 DatagramPacket 對象的內容填充上,當 receive() 執行結束之后,就會得到一個 裝滿內容的 DatagramPacket。

對于 response.getBytes().length 和 response.length()來說,這兩者有什么區別??這很重要,一定不要弄錯。如果當 response 里都是英文字母時,這兩者獲取到的長度是一樣的,但是如果說 response 里是2個漢字時,此時這兩者獲取到的長度就會有差別,一個漢字是3個字節,response.length()此時獲取到的長度是2,而 response.getBytes().length 獲取到的長度是 6。 Socket api 本身,是按照字節來處理數據的。

對于 requestPacket.getSocketAddress() 來說,是用來獲取IP地址和端口號的,DatagramPacket 這個對象里就包含了通信雙方的 IP地址和端口號。

socket對象 就相當于一個 socket 文件,因此 socket 對象用完后,就需要及時關閉,以免造成文件資源泄露問題,導致程序異常。那么此時 socket = new DatagramSocket(port); 來說,是否需要關閉呢??

對于我們當前編寫的這個服務器程序來說,DatagramSocket 不關閉,也是可以的。因為整個程序中,只有這么一個 socket 對象,且不是在頻繁創建的情況下。這個 socket 對象生命周期十分長,伴隨整個程序,此時,socket 就需要保持打開的狀態。

socket 對象 ——>系統中的 socket 文件——>文件描述符(文件描述符即表示當前進程所占有的文件,進程每打開一個文件,就會生成一個文件描述符)(關閉 socket 對象的主要原因,就是因為要釋放文件描述符),但是因為我們此時程序中只有一個 socket 對象,且生命周期伴隨整個程序,此時無需手動關閉,只需要等待進程結束后,系統將PCB回收后,PCB里的文件描述符表字段也就被銷毀了。

僅限于,只有一個 socket 對象,并且生命周期是跟隨整個進程。如果是含有多個 socket 對象,并且 socket 對象的生命周期短,需要頻繁創建、釋放,就必須去關閉 socket!

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

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

相關文章

基于大模型和RAG技術實現的開源項目

基于大模型和RAG技術實現的開源項目 為解決大模型的不足,使用RAG技術增強大模型生成內容的針對性和可讀性能力,有很多不錯的開源項目。例如下面的項目。 1 ragflow 優點:可以對文檔和知識庫進行管理,構建不同的知識庫&#xff…

python冰雹序列的探索與編程實現

新書上架~👇全國包郵奧~ python實用小工具開發教程http://pythontoolsteach.com/3 歡迎關注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目錄 一、冰雹序列的奧秘 二、編程實現冰雹序列 三、測試與驗證 四、總結與展望 一、冰雹序列的…

整理好了!2024年最常見 20 道 Redis面試題(八)

上一篇地址:整理好了!2024年最常見 20 道 Redis面試題(七)-CSDN博客 十五、Redis 的性能調優有哪些方法? Redis的性能調優是一個多方面的工作,涉及到硬件、配置、代碼層面的優化等多個方面。以下是一些常…

openEuler 22.03 LTS SP3源碼編譯部署OpenStack-Caracal

openEuler 22.03 LTS SP3源碼編譯部署OpenStack-Caracal 說明機器詳情安裝操作系統注意事項基礎準備Controller節點 && Compute節點 && Block節點關閉防火墻關閉selinux設置靜態IP更新安裝前準備Controller節點 && Compute節點 && Block節點設…

第十課,while循環

一,認識循環是什么 循環普遍存在于日常生活中,同樣,在程序中,循環功能也是至關重要的基礎功能。 當程序需要重復執行某一段代碼,利用循環可以輕松完成工作 例如我要你打印100次上課,直接寫100次print&…

python調用阿里云通義千問(q-wen-max)API-只能總結pdf文檔內容

文章目錄 通義千問插件PDF解析插件調用案例通義千問插件 Dashscope插件功能能夠使得大模型的生成內容與外部三方應用結合,使得模型生成的內容更加準確和豐富,模型將擁有更好的生成能力。您也可以通過開發自定義插件,來使得模型生成更符合您預期的結果。 使用插件功能,大模…

電子閱覽室在管理時需注意什么

關于如今的絕大多數人來說,想必都聽說過“電子閱覽室”這一概念。它首要運用在校園中,給學生們供給愈加豐厚的常識儲藏。它也是一個獨立的局域網,在校園網絡中作為重要的一個組成部分而存在。但是,一個好的電子閱覽室是需求滿意運…

LORA學習筆記3——訓練參數

訓練步長 Step(步):模型訓練時ai模型會根據標注生成一個圖片,并與學習圖片進行對比,通過對比的結果調整嵌入向量。這樣的一個流程就被稱為“一步”。 如果一個訓練集中有50張圖片,每張圖片設定為要訓練10次&#xff…

CCF20231201——倉庫規劃

CCF20231201——倉庫規劃 代碼如下&#xff1a; #include<bits/stdc.h> using namespace std; int main() {int n,m,a[1001][11],b[1001]{0};cin>>n>>m;for(int i1;i<n;i){for(int j1;j<m;j)cin>>a[i][j];}for(int i1;i<n;i){bool foundfals…

設計模式在芯片驗證中的應用——模板方法

一、模板方法 模板方法(Template Method)設計模式是一種行為設計模式&#xff0c; 它在父類中定義了一個功能的框架&#xff0c; 允許子類在不修改結構的情況下重寫功能的特定步驟。也就是模板方法定義了一組有序執行的操作&#xff0c;將一些步驟的實現留給子類&#xff0c;同…

把自己的垃圾代碼發布到官方中央倉庫

參考博客&#xff1a;將組件發布到maven中央倉庫-CSDN博客 感謝這位博主。但是他的步驟有漏缺&#xff0c;相對進行補充 訪問管理頁面 網址&#xff1a;Maven Central 新注冊賬號&#xff0c;或者使用github快捷登錄&#xff0c;建議使用github快捷登錄 添加命名空間 注意&…

連接mysql的java代碼

要在Java中連接MySQL數據庫,你需要以下幾個步驟: 導入MySQL JDBC驅動:在項目中添加MySQL JDBC驅動的依賴。如果你使用的是Maven,可以在pom.xml中添加依賴;如果使用的是Gradle,可以在build.gradle中添加依賴;如果不使用構建工具,需要手動下載驅動并添加到項目中。 編寫J…

【Linux】進程通信實戰 —— 進程池項目

送給大家一句話: 沒有一顆星&#xff0c;會因為追求夢想而受傷&#xff0c;當你真心渴望某樣東西時&#xff0c;整個宇宙都會來幫忙。 – 保羅?戈埃羅 《牧羊少年奇幻之旅》 &#x1f3d5;?&#x1f3d5;?&#x1f3d5;?&#x1f3d5;?&#x1f3d5;?&#x1f3d5;? &a…

flink cdc mysql整理與總結

文章目錄 一、業務中常見的需要數據同步的場景CDC是什么FlinkCDC是什么CDC原理為什么是FlinkCDC業務場景flink cdc對應flink的版本 二、模擬案例1.阿里云flink sql2.開源flink sql(單機模式)flink 安裝安裝mysql3.flink datastream 三、總結 提示&#xff1a;以下是本篇文章正文…

mac中文件夾怎么顯示.git隱藏文件

1. 打開終端應用程序&#xff0c;然后進入到包含.git文件夾的目錄&#xff0c;可以使用以下命令來顯示隱藏文件和文件夾&#xff1a; defaults write com.apple.finder AppleShowAllFiles YES 2. 然后重啟 Finder&#xff1a; killall Finder

kali基本掃描工具(自帶)

免責聲明:本文僅做技術交流與學習...請勿非法破壞... 詳細用法: 命令 -h/百度/翻譯 fping 用法 hostlist 文件里面為ip fping -a -q -f hostlist -a 只看存活的 fping -g 202.100.1.1 202.100.1.255 -a -q > Ahost 輸出到Ahost文件上 nping nping -c 1 201.100.2.155-244 …

工具方法 - 如何在網上找資料

在查詢USB相關的技術資料時&#xff0c;官網的文檔中心里找到個spec的記錄&#xff0c;但下載鏈接沒有。然后在Google上搜索&#xff1a; fileytpe:pdf my_keyword 只找到一個收費的文檔下載網站&#xff0c;這讓我不開心。 于是在Yandex上搜了下&#xff0c;找到了兩個網站可以…

香橙派AIpro使用SSH遠程登錄

香橙派AIpro可以連接HDMI顯示器使用&#xff0c;也可以遠程登錄。這里采用MobaXterm軟件遠程登錄開發板。 首先要使得控制電腦和香橙派開發板連接到同一個局域網&#xff0c;兩者的IP地址能夠ping通。在Windows 下可以使用MobaXterm 遠程登錄開發板&#xff0c;首先新建一個ss…

屬于程序員的浪漫,一顆會跳動的心!!!

繪制一顆會跳動的心? 嘿嘿 可以說是程序員的專屬浪漫了吧&#xff0c;就像點燃一顆LED燈一樣&#xff1f;&#xff08;我瞎說的啊&#xff0c;大家別當真&#xff0c;我很菜的&#xff01;&#xff01;&#xff01;&#xff01;&#xff09; 程序就在下面啦&#xff0c;然…

hive結合Hbase實現實時數據處理和批量分析

問題背景 Hive主要設計為一個用于大數據集的批處理查詢引擎&#xff0c;并不是為實時查詢或實時數據更新而設計的。它主要用于執行數據摘要、查詢和分析。因此&#xff0c;Hive本身不支持實時數據更新或實時查詢&#xff0c;它更適合用于對大量數據進行批量處理和分析。 分析…