Linux:TCP協議

TCP是一個面向連接的、可靠的、基于字節流的傳輸層協議。文次我們會通過介紹TCP的報頭并通過分析各字段的用途來進一步解釋其核心特性:

  • 可靠傳輸:?有確認應答、超時重傳、確保有序。

  • 流量控制和擁塞控制:?動態調節發送速率,防止丟包與擁塞。

  • 面向連接:?通過“三次握手”建立連接,“四次揮手”斷開連接。

TCP報頭

源/目的端口號:

標識唯一的發送方和接收方進程?

32 位序號Seq:

體現基于字節流特性和可靠性:表示本報文段所攜帶數據的第一個字節在整個字節流中的編號。TCP將應用層交付的數據視為連續的字節流,并為每個字節編號。接收端TCP利用序列號將可能亂序到達的報文段重新排序,確保數據按正確的順序交付給應用層。

32 位確認號Ack:?

(1)體現可靠性 (確認機制):?當ACK標志位為1時,該字段才有效。它表示接收方期望收到的下一個字節的序列號。

(2)也用于流量控制

4 位 TCP 報頭長度:

表示該 TCP 頭部有多少個 4 字節,最小值為5(對應20字節標準報頭),最大值為15(對應60字節報頭)

4位保留未用:必須置為0

6 位標志位:

○ URG: 緊急指針是否有效,一般沒用

ACK: 確認號是否有效,絕大多數報文段都攜帶ACK

○ PSH: 提示接收端應用程序立刻從 TCP 緩沖區把數據讀走

○ RST: 對方要求重新建立連接,通常在發生嚴重錯誤或拒絕連接請求時使用; 我們把攜帶 RST 標識的稱為復位報文段

SYN: 請求建立連接,在三次握手中用于同步序列號; 我們把攜帶 SYN 標識的稱為同步報文段

FIN: 表示發送方數據已發送完畢,請求終止連接,用于四次揮手關閉連接; 我們稱攜帶 FIN 標識的為結束報文段

16 位窗口大小:

用于流量控制:?表示接收方當前愿意接收的數據量(以字節為單位),即接收窗口的大小。發送方根據這個值動態調整自己發送數據的速率,確保不會淹沒接收方,防止接收緩沖區溢出。這是TCP實現端到端流量控制的關鍵機制。

16 位校驗和:

發送端填充, CRC 校驗.

接收端校驗不通過, 則認為數據有問題

此處的檢驗和不光包含 TCP 首部, 也包含 TCP 數據部分.

16 位緊急指針:

標識哪部分數據是緊急數據;

40 字節頭部選項: 暫時忽略;

可靠傳輸

確認應答

在進行tcp通信時,發送方每發送一個報文,接收方就必須給接收方發一個ACK應答報文,表示“Ack序號之前的數據我收到了”(ACK是一個標識位;Ack就是確認序號,可以認為是緩沖區上的一個指針,而序號Seq同樣是一個指針),這保證了發送方能掌握接收方的接收狀態,避免盲目發送(如接收方網絡中斷,發送方還在發送),保證了通信時的可靠性,同時還與下文的滑動窗口、超時重傳、快速重傳有密切關系(通過Ack來判斷哪一部分數據丟包)

快速重傳

如果連續三次接收方都給發送方應答同一個ACK,那么接收方就會認為該ACK對應的報文丟失,會進行重發

超時重傳

如果發送方發送報文后一段時間內接收方沒有應答,接收方就會認為發送的報文丟失,會進行重復發送。那么如何確定該過多長時間沒收到應答才認為是丟包呢,這個時間如果太短會導致網絡環境較差時頻繁發送重復數據,太長又降低了整體的重傳效率,因此一般會動態計算超時時間:

Linux 中(BSD Unix 和 Windows 也是如此), 超時以 500ms 為一個單位進行控制, 每次判定超時重發的超時時間都是 500ms 的整數倍.

如果重發一次之后, 仍然得不到應答, 等待 2*500ms 后再進行重傳.

如果仍然得不到應答, 等待 4*500ms 進行重傳. 依次類推, 以指數形式遞增.

累計到一定的重傳次數, TCP 認為網絡或者對端主機出現異常, 強制關閉連接

滑動窗口

一方面,由于發送方每發送一個報文都需要接收方進行應答,這使得高延遲網絡下雙方通信效率較低;另一方面,如果發送方發送數據過快,接收方來不及將新報文放入接收緩沖區,只能將其丟棄。為此就需要一種機制動態地調節傳輸速率——滑動窗口

