日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

网络基础2-3(TCP协议,三次握手,四次挥手,TIME_WAIT状态的作用,TCP如何保证可靠传输,TCP连接中状态转化,滑动窗口,流量控制,快速重传,拥塞窗口,延迟应答,捎带应答,粘包问题)

發(fā)布時間:2023/11/30 70 豆豆

TCP協(xié)議

TCP協(xié)議概念

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

TCP協(xié)議格式

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

    發(fā)送端填充, CRC校驗(yàn). 接收端校驗(yàn)不通過, 則認(rèn)為數(shù)據(jù)有問題. 此處的檢驗(yàn)和不光包含TCP首部, 也 包含TCP數(shù)據(jù)部分.

    7. 16位緊急指針

    標(biāo)識哪部分?jǐn)?shù)據(jù)是緊急數(shù)據(jù);

    8. 40字節(jié)頭部選項(xiàng)

    三次握手和四次揮手圖示

    關(guān)于TCP協(xié)議的重點(diǎn)問題

    1. 三次握手建立連接以及四次揮手?jǐn)嚅_連接的流程?

    三次握手過程

    當(dāng)客戶端調(diào)用connect時,觸發(fā)了連接請求,向服務(wù)器發(fā)送了SYN X包,這時connect進(jìn)入阻塞狀態(tài);服務(wù)器監(jiān)聽到連接請求,即收到SYN X包,調(diào)用accept函 數(shù)接收請求向客戶端發(fā)送SYN K ,ACK X+1,這時accept進(jìn)入阻塞狀態(tài);客戶端收到服務(wù)器的SYN K ,ACK X+1之后,這時connect返回,并對SYN K進(jìn)行確認(rèn);服務(wù)器收到ACK K+1時,accept返回,至此三次握手完畢,連接建立。

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

    四次揮手

  • 某個應(yīng)用進(jìn)程首先調(diào)用close主動關(guān)閉連接,這時TCP發(fā)送一個FIN M;
  • 另一端接收到FIN M之后,執(zhí)行被動關(guān)閉,對這個FIN進(jìn)行確認(rèn)。它的接收也作為文件結(jié)束符傳遞給應(yīng)用進(jìn)程,因?yàn)镕IN的接收意味著應(yīng)用進(jìn)程在相應(yīng)的連接上再也接收不到額外數(shù)據(jù);
  • 一段時間之后,接收到文件結(jié)束符的應(yīng)用進(jìn)程調(diào)用close關(guān)閉它的socket。這導(dǎo)致它的TCP也發(fā)送一個FIN N;
  • 接收到這個FIN的源發(fā)送端TCP對它進(jìn)行確認(rèn)。
  • 2. 握手為什么是三次,揮手為什么是四次?

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

    例如:

    有這樣一種情況,當(dāng)A發(fā)送一個消息給B,但是由于網(wǎng)絡(luò)原因,消息被阻塞在了某個節(jié)點(diǎn),然后阻塞的時間超出設(shè)定的時間,A會認(rèn)為這個消息丟失了,然后重新發(fā)送消息。
    當(dāng)A和B通信完成后,這個被A認(rèn)為失效的消息,到達(dá)了B
    對于B而言,以為這是一個新的請求鏈接消息,就向A發(fā)送確認(rèn),
    對于A而言,它認(rèn)為沒有給B再次發(fā)送消息(因?yàn)樯洗蔚耐ㄔ捯呀?jīng)結(jié)束)所有A不會理睬B的這個確認(rèn),但是B則會一直等待A的消息

    四次揮手

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

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

    失敗時服務(wù)器并不會重傳ack報文,而是直接發(fā)送RTS報文段,進(jìn)入CLOSED狀態(tài)。這樣做的目的是為了防止SYN洪泛攻擊。

    4. TIME_WAIT狀態(tài)的作用?

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

    總結(jié)

  • 假如沒有TIME_WAIT,客戶端直接關(guān)閉,但是又重啟了相同地址的客戶端
  • 有可能因?yàn)樗拇螕]手最后一次ACK丟失導(dǎo)致服務(wù)器重傳FIN包,對后續(xù)連接造成影響
  • 因此主動關(guān)閉方,發(fā)送最后一ACK后。不能直接關(guān)閉,需要等待一段時間-----2個MSL時間
  • MSL-----報文最大生存周期

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

    5. 服務(wù)端出現(xiàn)大量TIME_WAIT狀態(tài)的原因以及解決方法

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

    方法一

    C/C++中提供了一個接口,如果服務(wù)器重啟時需要對端口號以及socket地址進(jìn)行復(fù)用,從而避免了TIME_WAIT狀態(tài)

    方法二

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

    TCP的可靠傳輸

    1. 確認(rèn)應(yīng)答機(jī)制

    2. 超時重傳機(jī)制

  • 主機(jī)A發(fā)送數(shù)據(jù)給B之后, 可能因?yàn)榫W(wǎng)絡(luò)擁堵等原因, 數(shù)據(jù)無法到達(dá)主機(jī)B;
  • 如果主機(jī)A在一個特定時間間隔內(nèi)沒有收到B發(fā)來的確認(rèn)應(yīng)答, 就會進(jìn)行重發(fā);
  • 超時的時間如何確定?

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

  • Linux中(BSD Unix和Windows也是如此), 超時以500ms為一個單位進(jìn)行控制, 每次判定超時重發(fā)的超時 時間都是500ms的整數(shù)倍.
  • 如果重發(fā)一次之后, 仍然得不到應(yīng)答, 等待 2*500ms 后再進(jìn)行重傳.
  • 如果仍然得不到應(yīng)答, 等待 4*500ms 進(jìn)行重傳. 依次類推, 以指數(shù)形式遞增.
  • 累計到一定的重傳次數(shù), TCP認(rèn)為網(wǎng)絡(luò)或者對端主機(jī)出現(xiàn)異常, 強(qiáng)制關(guān)閉連接
  • 3. 包序管理

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

    TCP連接管理機(jī)制

    服務(wù)端狀態(tài)轉(zhuǎn)化

  • [CLOSED -> LISTEN] 服務(wù)器端調(diào)用listen后進(jìn)入LISTEN狀態(tài), 等待客戶端連接;
  • [LISTEN -> SYN_RCVD] 一旦監(jiān)聽到連接請求(同步報文段), 就將該連接放入內(nèi)核等待隊(duì)列中, 并向客戶端 發(fā)送SYN確認(rèn)報文
  • [SYN_RCVD -> ESTABLISHED] 服務(wù)端一旦收到客戶端的確認(rèn)報文, 就進(jìn)入ESTABLISHED狀態(tài), 可以進(jìn)行 讀寫數(shù)據(jù)了.
  • [ESTABLISHED -> CLOSE_WAIT] 當(dāng)客戶端主動關(guān)閉連接(調(diào)用close), 服務(wù)器會收到結(jié)束報文段, 服務(wù)器 返回確認(rèn)報文段并進(jìn)入CLOSE_WAIT;
  • [CLOSE_WAIT -> LAST_ACK] 進(jìn)入CLOSE_WAIT后說明服務(wù)器準(zhǔn)備關(guān)閉連接(需要處理完之前的數(shù)據(jù)); 當(dāng) 服務(wù)器真正調(diào)用close關(guān)閉連接時, 會向客戶端發(fā)送FIN, 此時服務(wù)器進(jìn)入LAST_ACK狀態(tài), 等待后一個 ACK到來(這個ACK是客戶端確認(rèn)收到了FIN)
  • [LAST_ACK -> CLOSED] 服務(wù)器收到了對FIN的ACK, 徹底關(guān)閉連接
  • 客戶端狀態(tài)轉(zhuǎn)化

  • [CLOSED -> SYN_SENT] 客戶端調(diào)用connect, 發(fā)送同步報文段;
  • [SYN_SENT -> ESTABLISHED] connect調(diào)用成功, 則進(jìn)入ESTABLISHED狀態(tài), 開始讀寫數(shù)據(jù);
  • [ESTABLISHED -> FIN_WAIT_1] 客戶端主動調(diào)用close時, 向服務(wù)器發(fā)送結(jié)束報文段, 同時進(jìn)入 FIN_WAIT_1;
  • [FIN_WAIT_1 -> FIN_WAIT_2] 客戶端收到服務(wù)器對結(jié)束報文段的確認(rèn), 則進(jìn)入FIN_WAIT_2, 開始等待服 務(wù)器的結(jié)束報文段;
  • [FIN_WAIT_2 -> TIME_WAIT] 客戶端收到服務(wù)器發(fā)來的結(jié)束報文段, 進(jìn)入TIME_WAIT, 并發(fā)出LAST_ACK;
  • [TIME_WAIT -> CLOSED] 客戶端要等待一個2MSL(Max Segment Life, 報文大生存時間)的時間, 才會 進(jìn)入CLOSED狀態(tài).
  • 滑動窗口

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

  • 窗口大小指的是無需等待確認(rèn)應(yīng)答而可以繼續(xù)發(fā)送數(shù)據(jù)的大值.
  • 發(fā)送前四個段的時候, 不需要等待任何ACK, 直接發(fā)送;
  • 收到第一個ACK后, 滑動窗口向后移動, 繼續(xù)發(fā)送第五個段的數(shù)據(jù); 依次類推;
  • 操作系統(tǒng)內(nèi)核為了維護(hù)這個滑動窗口, 需要開辟 發(fā)送緩沖區(qū) 來記錄當(dāng)前還有哪些數(shù)據(jù)沒有應(yīng)答; 只有確 認(rèn)應(yīng)答過的數(shù)據(jù), 才能從緩沖區(qū)刪掉;
  • 窗口越大, 則網(wǎng)絡(luò)的吞吐率就越高
  • 服務(wù)端:接受數(shù)據(jù),后沿往后走并回復(fù)客戶端,前沿不能動,客戶端拿走數(shù)據(jù)后,前沿往后走
    客戶端:發(fā)送第一條數(shù)據(jù),窗口不動,等到接受到第一條數(shù)據(jù)的回復(fù)后,后沿向后走,根據(jù)回復(fù)的窗口大小,決定前沿是否向后動

    滑動窗口中快速重傳機(jī)制

    如果出現(xiàn)了丟包, 如何進(jìn)行重傳?

    情況一: 數(shù)據(jù)包已經(jīng)抵達(dá), ACK被丟了.

    這種情況下, 部分ACK丟了并不要緊, 因?yàn)榭梢酝ㄟ^后續(xù)的ACK進(jìn)行確認(rèn);

    只要后面有一次ack成功了,就代表前面的都接收到了

    情況二: 數(shù)據(jù)包就直接丟了.

  • 當(dāng)某一段報文段丟失之后, 發(fā)送端會一直收到 1 這樣的ACK, 就像是在提醒發(fā)送端 "我想要的是 1 一樣;
  • 如果發(fā)送端主機(jī)連續(xù)三次收到了同樣一個 “1” 這樣的應(yīng)答, 就會將對應(yīng)的數(shù)據(jù) 1~1024 重新發(fā)送;
  • 這個時候接收端收到了 1 之后, 再次返回的ACK就是3073了(因?yàn)榍懊娴囊呀?jīng)接收到了)接收端其實(shí)之前就已 經(jīng)收到了, 被放到了接收端操作系統(tǒng)內(nèi)核的接收緩沖區(qū)中
  • 滑動窗口中數(shù)據(jù)的連續(xù)發(fā)送,盡力避免了因?yàn)閍ck丟失而導(dǎo)致的重傳
    確認(rèn)回復(fù)中的ACK確認(rèn)序號能夠表示,這個序號之前的數(shù)據(jù)都已經(jīng)接收到了
    若前邊的數(shù)據(jù)沒有接受到,反而接收到了后邊的數(shù)據(jù),則不會對后邊的數(shù)據(jù)進(jìn)行ACK確認(rèn)
    總結(jié):
    當(dāng)接收端接受數(shù)據(jù)的時候,若第一條數(shù)據(jù)沒到,但是接受到了第二條數(shù)據(jù),認(rèn)為第一條數(shù)據(jù)可能丟失,立即向發(fā)送端連續(xù)三次發(fā)送重傳請求;發(fā)送端連續(xù)接受到三條重傳請求,則對這條數(shù)據(jù)進(jìn)行重傳

    流量控制

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

  • 接收端將自己可以接收的緩沖區(qū)大小放入 TCP 首部中的 “窗口大小” 字段, 通過ACK端通知發(fā)送端;
  • 窗口大小字段越大, 說明網(wǎng)絡(luò)的吞吐量越高;
  • 接收端一旦發(fā)現(xiàn)自己的緩沖區(qū)快滿了, 就會將窗口大小設(shè)置成一個更小的值通知給發(fā)送端;
  • 發(fā)送端接受到這個窗口之后, 就會減慢自己的發(fā)送速度;
  • 如果接收端緩沖區(qū)滿了, 就會將窗口置為0; 這時發(fā)送方不再發(fā)送數(shù)據(jù), 但是需要定期發(fā)送一個窗口探測數(shù) 據(jù)段, 使接收端把窗口大小告訴發(fā)送端
  • 接收端如何把窗口大小告訴發(fā)送端呢?

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

    16位數(shù)字大表示65535, 那么TCP窗口大就是65535字節(jié)么?

    實(shí)際上, TCP首部40字節(jié)選項(xiàng)中還包含了一個窗口擴(kuò)大因子M, 實(shí)際窗口大小是 窗口字段的值左移 M 位;
    總結(jié)

  • 通信雙方通過協(xié)議字段中的窗口大小來協(xié)商接下來應(yīng)該發(fā)送的最大數(shù)據(jù)長度
  • 窗口大小不大于當(dāng)前接收緩沖區(qū)中空閑空間大小,避免因?yàn)榘l(fā)送數(shù)據(jù)過多導(dǎo)致緩沖區(qū)發(fā)滿,而丟數(shù)據(jù)導(dǎo)致重傳
  • TCP的擁塞窗口

    TCP引入 慢啟動,快增長 機(jī)制, 先發(fā)少量的數(shù)據(jù), 探探路, 摸清當(dāng)前的網(wǎng)絡(luò)擁堵狀態(tài), 再決定按照多大的速度傳輸數(shù)據(jù);

    通信初始雙方協(xié)商窗口大小,窗口有可能很大,一次會發(fā)送很多數(shù)據(jù),可能會因?yàn)榫W(wǎng)絡(luò)原因?qū)е麓罅縼G包,導(dǎo)致重傳,降低效率 發(fā)送端維護(hù)一個擁塞窗口,控制/限制發(fā)送端發(fā)送的數(shù)據(jù)最大大小,這個數(shù)字隨著每次ack的確認(rèn)回復(fù)快速增長,但是一旦出現(xiàn)包重傳,則立即重新初始化

  • 為了不增長的那么快, 因此不能使擁塞窗口單純的加倍.
  • 此處引入一個叫做慢啟動的閾值
  • 當(dāng)擁塞窗口超過這個閾值的時候, 不再按照指數(shù)方式增長, 而是按照線性方式增長
  • 當(dāng)TCP開始啟動的時候, 慢啟動閾值等于窗口大值;
  • 在每次超時重發(fā)的時候, 慢啟動閾值會變成原來的一半, 同時擁塞窗口置回1
  • 少量的丟包, 我們僅僅是觸發(fā)超時重傳; 大量的丟包, 我們就認(rèn)為網(wǎng)絡(luò)擁塞; 當(dāng)TCP通信開始后, 網(wǎng)絡(luò)吞吐量會逐漸上升; 隨著網(wǎng)絡(luò)發(fā)生擁堵, 吞吐量會立刻下降; 擁塞控制, 歸根結(jié)底是TCP協(xié)議想盡可能快的把數(shù)據(jù)傳輸給對方, 但是又要避免給網(wǎng)絡(luò)造成太大壓力的折中方案.
    TCP擁塞控制這樣的過程, 就好像 熱戀的感覺

    TCP的延遲應(yīng)答機(jī)制

    盡可能保證窗口大小(因?yàn)榻邮芊?#xff0c;有可能很快就會把數(shù)據(jù)從緩沖區(qū)拿走)
    如果接收數(shù)據(jù)的主機(jī)立刻返回ACK應(yīng)答, 這時候返回的窗口可能比較小

  • 假設(shè)接收端緩沖區(qū)為1M. 一次收到了500K的數(shù)據(jù); 如果立刻應(yīng)答, 返回的窗口就是500K;
  • 但實(shí)際上可能處理端處理的速度很快, 10ms之內(nèi)就把500K數(shù)據(jù)從緩沖區(qū)消費(fèi)掉了;
  • 在這種情況下, 接收端處理還遠(yuǎn)沒有達(dá)到自己的極限, 即使窗口再放大一些, 也能處理過來;
  • 如果接收端稍微等一會再應(yīng)答, 比如等待200ms再應(yīng)答, 那么這個時候返回的窗口大小就是1M
  • 一定要記得, 窗口越大, 網(wǎng)絡(luò)吞吐量就越大, 傳輸效率就越高. 我們的目標(biāo)是在保證網(wǎng)絡(luò)不擁塞的情況下盡量提高傳輸 效率;
    那么所有的包都可以延遲應(yīng)答么? 肯定也不是;

  • 數(shù)量限制: 每隔N個包就應(yīng)答一次;
  • 時間限制: 超過大延遲時間就應(yīng)答一次;
  • TCP捎帶應(yīng)答機(jī)制

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

    面向字節(jié)流

    對數(shù)據(jù)按照以字節(jié)為單位的流式傳輸
    創(chuàng)建一個TCP的socket, 同時在內(nèi)核中創(chuàng)建一個 發(fā)送緩沖區(qū) 和一個 接收緩沖區(qū);

  • 調(diào)用write時, 數(shù)據(jù)會先寫入發(fā)送緩沖區(qū)中;
  • 如果發(fā)送的字節(jié)數(shù)太長, 會被拆分成多個TCP的數(shù)據(jù)包發(fā)出;
  • 如果發(fā)送的字節(jié)數(shù)太短, 就會先在緩沖區(qū)里等待, 等到緩沖區(qū)長度差不多了, 或者其他合適的時機(jī)發(fā)送出 去;
  • 接收數(shù)據(jù)的時候, 數(shù)據(jù)也是從網(wǎng)卡驅(qū)動程序到達(dá)內(nèi)核的接收緩沖區(qū);
  • 然后應(yīng)用程序可以調(diào)用read從接收緩沖區(qū)拿數(shù)據(jù);
  • 另一方面, TCP的一個連接, 既有發(fā)送緩沖區(qū), 也有接收緩沖區(qū), 那么對于這一個連接, 既可以讀數(shù)據(jù), 也可 以寫數(shù)據(jù). 這個概念叫做 全雙工
  • 特性:傳輸比較靈活,但是缺點(diǎn)是tcp的粘包問題
  • 由于緩沖區(qū)的存在, TCP程序的讀和寫不需要一一匹配, 例如:
    寫100個字節(jié)數(shù)據(jù)時, 可以調(diào)用一次write寫100個字節(jié), 也可以調(diào)用100次write, 每次寫一個字節(jié); 讀100個字節(jié)數(shù)據(jù)時, 也完全不需要考慮寫的時候是怎么寫的, 既可以一次read 100個字節(jié), 也可以一次 read一個字節(jié), 重復(fù)100次;

    粘包問題

    tcp產(chǎn)生粘包就是內(nèi)核并沒有對send要發(fā)送的數(shù)據(jù)進(jìn)行明確的邊界區(qū)分。

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

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

  • HTTP
  • HTTPS
  • SSH
  • Telnet
  • FTP
  • SMTP
  • 總結(jié)

    以上是生活随笔為你收集整理的网络基础2-3(TCP协议,三次握手,四次挥手,TIME_WAIT状态的作用,TCP如何保证可靠传输,TCP连接中状态转化,滑动窗口,流量控制,快速重传,拥塞窗口,延迟应答,捎带应答,粘包问题)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。