網絡基礎2-3(TCP協議,三次握手,四次揮手,TIME_WAIT狀態的作用,TCP如何保證可靠傳輸,TCP連接中狀態轉化,滑動窗口,流量控制,快速重傳,擁塞窗口,延遲應答,捎帶應答,粘包問題)

TCP協議

TCP協議概念

TCP全稱為 “傳輸控制協議(Transmission Control Protocol”). 人如其名, 要對數據的傳輸進行一個詳細的控制

TCP協議格式

在這里插入圖片描述

1. 源/目的端口號: 表示數據是從哪個進程來, 到哪個進程去;
2. 32位序號/32位確認號: 后面詳細講;
3. 4位TCP報頭長度: 表示該TCP頭部有多少個32位bit(有多少個4字節); 所以TCP頭部大長度是15 * 4 = 60
4. 6位標志位:
  1. URG: 緊急指針是否有效
  2. ACK: 確認號是否有效
  3. PSH: 提示接收端應用程序立刻從TCP緩沖區把數據讀走
  4. RST: 對方要求重新建立連接; 我們把攜帶RST標識的稱為復位報文段
  5. SYN: 請求建立連接; 我們把攜帶SYN標識的稱為同步報文段
  6. FIN: 通知對方, 本端要關閉了, 我們稱攜帶FIN標識的為結束報文段
5. 16位窗口大小
6. 16位校驗和

發送端填充, CRC校驗. 接收端校驗不通過, 則認為數據有問題. 此處的檢驗和不光包含TCP首部, 也 包含TCP數據部分.

7. 16位緊急指針

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

8. 40字節頭部選項

三次握手和四次揮手圖示

在這里插入圖片描述

關于TCP協議的重點問題

1. 三次握手建立連接以及四次揮手斷開連接的流程?

在這里插入圖片描述

三次握手過程

當客戶端調用connect時,觸發了連接請求,向服務器發送了SYN X包,這時connect進入阻塞狀態;服務器監聽到連接請求,即收到SYN X包,調用accept函 數接收請求向客戶端發送SYN K ,ACK X+1,這時accept進入阻塞狀態;客戶端收到服務器的SYN K ,ACK X+1之后,這時connect返回,并對SYN K進行確認;服務器收到ACK K+1時,accept返回,至此三次握手完畢,連接建立。

總結:客戶端的connect在三次握手的第二個次返回,而服務器端的accept在三次握手的第三次返回。

四次揮手

在這里插入圖片描述

  1. 某個應用進程首先調用close主動關閉連接,這時TCP發送一個FIN M;
  2. 另一端接收到FIN M之后,執行被動關閉,對這個FIN進行確認。它的接收也作為文件結束符傳遞給應用進程,因為FIN的接收意味著應用進程在相應的連接上再也接收不到額外數據;
  3. 一段時間之后,接收到文件結束符的應用進程調用close關閉它的socket。這導致它的TCP也發送一個FIN N;
  4. 接收到這個FIN的源發送端TCP對它進行確認。

2. 握手為什么是三次,揮手為什么是四次?

三次握手足以建立連接,四次握手就有些多余
如果兩次握手的話,就會出現已失效的請求報文段突然又傳送到了服務端而產生連接的誤判

例如:

有這樣一種情況,當A發送一個消息給B,但是由于網絡原因,消息被阻塞在了某個節點,然后阻塞的時間超出設定的時間,A會認為這個消息丟失了,然后重新發送消息。
當A和B通信完成后,這個被A認為失效的消息,到達了B
對于B而言,以為這是一個新的請求鏈接消息,就向A發送確認,
對于A而言,它認為沒有給B再次發送消息(因為上次的通話已經結束)所有A不會理睬B的這個確認,但是B則會一直等待A的消息

四次揮手

因為當Server端收到Client端的SYN連接請求報文后,可以直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。但是關閉連接時,當Server端收到FIN報文時,很可能并不會立即關閉SOCKET,所以只能先回復一個ACK報文,告訴Client端,“你發的FIN報文我收到了”。只有等到我Server端所有的報文都發送完了,我才能發送FIN報文,因此不能一起發送。故需要四步握手。

