簡要介紹
TCP(Transmission Control Protocol,傳輸控制協議)是一種面向連接的、可靠的、基於字節流的通信協議,數據在傳輸前要建立連接,傳輸完畢后還要斷開連接。
客戶端在收發數據前要使用 connect() 函數和服務器建立連接。建立連接的目的是保證IP地址、端口、物理鏈路等正確無誤,為數據的傳輸開辟通道。
TCP建立連接時要傳輸三個數據包,俗稱三次握手(Three-way Handshaking)。可以形象的比喻為下面的對話:
- [Shake 1] 套接字A:“你好,套接字B,我這里有數據要傳送給你,建立連接吧。”
- [Shake 2] 套接字B:“好的,我這邊已准備就緒。”
- [Shake 3] 套接字A:“謝謝你受理我的請求。”
TCP數據報結構
具體內容參照
https://www.cnblogs.com/cyx-b/p/12492872.html
只對帶陰影的幾個字段重點說明一下:
1) 序號:Seq(Sequence Number)序號占32位,用來標識從計算機A發送到計算機B的數據包的序號,計算機發送數據時對此進行標記。
2) 確認號:Ack(Acknowledge Number)確認號占32位,客戶端和服務器端都可以發送,Ack = Seq + 1。
3) 標志位:每個標志位占用1Bit,共有6個,分別為 URG、ACK、PSH、RST、SYN、FIN,具體含義如下:
- URG:緊急指針(urgent pointer)有效。
- ACK:確認序號有效。
- PSH:接收方應該盡快將這個報文交給應用層。
- RST:重置連接。
- SYN:建立一個新連接。
- FIN:斷開一個連接。
對英文字母縮寫的總結:Seq 是 Sequence 的縮寫,表示序列;Ack(ACK) 是 Acknowledge 的縮寫,表示確認;SYN 是 Synchronous 的縮寫,願意是“同步的”,這里表示建立同步連接;FIN 是 Finish 的縮寫,表示完成。
連接的建立(三次握手)
為了理解得更深刻,我查找了很多資料。
①知乎
https://zhuanlan.zhihu.com/p/43838752
TCP把連接作為最基本的對象,每一條TCP連接都有兩個端點,這種斷點我們叫作套接字(socket),它的定義為端口號拼接到IP地址即構成了套接字,例如,若IP地址為192.168.4.16 而端口號為80,那么得到的套接字為192.168.4.16:80。
最開始的時候客戶端和服務器都是處於CLOSED狀態。主動打開連接的為客戶端,被動打開連接的是服務器。
1、TCP服務器進程先創建傳輸控制塊TCB,時刻准備接受客戶進程的連接請求,此時服務器就進入了LISTEN(監聽)狀態;
2、TCP客戶進程也是先創建傳輸控制塊TCB,然后向服務器發出連接請求報文,這是報文首部中的同部位SYN=1,同時選擇一個初始序列號 seq=x ,此時,TCP客戶端進程進入了 SYN-SENT(同步已發送狀態)狀態。TCP規定,SYN報文段(SYN=1的報文段)不能攜帶數據,但需要消耗掉一個序號。
3、TCP服務器收到請求報文后,如果同意連接,則發出確認報文。確認報文中應該 ACK=1,SYN=1,確認號是ack=x+1,同時也要為自己初始化一個序列號 seq=y,此時,TCP服務器進程進入了SYN-RCVD(同步收到)狀態。這個報文也不能攜帶數據,但是同樣要消耗一個序號。
4、TCP客戶進程收到確認后,還要向服務器給出確認。確認報文的ACK=1,ack=y+1,自己的序列號seq=x+1,此時,TCP連接建立,客戶端進入ESTABLISHED(已建立連接)狀態。TCP規定,ACK報文段可以攜帶數據,但是如果不攜帶數據則不消耗序號。
5、當服務器收到客戶端的確認后也進入ESTABLISHED狀態,此后雙方就可以開始通信了。