滑動窗口首先允許發送方連續發送多個報文(無需逐個等待ACK),顯著提高了傳輸效率。

這個過程中即使應答報文丟失了也沒關系,因為還會有后續的應答報文。

隨后又將發送/接收緩沖區進行劃分:

發送方:

已確認發送|發送窗口|未發送

  • SND.WND: 表示發送窗口的大小, 上圖虛線框的格子數是 10 個,即發送窗口大小是 10。

  • SND.NXT:下一個發送的位置,它指向未發送但可以發送的第一個字節的序列號。

  • SND.UNA: 一個絕對指針,它指向的是已發送但未確認的第一個字節的序列號。

發送方在收到應答報文時,需要將確認號Ack與自己的窗口范圍進行對比:

  • 若?Ack?不在?[SND.UNA,SND.NXT]?范圍內→?無效ACK,直接忽略。

  • 若?Ack > SND.UNA?→?新數據被確認,更新?SND.UNA = Ack。

  • 若?Ack == SND.UNA?→?重復ACK(可能數據丟失或亂序),

  • 累計重復次數:若重復ACK ≥ 3次?→ 觸發快速重傳(重傳?SND.UNA?對應的數據包)。

  • 若?Ack < SND.UNA→?過期的ACK(確認已確認的數據),直接忽略。

那么接收方的Ack又是如何更新的呢:

接收方:

已確認收到|接收窗口|未收到

  • REV.WND: 表示接收窗口的大小, 上圖虛線框的格子就是 9 個。

  • REV.NXT: 下一個接收的位置,它指向未收到但可以接收的第一個字節的序列號。

當Seq<RCV.NXT時(重復數據),直接丟棄報文,窗口不變,Ack不變

當Seq==RCV.NXT時(按序到達),Ack=RCV.NXT=RCV.NXT+len,窗口縮小

當Seq>RCV.NXT時(亂序數據),RCV.NXt和Ack不變,將數據緩存,窗口縮小,REV.WND-=len

而當應用層將數據從緩沖區取出時,窗口則會變大

流量控制

有了滑動窗口機制,我們就可以通過控制窗口大小來限制傳輸速率

接收方通過 TCP 報頭的窗口大小字段,動態告知發送方其剩余接收緩沖區容量;

窗口大小字段越大, 說明網絡的吞吐量越高;

接收端一旦發現自己的緩沖區快滿了, 就會將窗口大小設置成一個更小的值;

發送端接收到這個窗口之后, 就會減慢自己的發送速度;

如果接收端緩沖區滿了, 就會將窗口置為 0;

這時發送方不再發送數據, 但是需要定期發送一個窗口探測數據段, 強制接收方應答并把接窗口大小告訴發送端

擁塞控制

由于可能同時有大量的計算機在網絡上進行通信,大家同時發送大量的數據, 很有可能導致甚至加重網絡擁堵;為此,TCP引入慢啟動機制, 先發少量的數據,摸清當前的網絡擁堵狀態, 再決定按照多大的速度傳輸數據;

此處引入一個概念稱為擁塞窗口

發送開始的時候, 定義擁塞窗口大小為 1;

每次收到一個 ACK 應答, 擁塞窗口大小乘2;

每次發送數據包的時候, 將擁塞窗口和接收端主機反饋的窗口大小做比較, 取較小的值作為實際發送的窗口

像上面這樣的擁塞窗口增長速度, 是指數級別的

"慢啟動" 只是指初使時慢, 但是增長速度非常快.

為了不增長的那么快, 因此不能使擁塞窗口單純的加倍.

此處引入一個叫做慢啟動的閾值

當擁塞窗口超過這個閾值的時候, 不再按照指數方式增長, 而是按照線性方式增長

當 TCP 開始啟動的時候, 慢啟動閾值等于窗口最大值;

在每次超時重發的時候, 慢啟動閾值會變成原來的一半, 同時擁塞窗口置回1;

少量的丟包, 我們僅僅是觸發超時重傳;

大量的丟包, 我們就認為網絡擁塞;

當 TCP 通信開始后, 網絡吞吐量會逐漸上升;

隨著網絡發生擁堵, 吞吐量會立刻下降;

擁塞控制, 歸根結底是 TCP 協議想盡可能快的把數據傳輸給對方, 但是又要避免給網絡造成太大壓力的折中方案.