3. 三次握手失敗,服務端是如何處理的?

失敗時服務器并不會重傳ack報文,而是直接發送RTS報文段,進入CLOSED狀態。這樣做的目的是為了防止SYN洪泛攻擊。

4. TIME_WAIT狀態的作用?

如果四次揮手中最后一個ACK丟了,那么服務端會再次發送一個FIN。如果沒有TIME_WAIT的話,那么客戶端直接關閉,有可能重新與別的服務器建立連接,此時用的還是原來的端口和IP,那么之前的服務端重新發送的FIN又發給了客戶端,此時客戶端就懵逼了,我才剛建立連接,怎么就要分手?

總結

  1. 假如沒有TIME_WAIT,客戶端直接關閉,但是又重啟了相同地址的客戶端
  2. 有可能因為四次揮手最后一次ACK丟失導致服務器重傳FIN包,對后續連接造成影響
  3. 因此主動關閉方,發送最后一ACK后。不能直接關閉,需要等待一段時間-----2個MSL時間
MSL-----報文最大生存周期

等待1個MSL時間是為了能夠處理對端重傳的FIN包進行ACK回復
等待2個MSL時間是為了讓所有網絡中延遲的報文都消失在網絡中,不會對后續連接造成影響

5. 服務端出現大量TIME_WAIT狀態的原因以及解決方法

由于主動關閉TCP連接的一方才會進入TIME_WAIT狀態,一般情況服務器端不會出現TIME_WAIT狀態,因為大多數情況都是客戶端主動發起連接并主動關閉連接。但是某些服務如pop/smtp、ftp卻是服務端收到客戶端的QUIT命令后主動關閉連接,這就造成這類服務器上容易出現大量的TIME_WAIT狀態的連接,而且并發量越大處于此種狀態的連接越多。另外,對于被動關閉連接的服務在主動關閉客戶端非法請求或清理長時間不活動的連接時(這種情況很可能是客戶端程序忘記關閉連接)也會出現TIME_WAIT的狀態。

方法一

C/C++中提供了一個接口,如果服務器重啟時需要對端口號以及socket地址進行復用,從而避免了TIME_WAIT狀態
在這里插入圖片描述

方法二

通過修改Linux內核的方式解決該問題
在 /etc/sysctl.conf中加入
net.ipv4.tcp_tw_recycle = 1 (表示開啟TCP連接中TIME-WAIT sockets的快速回收,默認為0,表示關閉)
net.ipv4.tcp_fin_timeout=30 (修改系統默認的 TIMEOUT 時間)

TCP的可靠傳輸

1. 確認應答機制

2. 超時重傳機制

  1. 主機A發送數據給B之后, 可能因為網絡擁堵等原因, 數據無法到達主機B;
  2. 如果主機A在一個特定時間間隔內沒有收到B發來的確認應答, 就會進行重發;
超時的時間如何確定?

理想的情況下, 找到一個小的時間, 保證 “確認應答一定能在這個時間內返回”. 但是這個時間的長短, 隨著網絡環境的不同, 是有差異的. 如果超時時間設的太長, 會影響整體的重傳效率; 如果超時時間設的太短, 有可能會頻繁發送重復的包;
TCP為了保證無論在任何環境下都能比較高性能的通信, 因此會動態計算這個大超時時間.

  1. Linux中(BSD Unix和Windows也是如此), 超時以500ms為一個單位進行控制, 每次判定超時重發的超時 時間都是500ms的整數倍.
  2. 如果重發一次之后, 仍然得不到應答, 等待 2*500ms 后再進行重傳.
  3. 如果仍然得不到應答, 等待 4*500ms 進行重傳. 依次類推, 以指數形式遞增.
  4. 累計到一定的重傳次數, TCP認為網絡或者對端主機出現異常, 強制關閉連接

3. 包序管理

TCP協議需要能夠識別出那些包是重復的包, 并且把重復的丟棄掉. 這時候我們利用序列號, 就可以很容易做到去重的效果.
序號+長度

TCP連接管理機制

在這里插入圖片描述