②C語言中文網
http://c.biancheng.net/cpp/html/3042.html
使用 connect() 建立連接時,客戶端和服務器端會相互發送三個數據包,請看下圖:
客戶端調用 socket() 函數創建套接字后,因為沒有建立連接,所以套接字處於CLOSED
狀態;服務器端調用 listen() 函數后,套接字進入LISTEN
狀態,開始監聽客戶端請求。
這個時候,客戶端開始發起請求:
1) 當客戶端調用 connect() 函數后,TCP協議會組建一個數據包,並設置 SYN 標志位,表示該數據包是用來建立同步連接的。同時生成一個隨機數字 1000,填充“序號(Seq)”字段,表示該數據包的序號。完成這些工作,開始向服務器端發送數據包,客戶端就進入了SYN-SEND
狀態。
2) 服務器端收到數據包,檢測到已經設置了 SYN 標志位,就知道這是客戶端發來的建立連接的“請求包”。服務器端也會組建一個數據包,並設置 SYN 和 ACK 標志位,SYN 表示該數據包用來建立連接,ACK 用來確認收到了剛才客戶端發送的數據包。
服務器生成一個隨機數 2000,填充“序號(Seq)”字段。2000 和客戶端數據包沒有關系。
服務器將客戶端數據包序號(1000)加1,得到1001,並用這個數字填充“確認號(Ack)”字段。
服務器將數據包發出,進入SYN-RECV
狀態。
3) 客戶端收到數據包,檢測到已經設置了 SYN 和 ACK 標志位,就知道這是服務器發來的“確認包”。客戶端會檢測“確認號(Ack)”字段,看它的值是否為 1000+1,如果是就說明連接建立成功。
接下來,客戶端會繼續組建數據包,並設置 ACK 標志位,表示客戶端正確接收了服務器發來的“確認包”。同時,將剛才服務器發來的數據包序號(2000)加1,得到 2001,並用這個數字來填充“確認號(Ack)”字段。
客戶端將數據包發出,進入ESTABLISED
狀態,表示連接已經成功建立。
4) 服務器端收到數據包,檢測到已經設置了 ACK 標志位,就知道這是客戶端發來的“確認包”。服務器會檢測“確認號(Ack)”字段,看它的值是否為 2000+1,如果是就說明連接建立成功,服務器進入ESTABLISED
狀態。
至此,客戶端和服務器都進入了ESTABLISED
狀態,連接建立成功,接下來就可以收發數據了。
③《TCP/IP入門經典》
TCP 的一切操作都是在一個連接上下文的環境中完成的。TCP 通過連接發送和接收數據,而這個連接必須根據TCP的規則進行請求、打開和關閉。
TCP 的功能之一是為應用程序提供訪問網絡的接口。這個接口是通過 TCP端口提供的,而為了通過端口提供連接,必須打開TCP與應用程序的接口。TCP支持以下兩種打開狀態。
被動打開 :某個應用程序進程通知TCP准備通過TCP端口接收連接,這樣就會打開TCP到應用程序的連接,從而為參與連接請求做准備。
主動打開 :程序要求TCP發起與另一台計算機(處於被動打開狀態)的連接,這就是主動打開狀態。
在通常情況下,想接收連接的應用程序(比如 FTP 服務器)會把自身及其 TCP 端口置於被動打開狀態。在客戶端計算機上,FTP客戶端的TCP狀態一般是關閉的,直到用戶發起一個從FTP客戶端到FTP服務器的連接,這對於客戶端來說就是主動打開。處於主動打開狀態的計算機(比如客戶端)上的TCP軟件會開始一些用於建立連接的信息交換,這種信息交換被稱為“三次握手”。
客戶端是指向網絡中的其他計算機請求或接收服務的計算機。
服務器是指向網絡中其他計算機提供服務的計算機。
TCP發送的數據分段的長度是不定的。在一個數據分段內,每字節數據都被分配一個序列號。接收端計算機必須為接收到的每個字節數據都發送一個確認信號。因此,TCP通信是一種傳輸與確認的系統。TCP報頭中的“序列號”和“確認號”字段(見前面小節的介紹)讓通信的TCP軟件能夠定期更新傳輸的狀態。
實際上,數據分段中並不是為每個字節都單獨編了一個序列號,而是在報頭的“序列號”字段指定了數據分段第一個字節的序列號。
這個規則有一個例外。如果數據分段是連接初期使用的,“序列號”字段里包含的是ISN,它的值比數據分段中第一個字節的序列號小 1(也就是說,第一個字節的序列號是ISN加1)。
如果數據分段被成功接收,接收端計算機會利用“確認號”字段告訴發送端計算機它接收到哪個字節。在確認消息中,“確認號”字段的值是已接收的最后一個序列號加1。換句話說,“確認號”字段中的值是計算機准備接收的下一個序列號。
如果發送端計算機沒有在指定時間內收到確認消息,它會從已經得到確認的下一字節重新發送數據。