今天對網絡數據抓包!查了一下TCP的資料!覺得對大家可能有用就放在這里吧!
TCP 的包頭
SEQ
等于該主機選擇本次連接的初始序號加上報文段中第一個字節在整個數據流中的序號。在連接建立的時候,會隨機選擇一個初始序號,如果發送的數據包中的字節是整個數據流中的第 256 字節到 512 字節。
WINDOW
16 個字節,接受方用來通知發送方,我的接受 buffer 的大小,發送方不能過分的發送,導致接受方的 buffer 溢出。 單位是字節。
SYN
建立連接用的。
ACK
建立連接和數據發送,關閉連接都用。
RST
連接異常。
FIN
關閉連接。
PSH
表示接受方應該盡快把數據發送給應用程序, 現在的 TCP 模塊一般都可以自動識別處理 PSH 。
URG
發送帶外數據。
TCP 的重傳機制 Go-Back-N
接受方不斷發送 ACK 信息和 32 位的 acknowledge seq number, 用來通知發送方,期望接收到數據包的序號,同時也表示已經正確接收的數據。acknowledge
seq number 不一定要連續。
Delayed ACK
TCP 并不是對收到的數據立即發送 ACK 信息,而是希望
ACK 信息隨著數據一起發送。
如果在 200 ms 內,沒有數據需要發送,那么就發送一個不含數據的 ACK 數據包。
這個數據包不應該增加 TCP 的順序編號,接受方應該從數據長度上判斷出這個包是一個控制包。
還有一種算法是如果接收到一個數據包之后,啟動一個計時器,在計時器超時之前沒有可供 piggy back 的數據發送,那么就發送一個 pure ACK ,一個不帶數據包的 ACK 消息。
Nagle 算法
要解決得的問題
只傳一個字節的數據,需要帶上 20 bytes 的 IP
header, 20 bytes 的 TCP header , 效率很低。
解決辦法
讓 TCP 的連接只允許一個 TCP 的小包發送出去而沒有得到確認。也就是說,如果發送了一個小包出去,
那么在沒有收到確認消息之前,不能在發送新的小數據包。
分析
如果往返時間很短的話,在下一個小數據包到來之前,
就收到了對于上一個這個數據包的確認信息,所以在這種情況下, Nagle 算法不會起作用。字節的數據在以太網上的 RTT 大約是 16 ms 。
如果往返時間很長的話,在發送下一個小數據包的時候,還沒有接收到上一個小數據包的確認信息,那么就算擁塞算法允許發送數據包,也不可以發送,這就是 Nagle 算法,這樣就可以把很多小的數據積累起來,
在一個數據包中一起發送。尤其適用于 Rlogin 等交互式服務。
滑動窗口
當收到 ACK 的時候,發送方的窗口變大,也叫開窗, 當發送數據的時候,發送方的窗口變小,也叫關窗。
在窗子完全關閉的時候,不能在發送數據了。
慢啟動
cwnd ,表示擁塞窗口的大小,單位是字節。初始化的時候, cwnd 是一個數據段的大小。cwnd 的增加是一個數據段的長度。
發送方收到一個 ACK 那么就增加 cwnd 。
cwnd = cwnd + MSS
cwnd = min(cwnd,awnd)
問題, 如果是 DUPACK ,那么也應該增加。
問題, 一個 segment 的大小是可變的,假設是個固定值
當出現 3 個 DUPACK 的時候,進入 Fast Recovery 過程。
???當出現超時重傳,則進到 Congestion Avoid 的過程。
當 cwnd 大于 ssthrd ,那么進入 Congestion Avoid 的過程。
Congestion Avoid
收到一個 ACK 的時候,增加 cwnd。
cwnd = cwnd + MSS * MSS / cwnd
cwnd = min(cwnd,awnd)
如果有 3 各重復的 ACK ,那么應該進入 Fast
Recovery 的過程。
如果有重傳,那么應該進入 Slow Start 的過程??梢灾貍鞯谝粋€ Unacknowledged segment ,也可以重傳許多。
DUP ACK 不能增加
Fast Recovery
當收到 3 各 DUPACK 的時候會進入 Fast Recovery .
重傳第一個 unacknowledged segment.
改變 ssthres , sshres = max(flightsize/2, 2*MSS)
改變 cwnd , cwnd = sshres + 3
重置重傳定時器。
如果還有新的 DUPACK 到來,那么 cwnd 還會增加, 每次增加 MSS, 當有 ACK 確認最新的數據,那么 cwnd 設置成為 sshres , 進入 Congestion Avoid 的過程。
問題,如果在 fast Recovery 的過程中,出現重傳, 應該進入 Slow Start 的過程。
發生重傳的處理
cwnd = MSS
sshres = max(flightsize/2, 2*MSS)
重置對于 DUPACK 的計數器
RTO = min(2*RTO, 64 seconds)
如果一個包超過重傳 4 次,那么 TCP 連接關閉。
重置關于重傳的計時器。
停止測量 RTT 和 RTO 。
不再發送新的數據包
當所有 on the fly 的包都得到確認之后,啟動關于重傳的計時器,進入 slow start 的過程
如果在重傳的過程中,還發生了重傳,也就是計時器超時。
重新分組。發送方不一定重傳和原來一模一樣的包,也可以在重傳的包內包含新的數據,以增加吞吐量. 尤其是有很多小包的時候。
應該發送出去多少個重傳的包呢?
如果在 slow start 的時候超時,應該傳送一個 cwnd 那么多的包,cwnd = MSS.
如果在 congestion avoid 的時候超時,應該傳送一個 cwnd 那么多的包,cwnd = MSS.
如果因為三個 dup ack ,那么應該發送 1 個包。
如果在 fast recover 的過程中, 每收到一個 DUP ACK ,增加 cwnd 一個 MSS ,發送一個新包。
RTO 和 RTT 的測量
RTT_Err = RTT_Delay - RTT_Ave
RTT_Ave = RTT_Ave + 0.125 × RTT_Err
RTT_Dev = 0.75 × RTT_Dev + 0.25 × | RTT_Err |
RTO = RTT_Ave + 4 × RTT_Dev
根據實現不同,可能所有的包都作測量,也可能選擇某些包作測量。
由于不是每一個包都有 ack ,那么怎么選擇呢?
Karn 算法:
重傳過程中,不作測量。因為不知道 ACK 是對首次的包的 ACK ,還是對重傳的包的 ACK
重傳之后, RTO 加倍。防止連續重傳。
吞吐量
吞吐量 = 帶寬 * 往返時間
亂序的包
如果收到亂序的包,那么就應該立即發送 ACK ,以確保對方知道 DUPACK ,然后及時重傳。
參考文獻
http://www.faqs.org/rfcs/rfc2001.html RFC 2001 - TCP Slow Start, Congestion Avoidance, Fast Retransmit, and Fast Recovery Algorithms
http://www.ietf.org/rfc/rfc2581.txt TCP Congestion Control
http://www.ietf.org/rfc/rfc1122.txt RFC 1122 Requirements for Internet H osts - Communication Layers