應答的優化策略

延遲應答

由于接收方收到消息時,窗口會變小,此時如果立刻應答,會使得發送方發過來的報文變小(進行流量控制),可是很多時候,接收方的處理速度很快,可能窗口雖然在接收報文時變小了,但很快就會恢復。因此,實際上發送方可能會低估接收方的接收能力,進而降低傳輸效率。

所以,為了提高傳輸效率,采用延遲應答機制:減少應答次數和接收到消息后過一定時間才應答

那么這個延遲應答時間應該是多少呢:顯然不能超過500ms,因為這會與超時重傳產生沖突,導致接收方明明收到消息了卻被發送方認為是丟包了。一般來說,這個時間是200ms。

捎帶應答

很多時候tcp通信不是一方發送一方接收,而是雙方都在發送都在接受,這時候雙方不僅要發自己的消息,還要頻繁應答對方(而發送的信息僅僅是一個ACK和確認號和窗口大小,這顯然有些浪費),因此,為了提高通信效率,當進行雙向通信時,發送方(同時也是接收方)會把這次要發的報文和上次接收數據的應答報文合二為一發送給對方,這也是為什么大多數報文都會攜帶ACK應答

面向連接

三次握手

tcp通信在連接時需要先進行“三次握手”,其目的為:

1.確保雙方的接收能力和發送能力正常

2.同步雙方序列號seq

第一次握手前,雙方均處于CLOSED狀態,表示斷開;服務端調用listen()后進入LISTEN狀態,表示等待連接

第一次握手:

客戶端調用connect()向指定服務端發起連接請求并向服務端發送SYN報文請求連接并發送Seq序(假設值為x,因為并沒有發送任何數據,所以這個是隨機生成的)

客戶端進入SYNC-SENT狀態

此時服務端已知曉自己的接收功能正常,對方的發送功能正常,服務端進入SYNC-RCVD狀態

第二次握手:

服務端向客戶端發送SYN報文表示同意連接,并捎帶應答ACK報文;發送Seq序號(假設值為y,由于沒有發送任何數據,也是隨機生成的)和Ack確認序號(值為x+1,你可能疑惑不是沒有發送數據嗎,為什么確認序號還要加1,這是因為TCP 協議規定SYN報文雖然不攜帶數據, 但是也要消耗1個序列號)

此時,客戶端已知曉自己的發送和接收功能正常(因為收到了服務端應答,說明自己的消息成功發出,也說明自己能收到服務端的消息),也知曉服務端的發送和接收功能正常(因為服務端收到了自己的連接請求并成功應答);

但服務端尚不知道自己的發送功能和對方的接收功能是否正常(因為對方還沒有應答)因此需要第三次握手:

第三次握手:

客戶端發送ACK報文應答,并發送Seq序號(值為x+1)和Ack確認序號(值為y+1)

至此服務端收到消息,確認了自己的發送功能和對方的接收功能,雙方都進入ESTABLISHED狀態,表示已連接可以正常通信

四次揮手

tcp在斷開連接時,要進行四次揮手,其目的為:確保雙方數據完整傳輸并安全釋放資源

其中FIN信號表示不再發送數據,但仍可以接收數據

由于更多情況下是客戶端主動斷開連接(如關閉瀏覽器),所以這里我們認為客戶端是主動斷開連接的一方,服務端是被動斷開連接的一方,當然服務端也有可能是主動都斷開的連接的一方,下文會提到

第一次揮手:

客戶端調用close()函數,向服務端發送FIN報文表示準備斷開連接,并發送Seq序號(由于沒有數據,因此是隨機生成的,假設值為u)

客戶端進入FIN_WAIT-1狀態,關閉應用層動作(不再發送應用層的數據)

第二次揮手:

服務端發送ACK應答報文,并發送Ack確認序號(值為u+1,你可能疑惑不是沒有發送數據嗎,為什么確認序號還要加1,這是因為TCP 協議規定FIN報文雖然不攜帶數據, 但是也要消耗1個序列號)和Seq序號(由于沒有數據,因此是隨機生成的,假設值為v)

服務端進入CLOSE_WAIT狀態,關閉內核動作(無法讀取緩沖區中的數據)

客戶端進入FIN_WAIT_2狀態(這是一個半關閉狀態,不能發送,但可以接收)

第三次揮手:

服務端調用close()函數,向服務端發送FIN報文,并發送Ack確認序號(值為u+1)和Seq序號(假設值為w,若第二次揮手后到第三次揮手前,服務端向客戶端發送了數據,則w>v;否則w=v)

服務端進入LAST_ACK狀態,關閉應用層動作(不再發送應用層的數據)

第四次揮手:

客戶端發送ACK應答報文并發送確認序號Ack(值為w+1)和序號Seq(值為u+1)

客戶端進入TIME_WAIT狀態,關閉內核動作(無法讀取緩沖區中的數據),并等待一段時間確保對方收到應答報文

服務端收到報文后進入CLOSE狀態,連接斷開

TIME_WAIT

為什么客戶端在第四次揮手后,還要等待一段時間呢:這是因為,如果該報文丟失,服務端會超時重發第三次揮手的報文,客戶端收到后又會發送第四次揮手的報文;這樣確保了服務端能收到第四次報文

這里還存在一種情況:大量TIME_WAIT狀態堆積

服務器需要處理非常大量的客戶端的連接(每個連接的生存時間可能很短, 但是每秒都有很大數量的客戶端來請求)

這個時候如果由服務器端主動關閉連接(比如某些客戶端不活躍, 就需要被服務端主動清理掉), 就會產生大量 TIME_WAIT 連接

由于我們的請求量很大, 就可能導致 TIME_WAIT 的連接數很多, 每個連接都會占用一個通信五元組(源 ip, 源端口, 目的 ip, 目的端口, 協議). 其中服務器的 ip 和端口和協議是固定的

如果新來的客戶端連接的 ip 和端口號和 TIME_WAIT 占用的重復了, 就會出現問題,造成服務端bind失敗,一個解決方法使用 setsockopt()設置 socket 描述符的 選項 SO_REUSEADDR 為 1, 表示允許創建端口號相同但 IP 地址不同的多個 socket 描述符

CLOSE_WAIT

