婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > TCP第三次握手傳數據過程圖解

TCP第三次握手傳數據過程圖解

熱門標簽:激光標記地圖標注 企業辦理400電話收費標準 電銷智能機器人試用 撫州市城區地圖標注 中國地圖標注上各個省 智能電銷機器人真的有用么 新鄉牧野400電話申請 高德地圖標注足跡怎么打標 百度地圖底圖標注

RFC793文檔里帶有SYN標志的過程包是不可以攜帶數據的,也就是說三次握手的前兩次是不可以攜帶數據的(邏輯上看,連接還沒建立,攜帶數據好像也有點說不過去)。重點就是第三次握手可不可以攜帶數據。

先說結論:TCP協議建立連接的三次握手過程中的第三次握手允許攜帶數據。

對照著上邊的TCP狀態變化圖的連接建立部分,我們看下RFC793文檔的說法。RFC793文檔給出的說法如下(省略不重要的部分):

重點是這句 “Data or controls which were queued for transmission may be included”,也就是說標準表示,第三次握手的ACK包是可以攜帶數據。

首先, 第三次握手的包是由連接發起方(以下簡稱客戶端)發給端口監聽方(以下簡稱服務端)的,所以只需要找到內核協議棧在一個連接處于SYN-RECV(圖中的SYN_RECEIVED)狀態時收到包之后的處理過程即可。經過一番搜索后找到了,位于 net\ipv4目錄下tcp_input.c文件中的tcp_rcv_state_process函數處理這個過程。如圖:

這個函數實際上是個TCP狀態機,用于處理TCP連接處于各個狀態時收到數據包的處理工作。這里有幾個并列的switch語句,因為函數很長,所以比較容易看錯層次關系。下圖是精簡了無需關注的代碼之后SYN-RECV狀態的處理過程:

一定要注意這兩個switch語句是并列的。所以當TCP_SYN_RECV狀態收到合法規范的二次握手包之后,就會立即把socket狀態設置為TCP_ESTABLISHED狀態,執行到下面的TCP_ESTABLISHED狀態的case時,會繼續處理其包含的數據(如果有)。

上面表明了,當客戶端發過來的第三次握手的ACK包含有數據時,服務端是可以正常處理的。那么客戶端那邊呢?那看看客戶端處于SYN-SEND狀態時,怎么發送第三次ACK包吧。如圖:

tcp_rcv_synsent_state_process函數的實現比較長,這里直接貼出最后的關鍵點:

一目了然吧?if 條件不滿足直接回復單獨的ACK包,如果任意條件滿足的話則使用inet_csk_reset_xmit_timer函數設置定時器等待短暫的時間。這段時間如果有數據,隨著數據發送ACK,沒有數據回復ACK。

之前的疑問算是解決了。

條件1:sk->sk_write_pending != 0

這個值默認是0的,那什么情況會導致不為0呢?答案是協議棧發送數據的函數遇到socket狀態不是ESTABLISHED的時候,會對這個變量做++操作,并等待一小會時間嘗試發送數據。看圖:

net/core/stream.c里的sk_stream_wait_connect函數做了如下操作:

sk->sk_write_pending遞增,并且等待socket連接到達ESTABLISHED狀態后發出數據。這就解釋清楚了。

Linux socket的默認工作方式是阻塞的,也就是說,客戶端的connect調用在默認情況下會阻塞,等待三次握手過程結束之后或者遇到錯誤才會返回。那么nc這種完全用阻塞套接字實現的且沒有對默認socket參數進行修改的命令行小程序會乖乖等待connect返回成功或者失敗才會發送數據的,這就是我們抓不到第三次握手的包帶有數據的原因。

那么設置非阻塞套接字,connect后立即send數據,連接過程不是瞬間連接成功的話,也許有機會看到第三次握手包帶數據。不過開源的網絡庫即便是非阻塞socket,也是監聽該套接字的可寫事件,再次確認連接成功才會寫數據。為了節省這點幾乎可以忽略不計的性能,真的不如安全可靠的代碼更有價值。

條件2:icsk->icsk_accept_queue.rskq_defer_accept != 0

這個條件好奇怪,defer_accept是個socket選項,用于推遲accept,實際上是當接收到第一個數據之后,才會創建連接。tcp_defer_accept這個選項一般是在服務端用的,會影響socket的SYN和ACCEPT隊列。默認不設置的話,三次握手完成,socket就進入accept隊列,應用層就感知到并ACCEPT相關的連接。當tcp_defer_accept設置后,三次握手完成了,socket也不進入ACCEPT隊列,而是直接留在SYN隊列(有長度限制,超過內核就拒絕新連接),直到數據真的發過來再放到ACCEPT隊列。設置了這個參數的服務端可以accept之后直接read,必然有數據,也節省一次系統調用。

SYN隊列保存SYN_RECV狀態的socket,長度由net.ipv4.tcp_max_syn_backlog參數控制,accept隊列在listen調用時,backlog參數設置,內核硬限制由 net.core.somaxconn 限制,即實際的值由min(backlog,somaxconn) 來決定。

有意思的是如果客戶端先bind到一個端口和IP,然后setsockopt(TCP_DEFER_ACCEPT),然后connect服務器,這個時候就會出現rskq_defer_accept=1的情況,這時候內核會設置定時器等待數據一起在回復ACK包。我個人從未這么做過,難道只是為了減少一次ACK的空包發送來提高性能?哪位同學知道煩請告知,謝謝。

條件3:icsk->icsk_ack.pingpong != 0

pingpong這個屬性實際上也是一個套接字選項,用來表明當前鏈接是否為交互數據流,如其值為1,則表明為交互數據流,會使用延遲確認機制。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

標簽:延安 海西 邯鄲 忻州 南通 辛集 臨汾 西安

巨人網絡通訊聲明:本文標題《TCP第三次握手傳數據過程圖解》,本文關鍵詞  TCP,第三次,握手,傳,數據,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《TCP第三次握手傳數據過程圖解》相關的同類信息!
  • 本頁收集關于TCP第三次握手傳數據過程圖解的相關信息資訊供網民參考!
  • 推薦文章
    主站蜘蛛池模板: 嘉定区| 亳州市| 临江市| 马尔康县| 三亚市| 栾城县| 富顺县| 万山特区| 浦城县| 富宁县| 宝清县| 玉林市| 林口县| 墨江| 观塘区| 囊谦县| 屏南县| 镇原县| 昌江| 阿拉善盟| 杂多县| 西峡县| 宁夏| 廊坊市| 乡宁县| 九江市| 双城市| 凉山| 金门县| 嘉鱼县| 于都县| 长宁区| 莱阳市| 黎城县| 阿勒泰市| 尼勒克县| 丁青县| 太仓市| 平潭县| 炉霍县| 亚东县|