服務端狀態轉化

  1. [CLOSED -> LISTEN] 服務器端調用listen后進入LISTEN狀態, 等待客戶端連接;
  2. [LISTEN -> SYN_RCVD] 一旦監聽到連接請求(同步報文段), 就將該連接放入內核等待隊列中, 并向客戶端 發送SYN確認報文
  3. [SYN_RCVD -> ESTABLISHED] 服務端一旦收到客戶端的確認報文, 就進入ESTABLISHED狀態, 可以進行 讀寫數據了.
  4. [ESTABLISHED -> CLOSE_WAIT] 當客戶端主動關閉連接(調用close), 服務器會收到結束報文段, 服務器 返回確認報文段并進入CLOSE_WAIT;
  5. [CLOSE_WAIT -> LAST_ACK] 進入CLOSE_WAIT后說明服務器準備關閉連接(需要處理完之前的數據); 當 服務器真正調用close關閉連接時, 會向客戶端發送FIN, 此時服務器進入LAST_ACK狀態, 等待后一個 ACK到來(這個ACK是客戶端確認收到了FIN)
  6. [LAST_ACK -> CLOSED] 服務器收到了對FIN的ACK, 徹底關閉連接

客戶端狀態轉化

  1. [CLOSED -> SYN_SENT] 客戶端調用connect, 發送同步報文段;
  2. [SYN_SENT -> ESTABLISHED] connect調用成功, 則進入ESTABLISHED狀態, 開始讀寫數據;
  3. [ESTABLISHED -> FIN_WAIT_1] 客戶端主動調用close時, 向服務器發送結束報文段, 同時進入 FIN_WAIT_1;
  4. [FIN_WAIT_1 -> FIN_WAIT_2] 客戶端收到服務器對結束報文段的確認, 則進入FIN_WAIT_2, 開始等待服 務器的結束報文段;
  5. [FIN_WAIT_2 -> TIME_WAIT] 客戶端收到服務器發來的結束報文段, 進入TIME_WAIT, 并發出LAST_ACK;
  6. [TIME_WAIT -> CLOSED] 客戶端要等待一個2MSL(Max Segment Life, 報文大生存時間)的時間, 才會 進入CLOSED狀態.

滑動窗口

一次性可以發送大量的數據(受限于協議字段中的窗口大小);然后等待回復
對每一個發送的數據段, 都要給一個ACK確認應答. 收到ACK后再發送下一個數據段. 這樣做有一個比較大的缺點, 就是性能較差. 尤其是數據往返的時間較長的時候.既然這樣一發一收的方式性能較低, 那么我們一次發送多條數據, 就可以大大的提高性能(其實是將多個段的等待時 間重疊在一起了).

  1. 窗口大小指的是無需等待確認應答而可以繼續發送數據的大值.
  2. 發送前四個段的時候, 不需要等待任何ACK, 直接發送;
  3. 收到第一個ACK后, 滑動窗口向后移動, 繼續發送第五個段的數據; 依次類推;
  4. 操作系統內核為了維護這個滑動窗口, 需要開辟 發送緩沖區 來記錄當前還有哪些數據沒有應答; 只有確 認應答過的數據, 才能從緩沖區刪掉;
  5. 窗口越大, 則網絡的吞吐率就越高

在這里插入圖片描述

服務端:接受數據,后沿往后走并回復客戶端,前沿不能動,客戶端拿走數據后,前沿往后走
客戶端:發送第一條數據,窗口不動,等到接受到第一條數據的回復后,后沿向后走,根據回復的窗口大小,決定前沿是否向后動

滑動窗口中快速重傳機制

如果出現了丟包, 如何進行重傳?

情況一: 數據包已經抵達, ACK被丟了.

這種情況下, 部分ACK丟了并不要緊, 因為可以通過后續的ACK進行確認;
在這里插入圖片描述
只要后面有一次ack成功了,就代表前面的都接收到了

情況二: 數據包就直接丟了.

在這里插入圖片描述

  1. 當某一段報文段丟失之后, 發送端會一直收到 1 這樣的ACK, 就像是在提醒發送端 "我想要的是 1 一樣;
  2. 如果發送端主機連續三次收到了同樣一個 “1” 這樣的應答, 就會將對應的數據 1~1024 重新發送;
  3. 這個時候接收端收到了 1 之后, 再次返回的ACK就是3073了(因為前面的已經接收到了)接收端其實之前就已 經收到了, 被放到了接收端操作系統內核的接收緩沖區中

