前言:在FPGA上實現TCP協議實際是一個不太好的計划,因為FPGA最擅長的是流水線處理方式,而TCP存在交互,導致FPGA需要進行反饋式的處理。但是由於項目新增的附加要求而又只能在FPGA上去實現TCP協議,才有了這篇總結。
關於在FPGA上實現TCP的具體過程在另外一篇隨筆上進行詳細介紹。
TCP報文格式:
源端口號(16bit) |
目的端口號(16bit) |
|||||||
序列號(32bit) |
||||||||
確認序列號(32bit) |
||||||||
首部長度 (4bit) |
保留(6bit) |
URG |
ACK |
PSH |
RST |
SYN |
FIN |
窗口(16bit) |
校驗和(16bit) |
緊急指針(16bit) |
|||||||
選項和填充 |
||||||||
數據 |
ARP報文格式:
以太網目的地址(48bit) |
以太網源地址(48bit) |
幀類型 (16bit) |
|||||
硬件類型(16bit) |
協議類型(16bit) |
硬件地址長度(8bit) |
協議地址長度(8bit) |
操作碼(16bit) |
發送者硬件地址(48bit) |
||
發送者IP地址(32bit) |
目標硬件地址(48bit) |
目標IP地址(32bit) |
TCP數據傳輸流程:
搭建的測試環境很簡單,就是用一根網線將兩台筆記本連接起來,其中一台電腦上模擬客戶端,另一台電腦模擬服務端,用wireshark進行報文抓取。
測試地址如下:
交互端 |
MAC地址 |
IP地址 |
TCP端口號 |
服務器(Server) |
a0:88:69:8f:2f:64 |
192.168.1.124 |
6920 (0x1b08) |
客戶(Client) |
a0:88:b4:77:46:44 |
192.168.1.115 |
3005 (0x0bbd) |
1. 地址解析(ARP)
(1)客戶端向服務器發送一個尋址ARP包。
客戶端發送ARP報文,尋找ip地址為192.168.1.115的主機的mac地址是多少。
(2)服務器收到ARP包后,向客戶端發送一個帶地址的ARP包。
服務端告訴客戶端,我的mac地址是a0:88:69:8f:2f:64。
ARP結束(在TCP數據傳輸的后續過程中還會進行多次這樣的ARP過程)。
2.TCP交互過程:
序列號 |
確認序列號 |
SeqNum |
AckNum |
2.1 建鏈(三次握手)
使用socket調試工具進行tcp調試。
STEP1:客戶端向服務器發送一個數據包(SYN),請求建立連接。Flags=0x02
初始SeqNum(ISN)由客戶端隨機產生,AckNum為0。
[SYN]包:SeqNum=0x753bb0dd AckNum=0x00000000
STEP2:服務器收到SYN請求數據包后,對客戶端進行確認。Flags=0x12
初始SeqNum(ISN)由服務器隨機產生,AckNum=客戶端SeqNum + 1。
[SYN,ACK]包:SeqNum=0x98d82910 AckNum=0x753bb0de
STEP3:客戶端收到確認包后,再對服務器進行確認。Flags=0x10
SeqNum=收到上一幀的AckNum,AckNum=收到上一幀的SeqNum + 1。
[ACK]包:SeqNum=0x753bb0de AckNum=0x98d82911
2.2 數據傳輸(數據包+ACK包)
STEP1:發送數據:客戶端向服務器發送一個帶有數據的數據包。Flags=0x18
SeqNum=收到上一幀的AckNum,AckNum=收到上一幀的SeqNum。
STEP2:確認收到:服務器收到該數據包,向客戶端發送一個確認包。Flags=0x10
SeqNum=收到上一幀的AckNum,AckNum=收到上一幀的SeqNum + payload字節長度。
(1)發送長度為10字節的數據
[PUSH,ACK]包:SeqNum=0x753bb0de AckNum=0x98d82911
[ACK]包:SeqNum=0x98d82911 AckNum=0x753bb0e8
(2)發送長度為14字節的數據
[PUSH,ACK]包:SeqNum=0x753bb0e8 AckNum=0x98d82911
[ACK]包:SeqNum=0x98d82911 AckNum=0x753bb0f6
2.3 斷鏈(四次揮手)
STEP1:客戶端完成數據傳輸后,主動向服務器發送一個終止包(FIN)。Flags=0x11
SeqNum=收到上一幀的AckNum,AckNum=收到上一幀的SeqNum。
[FIN,ACK]包:SeqNum=0x753bb101 AckNum=0x98d82911
STEP2:服務器收到終止數據包后,向客戶端發送確認包進行確認。Flags=0x10
SeqNum=收到上一幀的AckNum,AckNum=收到上一幀的SeqNum + 1。
[ACK]包:SeqNum=0x98d82911 AckNum=0x753bb102
STEP3:服務器完成數據傳輸后,向客戶端發送一個終止包(FIN)。Flags=0x11
SeqNum=收到上一幀的AckNum,AckNum=收到上一幀的SeqNum。
[FIN,ACK]包:SeqNum=0x98d82911 AckNum=0x753bb102
STEP4:客戶端收到終止數據包后,向服務器發送確認包進行確認。Flags=0x10
SeqNum=收到上一幀的AckNum,AckNum=收到上一幀的SeqNum + 1。
[ACK]包:SeqNum=0x753bb102 AckNum=0x98d82912
3.TCP重傳機制
TCP重傳目的是防止報文的丟失。在使用TCP進行數據傳輸時,啟動重傳計時器(retransmission timer),在收到ACK確認報文后,停止重傳計時器。TCP重傳過程中有兩個重要的參數,往返時間(RTT)和重傳超時(RTO)。RTT是指發送端口從報文發出直至收到ACK確認報文所花費的時間。通過對RTT的值多次測量求平均來確定RTO的值。在默認配置下,Windows系統最大的重傳次數為5次,Linux系統最大的重傳次數為15次。
4. 分片、分段
4.1. 最大傳輸單元(MTU)
分片是針對IP協議存在的,IP報文的分片與重組是在網絡層完成的。在以太網中,MTU=1500字節,對長度大於MTU的報文進行分片處理,分片后的IP報文不一定按序到達對端。
4.2. 最大分段大小(MSS)
分段是針對TCP協議存在的,TCP報文的分段與重組是在傳輸層完成的。MSS是指TCP報文每一次可以傳輸的最大數據段,TCP協議在三次握手建立連接的前兩次握手中會協商雙方的MSS值,MSS值的配置在TCP協議的選項字段中,TCP連接的雙方會在握手中通過MSS值通知對方自己能夠接收數據段的最大長度。
在一般情況下,MSS=MTU-IP首部長度-TCP首部長度=1500-20-20=1460字節。如果在三次握手的過程中不對MSS值進行配置,默認的MSS為536字節。
TCP的options字段:
5. 滑動窗口技術
由於FPGA資源有限,在FPGA中一般無法實滑動窗口機制。
在發送端將數據分為四類:在窗口之外的已經成功發送並且被確認的數據、在窗口內的已經發送但未被確認的數據、在窗口內的接收端允許發送但未發送的數據、在窗口之外的接收端不允許發送的數據。
在接收端將數據分為三類:已經接收並回復確認但未被上層應用接收的數據、已經接收但未回復確認的數據、等待接收的數據。
注:在使用TCP協議進行數據傳輸中,並不是對於每一個報文段都回復ACK包,而是有可能對兩個甚至多個報文段只回復一個ACK包。