而 Linux 核心定義在 include/uapi/linux/tcp.h
中。這個結構體中,有針對 big endian 或 little endian 定義欄位。為了方便,這邊省略了 little endian 時的定義:
除此之外,對應欄位的 mask 也有定義:
source
與 dest
這兩個欄位紀錄的各自是「從發送方的哪個 port 出發」以及「送往接收方的哪個 port」。老樣子,因為 IP 位址已經紀錄在 L3 的 IP header 中了,所以這兩個欄位只會紀錄 port 的編號,不會紀錄 IP。
seq
–- 滑動視窗演算法使用的編號TCP 的可靠傳輸使用滑動視窗演算法。而使用滑動視窗演算法中,每個封包需要使用一個 sequence number,而這個 seq
欄位就是這個 sequence number。
而與前述的滑動視窗演算法稍有不同的是:TCP 提供的傳輸服務是一個「位元流」,所以這個 seq
並不是指封包的編號,而是指「底下 Data 的第一個位元,在整個位元流中的位置」。
ack
與 ack_seq
–- Cumilated ACK 的編號如果 ack
位元被設為 1
,表示這個封包會是個 ACK,而這時 qck_seq
欄位表示的就是 cumilated ACK 中,表達「這個 sequence number 以前的資料,我都收到了」的那個 sequence number。與上述的 seq
欄位類似,這個 ack_seq
註記的 sequence number,並不是封包的編號,而是「到這個位元流的哪個位置以前的資料,現在都收到了」。
要注意的事情是:只有在 ack
欄位被設為 1
時,這個 ack_seq
才會表示這個封包是一個 ACK,而這個 ack_seq
欄位才會表示上述的意義。否則這個欄位中的資訊不會被使用。
syn
與 fin
–- 建立與結束連線如果 syn
欄位是 1
,表示這個封包是用來請求建立連線; 類似地,若 fin
欄位是 1
,就表示這個封包是用來結束一個連線。
psh
–- 清空緩衝區這裡「清空」的意思不是移除資料,而是 flush。也就是「不論 buffer 中的資料有沒有滿,都立刻將裡面的資料移至下個階段處理」。
以發送方收到 psh
被設為 1
的封包為例。前面有提到:TCP 傳輸時,發送方的資料會先被 buffer 起來,直到累積到一定的量才會被打包為 TCP 封包傳輸。而當發送方從接收方收到一個 psh
被設定的封包時,buffer 中的資料會直接移給下一個階段,也就是強制打包傳送給發送方。不論發送方當下的 buffer 裡面的東西有沒累積到那個量。
而另外一方面,如果接收方從發送方收到一個 psh
被設定為 1
的封包,那麼不論接收方的 buffer 中有沒有滿,裡面的資料都要移往那台電腦 TCP stack 的下一個階段,把用來接收的 buffer 讓出來。
urg
與 urg_ptr
–- 緊急資料如果 urg
被設定,表示這個封包的 Data 欄位中的第 urg_ptr
開始,有緊急的資料。
window
–- 發送方能傳送的「額度」這個 16 位元的欄位用來讓接收方告訴發送方最多還可以再送多少位元組的資料,以用來做 flow control。要注意的是:這個欄位是拿來做 flow control,也就是用來讓接收方與發送方協調傳輸步調,而不是拿來做 congestion control。「整個網路有多壅塞」這件事情並沒有在 TCP header 中紀錄,而是以其他機制來判斷。