滑動窗口中數據的連續發送,盡力避免了因為ack丟失而導致的重傳
確認回復中的ACK確認序號能夠表示,這個序號之前的數據都已經接收到了
若前邊的數據沒有接受到,反而接收到了后邊的數據,則不會對后邊的數據進行ACK確認
總結:
當接收端接受數據的時候,若第一條數據沒到,但是接受到了第二條數據,認為第一條數據可能丟失,立即向發送端連續三次發送重傳請求;發送端連續接受到三條重傳請求,則對這條數據進行重傳

流量控制

接收端處理數據的速度是有限的. 如果發送端發的太快, 導致接收端的緩沖區被打滿, 這個時候如果發送端繼續發送, 就會造成丟包, 繼而引起丟包重傳等等一系列連鎖反應. 因此TCP支持根據接收端的處理能力, 來決定發送端的發送速度. 這個機制就叫做流量控制(Flow Control);

  1. 接收端將自己可以接收的緩沖區大小放入 TCP 首部中的 “窗口大小” 字段, 通過ACK端通知發送端;
  2. 窗口大小字段越大, 說明網絡的吞吐量越高;
  3. 接收端一旦發現自己的緩沖區快滿了, 就會將窗口大小設置成一個更小的值通知給發送端;
  4. 發送端接受到這個窗口之后, 就會減慢自己的發送速度;
  5. 如果接收端緩沖區滿了, 就會將窗口置為0; 這時發送方不再發送數據, 但是需要定期發送一個窗口探測數 據段, 使接收端把窗口大小告訴發送端
接收端如何把窗口大小告訴發送端呢?

TCP首部中, 有一個16位窗口字段, 就是存放了窗口大小信息;

16位數字大表示65535, 那么TCP窗口大就是65535字節么?

實際上, TCP首部40字節選項中還包含了一個窗口擴大因子M, 實際窗口大小是 窗口字段的值左移 M 位;
總結

  1. 通信雙方通過協議字段中的窗口大小來協商接下來應該發送的最大數據長度
  2. 窗口大小不大于當前接收緩沖區中空閑空間大小,避免因為發送數據過多導致緩沖區發滿,而丟數據導致重傳

TCP的擁塞窗口

TCP引入 慢啟動,快增長 機制, 先發少量的數據, 探探路, 摸清當前的網絡擁堵狀態, 再決定按照多大的速度傳輸數據;

通信初始雙方協商窗口大小,窗口有可能很大,一次會發送很多數據,可能會因為網絡原因導致大量丟包,導致重傳,降低效率
發送端維護一個擁塞窗口,控制/限制發送端發送的數據最大大小,這個數字隨著每次ack的確認回復快速增長,但是一旦出現包重傳,則立即重新初始化

在這里插入圖片描述

  1. 為了不增長的那么快, 因此不能使擁塞窗口單純的加倍.
  2. 此處引入一個叫做慢啟動的閾值
  3. 當擁塞窗口超過這個閾值的時候, 不再按照指數方式增長, 而是按照線性方式增長
  4. 當TCP開始啟動的時候, 慢啟動閾值等于窗口大值;
  5. 在每次超時重發的時候, 慢啟動閾值會變成原來的一半, 同時擁塞窗口置回1

少量的丟包, 我們僅僅是觸發超時重傳; 大量的丟包, 我們就認為網絡擁塞; 當TCP通信開始后, 網絡吞吐量會逐漸上升; 隨著網絡發生擁堵, 吞吐量會立刻下降; 擁塞控制, 歸根結底是TCP協議想盡可能快的把數據傳輸給對方, 但是又要避免給網絡造成太大壓力的折中方案.
TCP擁塞控制這樣的過程, 就好像 熱戀的感覺

TCP的延遲應答機制