CLOSE_WAIT表示:?本地(已經收到了對端發來的?FIN?包(關閉請求),并且已經回復了?ACK(確認收到)。本地已經知道對端沒有數據要發送了。

它在等待:?本地應用程序(通常是服務器端的服務進程)執行?close()?系統調用,關閉自己的套接字。只有應用程序調用了?close(),操作系統內核才會發送?FIN?包給對端。

這里可能存在一個問題:大量CLOSE_WAIT狀態堆積

如果服務端無法正常調用close函數關閉連接,可能會導致大量CLOSE_WAIT狀態堆積,占用文件描述符和內存,這時就需要調試尋找沒有正常關閉連接的原因。

為什么是四次揮手

你可能會疑惑,為什么斷開連接時,第二次揮手(服務端應答)和第三次揮手(服務端發送FIN報文)為什么不能合二為一(像三次握手中的第二次握手一樣,發送SYN報文的同時捎帶應答ACK報文)。這是因為客戶端發送FIN報文是表示自己不想再發送數據了,但此時服務端可能還有數據沒有發完,需要一些時間。因此,第二次揮手和第三次揮手有一定時間差,不能合二為一;同時,如果在這期間服務端又向客戶端發送了數據的話,兩次的確認序號也可能不同。

面向字節流

TCP的面向字節流是通過發送緩沖區和接收緩沖區來實現的,這使得其相較于UDP具有以下優勢:

  1. 有序性:盡管字節流在傳輸過程中會被分割成多個報文段,并且這些報文段可能亂序到達、丟失、重傳,TCP 協議保證了接收緩沖區中的字節流順序與發送緩沖區中的字節流順序完全一致。接收方應用讀取到的字節順序就是發送方寫入的字節順序。

  2. 可靠性:TCP 保證,只要連接沒有異常中斷,發送方寫入發送緩沖區的每一個字節最終都會按順序出現在接收方的接收緩沖區中,不會丟失、不會重復、不會出錯(通過校驗和、確認、重傳、序列號等機制實現)。

  3. 緩沖區機制平滑了應用層讀寫速度與網絡傳輸速度之間的差異(可以進行流量控制)。

但這也導致其沒有消息邊界(UDP是面向報文發送,有天然的消息邊界),進而催生了粘包和拆包兩個問題:

粘包問題:發送方多次寫入的較小數據塊,可能被 TCP 合并成一個較大的報文段發送

拆包問題:發送方寫入的一個較大數據塊,可能被 TCP 拆分成多個較小的報文段發送

這里舉一個例子:

發送方分別發送"Hello"和"World"

接收方讀取緩沖區中的內容,?返回 “HelloWorld”。

又或者是發送方分別發送 “HelloWorld

接收方讀取緩沖區中的內容,?返回”"Hello"和"World"。

為了解決這一問題,需要明確兩個包之間的邊界:

對于定長的包, 保證每次都按固定大小讀取即可;

對于變長的包, 可以在包頭的位置, 約定一個包總長度的字段, 從而就知道了包的結束位置;

對于變長的包, 還可以在包和包之間使用明確的分隔符(應用層協議來定, 只要保證分隔符不和正文沖突即可);

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

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

相關文章

uniapp使用map打包app后自定義氣泡不顯示解決方法customCallout

前言&#xff1a;使用uniapp開發后在小程序可以正常顯示&#xff0c;但是運行打包成App后就不顯示了&#xff0c;其實這一塊對于uniapp框架開發來說&#xff0c;是有系統性的bug&#xff0c;如果你再開發時使用的是vue文件進行&#xff0c;就會出現這個問題。解決方法&#xff…

【typenum】 22 類型級別二進制對數運算(Logarithm2)

一、源碼 這段代碼實現了一個類型級別的二進制對數運算系統 定義&#xff08;type_operators.rs&#xff09; /// A **type operator** for taking the integer binary logarithm of Self. /// /// The integer binary logarighm of n is the largest integer m such /// that …

golang 非error錯誤分類

1.應用級別&#xff0c;可recover這些 panic 一般是 邏輯或使用不當導致的運行時錯誤&#xff0c;Go 程序可以用 recover 捕獲并繼續運行&#xff1a;類型示例描述類型不一致atomic.Value 存不同類型 v.Store(100); v.Store("abc")panic: store of inconsistently ty…

【Ansible】變量與敏感數據管理:Vault加密與Facts采集詳解

1. 變量Ansible利用變量存儲可重復使用的值&#xff0c;可以簡化項目的創建和維護&#xff0c;減少錯誤數量。1.1 變量名稱由字符串組成&#xff0c;必須以字母開頭&#xff0c;并且只能含有字母、數字和下劃線&#xff0c;和其它編程語言很類似。1.2 常見變量要創建的用戶要安…

ROS2下YOLO+Moveit+PCL機械臂自主避障抓取方案

整體運行架構 1.運行相機取像節點 . ./install/setup.bash ros2 launch orbbec_camera gemini_330_series.launch.py depth_registration:true 2.運行根據圖像x,y獲取z的service 基本操作記錄&#xff1a; 創建python包,在src目錄下 ros2 pkg create test_python_topic --bu…

快速入門Vue3——初體驗

目錄 前言 一、搭建環境 1.1、安裝Node.js 1.2、安裝Vite 二、項目創建 三、運行項目 四、集成Pinia 4.1、Pinia介紹 4.2、Pinia安裝 五、集成VueUse 5.1、vueuse簡介 5.2、vueuse安裝 六、集成Vant 6.1、Vant簡介 6.2、Vant安裝 前言 本專欄主要介紹如何使用…

深入理解Kubernetes核心:標簽與標簽選擇器實戰解析

在管理 Kubernetes 集群時&#xff0c;隨著 Pods、Services 等資源數量的增長&#xff0c;如何有效地組織和篩選它們&#xff0c;成為了一個核心問題。Kubernetes 為此提供了一個簡單卻極其強大的機制&#xff1a;標簽&#xff08;Labels&#xff09;和標簽選擇器&#xff08;L…

哈希和字符串哈希

哈希&#xff08;Hash&#xff09; Hash 表 Hash 表又稱為散列表&#xff0c;一般由 Hash 函數&#xff08;散列函數&#xff09;與鏈表結構共同實現。與離散化思想類似&#xff0c;當我們要對若干復雜信息進行統計時&#xff0c;可以用 Hash 函數把這些復雜信息映射到一個容…

【Docker基礎】Docker-Compose核心配置文件深度解析:從YAML語法到高級配置

目錄 前言 1 YAML基礎語法解析 1.1 YAML格式簡介 1.2 Docker-compose中的YAML語法規則 1.3 YAML數據類型在Compose中的應用 2 docker-compose.yml文件結構剖析 2.1 基本文件結構 2.2 版本聲明詳解 3 services配置深度解析 3.1 服務定義基礎 3.2 鏡像與構建配置 3.3…

如何判斷是否應該為了一個小功能而引入一個大體積的庫

在軟件開發中&#xff0c;判斷是否應該為了一個看似微小的功能&#xff0c;而引入一個大體積的第三方庫&#xff0c;是一項極其重要的、需要進行審慎的“投入產出比”分析的技術決策。這個決策&#xff0c;絕不能&#xff0c;僅僅基于“實現功能的便利性”&#xff0c;而必須&a…

相機定屏問題分析五:【跳幀異常】照片模式1x以上的焦段拍照之后定屏

【關注我&#xff0c;后續持續新增專題博文&#xff0c;謝謝&#xff01;&#xff01;&#xff01;】 上一篇我們講了&#xff1a; 這一篇我們開始講&#xff1a; 相機定屏問題分析五&#xff1a;【跳幀異常】照片模式1x以上的焦段拍照之后定屏9573412 目錄 一、問題背景 二…

Non-stationary Diffusion For Probabilistic Time Series Forecasting論文閱讀筆記

Non-stationary Diffusion For Probabilistic Time Series Forecasting 摘要 時間序列數據受到潛在的物理動力學和外部影響&#xff0c;其不確定性通常隨時間而變化。現有的去噪擴散概率模型&#xff08;DDPMs&#xff09;受到加性噪聲模型&#xff08;ANM&#xff09;的恒定方…

解決Docker 無法連接到官方鏡像倉庫

這個錯誤&#xff1a; Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)表示 Docker 無法連接到官方鏡像倉庫 registry-1.docker…

解決RAGFlow啟動時Elasticsearch容器權限錯誤的技術指南

文章目錄 問題現象 根本原因分析 解決方案步驟 1. 定位宿主機數據目錄 2. 修復目錄權限 3. 驗證權限狀態 4. 重啟服務 5. 檢查啟動狀態 永久解決方案:優化Docker Compose配置 高級故障排除 技術原理 問題現象 在啟動RAGFlow項目時,執行 docker logs ragflow-es-01 發現Elast…

【C++高階六】哈希與哈希表

【C高階六】哈希與哈希表1.什么是哈希&#xff1f;2.unordered系列容器3.哈希表3.1將key與存儲位置建立映射關系3.1.1直接定址法3.1.2除留余數法&#xff08;產生哈希沖突&#xff09;3.2解決哈希沖突的方法3.2.1閉散列&#xff08;開放定址法&#xff09;3.3.2開散列&#xff…

Vue 3 +Ant Design Vue 父容器樣式不影響子級,隔離

公共樣式文件 common.scss.zz-ant-status-bar {div {font-size: 12px;padding: 0 8px;} }頁面代碼<div class"zz-ant-status-bar"><a-row><a-col :span"6" ><a-progress :percent"progress.percent" size"small"…

k8s 簡介及部署方法以及各方面應用

Kubernetes 簡介及部署方法Kubernetes&#xff08;簡稱 K8s&#xff09;是一個開源的容器編排平臺&#xff0c;用于自動化容器化應用的部署、擴展、管理和運維。它由 Google 基于內部的 Borg 系統經驗開發&#xff0c;2014 年開源后由云原生計算基金會&#xff08;CNCF&#xf…

Class A 包含字段 x Class B 也包含字段 x,如果判斷List<A> lista 和 List<B> listb 有相同的 x?

要判斷兩個不同類型的對象列表 List<A> 和 List<B> 是否包含相同的 x字段值&#xff08;即兩個列表中至少有一個 x是相同的&#xff09;&#xff0c;你可以使用 Java 8 的 Stream API 來實現。import java.util.List; import java.util.Set; import java.util.stre…

SpringBoot整合Camunda工作流

什么是工作流&#xff1f;概述 工作流是將一組任務組織起來以完成某個經營過程&#xff1a;定義了任務的觸發順序和觸發條件&#xff0c;每個任務可以由一個或多個軟件系統完成&#xff0c;也可以由一個或一組人完成&#xff0c;還可以由一個或多個人與軟件系統協作完成&#x…

2025年09月計算機二級Java選擇題每日一練——第四期

計算機二級中選擇題是非常重要的&#xff0c;所以開始寫一個每日一題的專欄。 答案及解析將在末尾公布&#xff01; 今日主題&#xff1a;面向對象特性 1、有兩個類 A 和 B 的定義如下&#xff1a; class A{final int x10;public void show(){System.out.print(x " &quo…