您的位置:

TCP首部详解

一、TCP首部结构

TCP首部由20字节的固定长度组成,其中有12个字节是固定的,剩余8个字节是可选的。TCP首部的结构如下:
  0                   1                   2                   3   
  0 1 2 3 4 5 6 7 8 9  0 1 2 3 4 5 6 7 8 9  0 1 2 3 4 5 6 7 8 9  0 1 2 3 4 5 6 7 8 9 
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |           Source Port          |       Destination Port        |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                        Sequence Number                        |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                     Acknowledgment Number                     |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |  Data |A|C|K|P|R|S|F|        Window Size                       |
 | Offset|N|E|G|S|S|Y|I|                                           |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |           Checksum            |         Urgent Pointer          |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                    Options                    |    Padding    |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
其中,各字段的含义如下: - 16位源端口(Source Port):发送方端口号(发送方在本机的标识) - 16位目的端口(Destination Port):接收方端口号(接收方在本机的标识) - 32位序列号(Sequence Number):字节流中的第一个字节的序列号,为了处理乱序到达的数据包 - 32位确认号(Acknowledgment Number):期望接收的下一字节的序列号,为了确认对方是否已经接收到自己发出的报文 - 4位报文头长度(Data Offset):以32位字长为单位的数据偏移量,指定数据从哪个偏移开始 - 6位保留位(RSV):保留,必须是0 - 6位标记位(Flags):6个标志位,依次分别为URG、ACK、PSH、RST、SYN和FIN - 16位窗口大小(Window Size):接收端缓冲区大小 - 16位校验和(Checksum):校验和,用于检验TCP头部和数据部分的错误(软件实现) - 16位紧急指针(Urgent Pointer):紧急指针,指出TCP紧急数据的字节数 - 可选项(Options):根据需要,在TCP头部中添加一些可选项(如时间戳、SACK选项等) - 填充(Padding):由于选项长度不一定是4的倍数,因此需要进行填充使长度为4的倍数

二、TCP标志位

TCP标志位是TCP首部中很重要的一部分,用于标识TCP连接的状态和控制TCP报文的传输。TCP标志位包括URG、ACK、PSH、RST、SYN和FIN六种标志。下面是各标志位的含义: - URG:表示TCP报文中有紧急数据,通知对端处理紧急数据 - ACK:表示确认号(Acknowledgment Number)有效,通知发送方已收到对方的数据 - PSH:表示TCP缓存中的数据应立即发送而不是等待缓存填满 - RST:表示连接复位,通知对端关闭连接 - SYN:表示发起一个新连接 - FIN:表示TCP连接已经关闭 因此,TCP报文的状态就可以通过标志位表示。例如,当SYN=1且ACK=0,表示此时正在建立连接;当SYN=1且ACK=1,表示此时连接已经建立;当FIN=1,表示连接正在关闭。

三、TCP窗口大小

TCP窗口大小指的是接收方缓存区的大小,其在TCP传输过程中起到了非常重要的作用。接收方通常会不断将TCP首部中的窗口大小信息发送给发送方,发送方依据此信息动态调整数据发送速率。 在TCP数据传输过程中,若发送方发现接收方的窗口大小为0,则会停止发送数据,直到接收方再次通知窗口大小不为0。这样可以减少网络拥塞的产生。同时,接收方的窗口大小也可以用来反馈网络拥塞信息,当接收方发现自己的窗口大小没有变大时就会认为网络发生拥塞。

四、TCP拥塞控制

TCP协议通过拥塞窗口(Congestion Window)来实现拥塞控制。当网络拥塞时,TCP发送方就会减小拥塞窗口的大小,从而减少发送速率。拥塞窗口的大小由拥塞避免算法和拥塞控制算法共同决定。 拥塞避免算法是一种保证网络不会过早进入拥塞状态的算法,其根据接收方的窗口大小不断调整拥塞窗口的大小。拥塞控制算法则是对拥塞状态进行控制的算法,其在检测到网络拥塞时会立即减小拥塞窗口的大小,从而有效控制网络拥塞的发生。

五、TCP头部可选项

TCP头部中还可以添加一些可选项,目的是为了支持更多的功能。例如,常用的时间戳选项(Timestamp Option)可以记录数据包到达时间,以此来计算延迟等网络性能指标。另外,选择性确认选项(Selective Acknowledgment Option,SACK)也是TCP头部中常用的一种选项,可以用来减少重传的数据大小,提高网络传输效率。 对于TCP头部中的选项,需要注意以下细节: - 选项需要遵循长度为4字节的整数倍。因为TCP头部中的长度是固定的,而且选项会使TCP首部变长,如果选项的长度不是4字节的整数倍,就需要添加填充(Padding),以使总长度为4字节的整数倍。 - 某些选项可能会被中间路由器或者应用层协议过滤,因此实际使用中需要谨慎。

六、完整代码实现

下面是基于Python语言的TCP头部的完整代码实现:
import struct

# 定义TCP首部结构
tcp_header = struct.Struct('! H H L L B B H H H')

# 定义TCP标志位
TCP_URG = 0b010000
TCP_ACK = 0b001000
TCP_PSH = 0b000100
TCP_RST = 0b000010
TCP_SYN = 0b000001
TCP_FIN = 0b000000

# 定义TCP首部类
class TCPHeader:
    def __init__(self, src_port, dst_port, seq_num, ack_num, flags, window_size):
        self.src_port = src_port  # 源端口
        self.dst_port = dst_port  # 目的端口
        self.seq_num = seq_num    # 序列号
        self.ack_num = ack_num    # 确认号
        self.data_offset = 5     # 数据偏移
        self.reserved = 0        # 保留
        self.flags = flags       # 标志位
        self.window_size = window_size    # 窗口大小
        self.checksum = 0        # 校验和
        self.urgent_pointer = 0  # 紧急指针
        self.options = bytes()   # 可选项
        self.padding = bytes()   # 填充

    # 将TCP头部打包成二进制数据
    def pack(self):
        data_offset = (self.data_offset << 4) | 0
        flags = self.flags
        tcp_header_pack = tcp_header.pack(
            self.src_port,    # 源端口
            self.dst_port,    # 目的端口
            self.seq_num,     # 序列号
            self.ack_num,     # 确认号
            data_offset,      # 数据偏移
            self.reserved,    # 保留
            flags,            # 标志位
            self.window_size, # 窗口大小
            self.checksum,    # 校验和
            self.urgent_pointer # 紧急指针
        )

        # 添加选项和填充
        header = self.options + self.padding
        return tcp_header_pack + header
以上就是TCP首部的详细解析及代码实现。