盡可能保證窗口大小(因為接受方,有可能很快就會把數據從緩沖區拿走)
如果接收數據的主機立刻返回ACK應答, 這時候返回的窗口可能比較小

  1. 假設接收端緩沖區為1M. 一次收到了500K的數據; 如果立刻應答, 返回的窗口就是500K;
  2. 但實際上可能處理端處理的速度很快, 10ms之內就把500K數據從緩沖區消費掉了;
  3. 在這種情況下, 接收端處理還遠沒有達到自己的極限, 即使窗口再放大一些, 也能處理過來;
  4. 如果接收端稍微等一會再應答, 比如等待200ms再應答, 那么這個時候返回的窗口大小就是1M

一定要記得, 窗口越大, 網絡吞吐量就越大, 傳輸效率就越高. 我們的目標是在保證網絡不擁塞的情況下盡量提高傳輸 效率;
那么所有的包都可以延遲應答么? 肯定也不是;

  1. 數量限制: 每隔N個包就應答一次;
  2. 時間限制: 超過大延遲時間就應答一次;

TCP捎帶應答機制

盡可能避免純報頭的確認回復
例如
在延遲應答的基礎上, 我們發現, 很多情況下, 客戶端服務器在應用層也是 “一發一收” 的. 意味著客戶端給服務器說 了 “How are you”, 服務器也會給客戶端回一個 “Fine, thank you”; 那么這個時候ACK就可以搭順風車, 和服務器回應的 “Fine, thank you” 一起回給客戶端

面向字節流

對數據按照以字節為單位的流式傳輸
創建一個TCP的socket, 同時在內核中創建一個 發送緩沖區 和一個 接收緩沖區;

  1. 調用write時, 數據會先寫入發送緩沖區中;
  2. 如果發送的字節數太長, 會被拆分成多個TCP的數據包發出;
  3. 如果發送的字節數太短, 就會先在緩沖區里等待, 等到緩沖區長度差不多了, 或者其他合適的時機發送出 去;
  4. 接收數據的時候, 數據也是從網卡驅動程序到達內核的接收緩沖區;
  5. 然后應用程序可以調用read從接收緩沖區拿數據;
  6. 另一方面, TCP的一個連接, 既有發送緩沖區, 也有接收緩沖區, 那么對于這一個連接, 既可以讀數據, 也可 以寫數據. 這個概念叫做 全雙工
  7. 特性:傳輸比較靈活,但是缺點是tcp的粘包問題

由于緩沖區的存在, TCP程序的讀和寫不需要一一匹配, 例如:
寫100個字節數據時, 可以調用一次write寫100個字節, 也可以調用100次write, 每次寫一個字節; 讀100個字節數據時, 也完全不需要考慮寫的時候是怎么寫的, 既可以一次read 100個字節, 也可以一次 read一個字節, 重復100次;

粘包問題

tcp產生粘包就是內核并沒有對send要發送的數據進行明確的邊界區分。

  1. 首先要明確, 粘包問題中的 “包” , 是指的應用層的數據包.
  2. 在TCP的協議頭中, 沒有如同UDP一樣的 “報文長度” 這樣的字段, 但是有一個序號這樣的字段.
  3. 站在傳輸層的角度, TCP是一個一個報文過來的. 按照序號排好序放在緩沖區中.
  4. 站在應用層的角度, 看到的只是一串連續的字節數據.
  5. 那么應用程序看到了這么一連串的字節數據, 就不知道從哪個部分開始到哪個部分, 是一個完整的應用層 數據包
那么如何避免粘包問題呢? 歸根結底就是一句話, 明確兩個包之間的邊界
  1. 對于定長的包, 保證每次都按固定大小讀取即可; 例如上面的Request結構, 是固定大小的, 那么就從緩沖 區從頭開始按sizeof(Request)依次讀取即可;
  2. 對于變長的包, 可以在包頭的位置, 約定一個包總長度的字段, 從而就知道了包的結束位置;
  3. 對于變長的包, 還可以在包和包之間使用明確的分隔符(應用層協議, 是程序猿自己來定的, 只要保證分隔 符不和正文沖突即可)
思考: 對于UDP協議來說, 是否也存在 “粘包問題” 呢?
  1. 對于UDP, 如果還沒有上層交付數據, UDP的報文長度仍然在. 同時, UDP是一個一個把數據交付給應用 層. 就有很明確的數據邊界.
  2. 站在應用層的站在應用層的角度, 使用UDP的時候, 要么收到完整的UDP報文, 要么不收. 不會出現"半 個"的情況

