TCP头部固定结构
16位源端端口号 | 16位目的端端口号 | |||
---|---|---|---|---|
32位序号 | ||||
32位确认码 | ||||
4位头部长度 | 6位保留 | 6位标志 | 16位窗口大小 | |
16位校验和 | 16位紧急指针 | |||
选 项(最多40字节) |
a. 16位源端端口值和目的端端口号,数据来源的程序的端口号。因为传输层是端对端的协议,所以从TCP头部可以看出,只有源端端口号和目的端端口号。在TCP中,客户端一般使用系统动态分配的端口号,每个系统的动态端口号区间并不相同。服务器一般使用知名端口,如web服务器使用80端口。
b. 32位序号,TCP中用唯一的序号标识每一个字节流。初始值由双方的系统给出一个随机值ISN,之后的每一个字节加一。在三次握手中,虽然syn同步数据报数据长度为0,但是它占一个单独序号,这是特殊的。
c. 32位确认码,用以确认以及回复对方TCP数据段是否到达。它的值是它要确认的数据段的序号加1,每个TCP报文不但带着自己的序号,还带着对之前数据的确认号。这是TCP数据报可靠的原因之一,应答确认机制。
d. 4位头部长度,和IP4位头部长度相似,所以头部最长为60字节(15 * 4)。
e. 6位标志位:
(1) URG标志:表示紧急指针是否有效。
(2) ACK标志:表示确认码是否有效。我们称携带确认码的报文段为确认报文段。
(3) PSH标志:提示接收端应用程序应该立即从接收缓存区取走数据,以便之后的数据可以存放。(如果应用程序没有取走数据,数据会一直呆在TCP接收缓存区)。
(4) RST标志:标志要求对方重新建立连接。携带RST标志的报文段称为复位报文段。
(5) SYN标志:表示请求建立一个连接。携带SYN标志的报文段为同步报文段。
(6) FIN标志:表示通知对方本端要断开连接了。携带FIN的报文段为结束报文段。
f. 16位窗口大小,是TCP进行流量控制的手段。这里的窗口指的是接收通告窗口,就是告诉对方自己的接收缓存区还能接受多少数据。对方就可以控制发送数据的速度。
g. 16位校验和,由发送端填充。接收端用来检验TCP报文段在传输过程中是否有错误。这个校验和包括检验数据部分,这是TCP可靠的一个重要原因。IP在用校验和检验的时候只检查头部信息。
h. 16紧急指针,用以发送端向接收端发送紧急数据。是一个正的偏移值,当前序号加上这个偏移值,就是下一个数据段的序号。
i. TCP头部选项:
kind(1字节) | length(1字节) | info | |
---|---|---|---|
kind = 0 | |||
kind = 1 | |||
kind = 2 | length = 4 | 最大segment长度(2字节) | |
kind = 3 | length = 3 | 移位数(1字节) | |
kind = 4 | length = 2 | ||
kind = 5 | length = N*8 + 2 | N个边沿块 | |
kind = 8 |
kind = 0 : 选项表结束选项。
kind = 1 : 空操作选项,没有特殊含义。一般用来将TCP选项的总长度添加为4字节的倍数。
kind = 2 : 最大报文段长度选项。在建立连接的时候,连接双方都会发送最大的报文段长度来协商。TCP模块通常会把MSS(max segment size)设置为MTU-40(减去TCP头部长度20字节和IP头部长度20字节,不考虑选项长度),这样发送的最大的报文段长度就不会超过MTU,避免IP分片。对以太网而言,MSS是1500-40,也就是1460字节。
kind = 3 : 窗口扩大因子选项。在建立链接的时候,通信双方会根据此选项来协商窗口扩大因子的大小。在TCP头部中窗口大小是用16位来表示的,所以最大是65535。但是在实际的传输过程中窗口的大小远不止这么大,因为需要网络有更大的吞吐量,所以需要用到窗口扩大因子。扩大方式是每次把初始窗口值向左移扩大因子值个位。一般扩大银子选项是0~14,我们可以修改/proc/sys/net/ipv4/tcp_window_scaling的内核变量来启用或者停用窗口扩大因子选项。和最大报文段选项一样,只能出现在同步报文段,否则将被忽略。
kind = 4 : 选择性确认选项。在TCP通信时,如果某个报文段丢失,那么TCP会重新发送这个报文段以及之后的所有报文段,这样就会有一个问题就是,之前发送的晚到的报文段会被再次发送,这样就会有重复数据发送,会大大降低TCP的传输效率。选择性确认选项(SACK)就是用来改善这种情况的,它可以使TCP只发送丢失的报文段,不必重复发送。SACK也用在连接初始化的时候,表示是否支持SACK。我们可以通过修改/proc/sys/net/ipv4/tcp_sack内核变量来启用或者关闭选择性确认选项。
kind = 5 : SACK的工作选项。每两个块表示一个连续的数据段区间,左边沿表示连续数据段的第一个数据序号,右边沿表示最后一个数据段序号的下一个序号。然后SACK就可以根据区间来确认哪些数据没有收到,以便重新发送丢失的数据段。因为一个区间就要占用8字节,所以一个TCP数据段最多有四个这样的区块
kind = 8 : 时间戳选项。用来较为精准的计算通信双方之间的回路时间(RTT),为TCP的流量控制提供重要信息。我们可以通过proc/sys/net/ipv4/tcp_timestamps内核变量来启用或者关闭时间戳选项。
## TCP连接超时 ##
使用一个客户端去链接一个服务器,然后使用iptable命令过滤并丢弃所有服务器端的连接请求报文,来模拟网络异常,让其重连。然后使用tcpdump抓包观察TCP的超时重连。
一共有六个同步报文段,第一个是第一次请求,之后的五个应该都是超时重连发送的请求。他们的时间间隔分别是1s,2s,4s,8s,16s。因此,TCP一共进行了五次重连。这个次数是由proc/sys/net/ipv4/tcp_syn_retries中定义的。 在五次重连都是失败的时候,TCP会放弃链接并通知应用程序。