三次握手的第三次握手發送ACK能攜帶數據嗎?如何攜帶?怎樣體現的呢?

如題,對於三次握手的疑問


如果我對同學們說,想透徹理解通信的本質,首先要追本溯源學習電話原理,你們會覺得我在說笑嗎?

人類先發明了電話,當電話原理成熟了,上世紀中後葉又出現了TCP/IP,TCP協議幾乎就是模仿電話原理的,為了更好學習TCP,我們要學習電話的基本原理。

三次握手的過程

第一次

上海的老王給北京的老張打電話,撥號碼

010-68886xx8

老王電話機與電信局之間的電話線,其實有兩個信道:信令信道 + 語音信道

當老王拿起電話,撥010-68886xx8,這個號碼通過信令信道傳到了電信局,同時將語音信道(DS0)保留,為了稍後的通信做語音信道預留

電信局根據這個號碼做路由查找,找到其上一級的交換機,通過信令信道將010-68886xx88轉發給上一級交換機,同時和上一級協商好,預留一個DS0語音信道,為了語音傳輸。

這樣一級級轉接,最終號碼轉接到北京老張的電話機,振鈴,北京電信局與老張電話機之間預留一個DS0語音信道,為了語音傳輸。

第二次

老張拿起電話的那一刻,一個「Connected」信令順著來時的信令信道(一跳、一跳)傳輸到老王的電話機。

第三次

老王電話機通常還會回復一個「ACK」給對方,以示接到對方的「Connected」。

語音傳輸

當老張拿起電話的那一刻,端到端的語音信道已經預留好了,一般為DS0= 64Kbps,這條端到端信道其實是由多條 hop-2-hop信道串聯而成的。

此時雙方可以自由說話,語音數據會從保留的語音信道流淌到對方。

從以上的描述來看,信令數據、語音數據是在自己獨立的信道里傳輸,大家井水不犯河水,互不干涉。

TCP

TCP模仿電話原理,也有自己的信令數據、應用層數據,那哪些是信令數據呢?

SYN

ACK

RST

PSH

URG

FIN

依靠這六個信令狀態位,與對方

1)建立連接SYN

2)重置連接RST

3)拆除連接FIN

那什麼是應用層數據呢?就是TCP的服務對象,比如Http。

TCP也想使用電話里的雙信道,但TCP所依賴的IP網路沒有信道的概念,完全是一個共享網路的模式。

TCP沒有雙信道使用,退而求其次,只要信令數據、應用數據放在獨立的IP包傳輸到對方就好,這就是大家最熟悉的TCP工作模式:

1)三次握手建立連接

2)數據傳輸

3)四次握手拆除連接

三次握手最後一個消息是客戶端發過來的ACK,如果讓應用層數據與這個信令數據合二為一,可以減少發送的IP包的數目,還可以提高效率,何樂不為呢?

TCP協議的制定者,為了提高效率,減少IP包的數目,最大可能地將信令數據、應用數據合二為一,各位同學通過抓包,可以看到一個TCP連接,除了第一個SYN包,每個TCP報文都有ACK信令,這就是合二為一的結果!

++++++++++++

如果同學們對計算機網路充滿著好奇,想徹底征服她,來參加我的live,傳授你獨家秘笈,姿勢全解鎖…

Live門票入口:

https://www.zhihu.com/lives/897123723914649600


可以攜帶,親測有效。Windows上調用ConnectEx來建立連接並發數據。此時第三次握手會是一個普通的數據包,加上TCP頭裡ACK標誌等信息。

Add client-side API to support Windows ConnectEx optimizations and TCP Fast Open · Issue #268 · carllerche/mio

  1. In TCP Fast Open, the initial data to send is sent in the same packet as the initial SYN, eliminating one round-trip and thus greatly reducing latency. In Linux, this is done by using sendto (usually used for datagrams) instead of connect and send, as explained in this article: https://lwn.net/Articles/508865/.
  2. Windows"s ConnectEx supports a mode where the kernel will, when it receives the initial SYN/ACK in the TCP handshake from the server, immediately sends a buffer of data that was supplied in the ConnectExcall. This doesn"t reduce any network-level latency, but it does eliminate a context switch between the kernel and userspace. See the lpSendBuffer and dwSendDataLength arguments in the documentation:https://msdn.microsoft.com/en-us/library/windows/desktop/ms737606(v=vs.85).aspx.

TCP客戶端和伺服器之間,建立TCP連接要經過三次報文傳輸。

詳細的過程如下圖所示。

http://d3ojx0qwvsjea2.cloudfront.net/wp-content/uploads/2016/12/24160105/Three-way-Handshake-ex2.png

連接的主動發起者是客戶端,連接的接收方是伺服器。

第三次握手,是客戶端為了告訴伺服器,我已經收到了你發送的SYNC + ACK報文,此時這個報文只帶ACK標誌,SYNC標誌沒有。

客戶端發送這個報文之後,就進入established狀態了。伺服器收到這個報文之後,也進入established狀態。

TCP標準規定,第三次握手的報文,可以攜帶數據。因為此時客戶端已經處於established狀態了呀。

假設第三次握手的報文的seq是x+1,

如果有攜帶數據,下次客戶端發送的報文,seq=伺服器發回的ACK號。

如果沒有攜帶數據,那麼第三次握手的報文不消耗seq。下次客戶端發送的報文,seq序列號還是和第三次握手的報文的seq一樣,為x+1。這是因為,seq和報文中的數據在整條數據流流中的位置是一一對應的。如果報文沒有攜帶數據,那麼seq當然也不會更新。


第三次ACK攜帶data的叫piggyback ACK,以前的三哥教授好像教過


請搜索TCP-fastopen技術,新的Linux內核有的。


我當年做考研題的時候有的題目就說到這個 當時還蠻奇怪


可以攜帶,必需內核支持


RFC 793


握手時發送的也是標準的TCP包,只是標誌位的區別,當然可以和普通的TCP包一樣攜帶數據。

另外TCP最後一次發送數據時還可以把FIN 標誌位置為1,這樣斷開連接時又省了一次。


已經實現了,叫tcp fastopen


你用wireshark抓個http請求看看,會看到這個在第三次握手時就發出去了。


推薦閱讀:

IT公司聘用應屆生的標準是什麼?即,看中應屆生的什麼?
為什麼一些政府網站上顯示今年是 19113 年?
明明是軟體開發的,但別人當你是修電腦的?
Facebook 在不斷分拆獨立業務,豆瓣卻在聚合業務,到底誰是正確的?

TAG:互聯網 | 計算機網路 | 計算機科學 | TCPIP | 網路協議 |