TCP斷開的體現

  1. recv返回0
  2. send觸發SIGPIPE異常
  3. tcp只有連接斷開的時候才會返回0
  4. 進程終止: 進程終止會釋放文件描述符, 仍然可以發送FIN. 和正常關閉沒有什么區別
  5. 機器重啟: 和進程終止的情況相同.
  6. 機器掉電/網線斷開: 接收端認為連接還在, 一旦接收端有寫入操作, 接收端發現連接已經不在了, 就會進行reset. 即 使沒有寫入操作, TCP自己也內置了一個保活定時器, 會定期詢問對方是否還在. 如果對方不在, 也會把連接釋放.
  7. 另外, 應用層的某些協議, 也有一些這樣的檢測機制. 例如HTTP長連接中, 也會定期檢測對方的狀態. 例如QQ, 在QQ 斷線之后, 也會定期嘗試重新連接.

基于TCP應用層協議

  1. HTTP
  2. HTTPS
  3. SSH
  4. Telnet
  5. FTP
  6. SMTP

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

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

相關文章

超時設置

//read操作加上超時時間。1 int read_timeout(int fd, void *buf, uint32_t count, int time)2 {3 if(time > 0) {4 fd_set rSet;5 FD_ZERO(&rSet);6 FD_SET(fd, &rSet);7 8 struct timeval timeout;9 memset(&tim…

字符串題目 1 --------判斷兩個字符串是否為旋轉詞

題目描述 如果一個字符串為str,把字符串的前面任意部分挪到后面形成的字符串交str的旋轉詞。比如str“12345”,str的旋轉串有“12345”、“45123”等等。給定兩個字符串,判斷是否為旋轉詞。 輸入描述: 輸出包含三行,第一個兩個…

2021-03-04

為什么nginx轉發后端默認使用1.0而不是1.1 在 Nginx 的官網文檔中,有這樣一個指令: Syntax: gzip_http_version 1.0 | 1.1; Default: gzip_http_version 1.1; Context: http, server, location Sets the minimum HTTP version of a request required to…

字符串題目---2判斷兩個字符串是否為變形詞

題目描述 給定兩個字符串str1和str2,如果str1和str2中出現的字符種類出現的一樣且每種字符出現的次數也一樣,那么str1和str2互為變形詞。請判斷str1和str2是否為變形詞 輸入描述: 輸入包括3行,第一行包含兩個整數n,m(1 \leq n,…

設計模式7----代理模式

代理模式 概念 Proxy 模式又叫做代理模式,是結構型的設計模式之一,它可以為其他對象提供一 種代理(Proxy)以控制對這個對象的訪問。 所謂代理,是指具有與代理元(被代理的對象)具有相同的接口的…

網絡基礎3-1(細談IP協議頭, 網絡層,子網劃分,路由選擇,數據鏈路層,以太網幀格式,MAC地址,再談ARP協議)

IP協議 IP協議頭格式 4位版本號(version): 指定IP協議的版本, 對于IPv4來說, 就是44位頭部長度(header length): IP頭部的長度是多少個。32bit, 也就是 length * 4 的字節數. 4bit表示大 的數字是15, 因此IP頭部大長度是60字節8位服務類型(Type Of Service): 3位優先權字段(已…

c++常見并且必須記住的問題

一、基礎知識 基本語言 1、說一下static關鍵字的作用 ?2、說一下C和C的區別 3、說一說c中四種cast轉換 4、請說一下C/C 中指針和引用的區別? 5、給定三角形ABC和一點P(x,y,z),判斷點P是否在ABC內,給出思路并手寫代碼 6、怎么判斷一個…

網絡中典型協議--(DNS,輸入url后, 發生的事情. ,ICMP,NAT)

DNS(Domain Name System) DNS是一整套從域名映射到IP的系統 域名服務器發展背景 TCP/IP中使用IP地址和端口號來確定網絡上的一臺主機的一個程序. 但是IP地址不方便記憶. 于是人們發明了一種叫主機名的東西, 是一個字符串, 并且使用hosts文件來描述主機…

高級IO--1 ---(五種典型IO,阻塞IO,非阻塞IO,信號驅動IO,異步IO, IO多路轉接)

高級IO: 五種典型IO: 阻塞IO/非阻塞IO/信號驅動IO/異步IO/IO多路轉接 IO多路轉接模型:select/poll/epoll 五種典型IO 阻塞IO IO操作的流程:等待IO操作條件具備,然后進行數據拷貝 為了完成IO操作發起調用&#xff…

IO多路轉接模型----(select的模型,select的優缺點,poll的模型,poll的優缺點)

IO多路轉接模型:select/poll/epoll 對大量描述符進行事件監控(可讀/可寫/異常) select模型 用戶定義描述符的事件監控集合 fd_set(這是一個位圖,用于存儲要監控的描述符); 用戶將需要監控的描述符添加到集合中,這個描…

IO多路轉接模型-----epoll

epoll: Linux下性能最高的多路轉接模型 epoll 有3個相關的系統調用. epoll_create 功能:創建epoll,在內核中創建eventpoll結構體,size決定了epoll最多監控多少個描述符,在Linux2.6.8之后被忽略,但是必須…

再寫順序表(c語言實現,外加冒泡排序,二分查找)

概念 順序表是用一段物理地址連續的存儲單元依次存儲數據元素的線性結構,一般情況下采用數組存儲。在數組 上完成數據的增刪查改。 順序表一般可以分為: 靜態順序表:使用定長數組存儲。動態順序表:使用動態開辟的數組存儲。 頭…

再寫單鏈表(不帶頭單鏈表)

單鏈表 實際中鏈表的結構非常多樣,以下情況組合起來就有8種鏈表結構: 單向、雙向帶頭、不帶頭循環、非循環 雖然有這么多的鏈表的結構,但是我們實際中最常用還是兩種結構: 無頭單向非循環鏈表:結構簡單&#xff0…

再寫雙向循環鏈表

#pragma once #include<assert.h> #include<malloc.h> #include<stdio.h> typedef int DLDataType;//定義鏈表結點結構 typedef struct DListNode{DLDataType value;struct DListNode *prev; //指向前一個結點struct DListNode *next; //指向后一個結點 } DL…

鏈表題目--1 刪除鏈表中所有等于val的值

注意事項 要刪除的結點相鄰第一個結點就是要刪除的結點 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/struct ListNode* removeElements(struct ListNode* head, int val){if(headNULL){return NULL;}struct …

鏈表題目--2 求鏈表的中間結點 和 求鏈表中倒數第k個結點

求鏈表的中間結點 思路 一個走兩步&#xff0c;一個走一步。一個走到尾&#xff0c;另外一個就走到了中間 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/struct ListNode* middleNode(struct ListNode* head…

鏈表題目---3 合并兩個有序單鏈表 和 分割鏈表

合并兩個有序單鏈表 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){if(l1 NULL){return l2;}else if(l2 NULL){return l1;}struc…

鏈表題目---4 刪除鏈表中重復的結點 和 判斷鏈表是否為回文鏈表

刪除鏈表中重復的結點 /* struct ListNode {int val;struct ListNode *next;ListNode(int x) :val(x), next(NULL) {} }; */ class Solution { public:ListNode* deleteDuplication(ListNode* pHead){if(pHead NULL){return NULL;}ListNode *prev NULL; //用于刪除的結點, 是…

鏈表題目----5 相交鏈表 和 環形鏈表 和 返回鏈表開始入環的第一個節點

相交鏈表 思路 鏈表交叉不可能是x型因為有可能兩個鏈表不等長&#xff0c;所以我們必須讓他們從同一起跑位置去起跑從同一起跑位置出發&#xff0c;依次比較每個結點的地址是否相同 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct L…

鏈表題目---6 復制帶隨機指針的鏈表

思路 將新結點放在老結點的后面 復制random 將鏈表拆開 /* // Definition for a Node. class Node { public:int val;Node* next;Node* random;Node() {}Node(int _val, Node* _next, Node* _random) {val _val;next _next;random _random;} }; */ class Solution { publi…