1、TCP报文格式
图 1.1
图1.1所示的为TCP报文格式,它的标准长度是20字节,除非出现选项。确认号、窗口大小以及ECE位和ACK位用于与该报文段的发送方关联的相反方向上的数据流。
序列号字段标识了TCP发送端到TCP接收端的数据流的一个字节,该字节代表着包含该序列号的报文段的数据中的第一个字节。
确认号字段包含的值是该确认号的发送方期待接收的下一个序列号。即最后被成功接收的数据字节的序列号加1。这个字段只有在ACK位字段被启用的情况下才有效,这个ACK位字段通常用于除了初始和末尾报文段之外的所有报文段。
数据偏移(头部长度)字段占用4个比特位,以8字节为单位,最多能表示的TCP头部和选项总长度为60个字节,用来标识数据的起始位置。
URG—紧急(紧急指针字段有效—很少被使用);
ACK—确认(确认号字段有效—连接建立以后一般都是启用状态);
PSH—推送(接收方应尽快给应用程序传送这个数据—没被可靠地实现或用到);
RST—重置连接(连接取消,经常是因为错误);
SYN—用于初始化一个连接的同步序列号;
FIN—该报文段的发送方已经结束向对方发送数据;
SYN位字段会消耗一个序列号,消耗一个序列号也意味着使用重传进行可靠传输。因此,SYN和应用程序字节(还有FIN)是被可靠传输的,不消耗序列号的ACK则不是。
TCP的流量控制由每个端点使用窗口字段来通告一个窗口大小来完成。这个窗口大小是字节数,从ACK号指定的,也是接收方想要接收的那个字节开始。16位字段限制了窗口大小到65535字节,从而限制了TCP的吞吐量。在TCP选项中可以看到窗口缩放选项可允许对这个值进行缩放,给高速和大延迟网络提供了更大的窗口和改进性能。
TCP校验和字段覆盖了TCP的头部和数据以及头部中的一些字段。这个字段是强制的,由发送方进行计算和保存,然后由接收方验证,TCP校验和的计算算法与IP、ICMP和UDP校验和一样。
紧急指针字段只有在URG位字段被设置时才有效。这个“指针”是一个必须要加到报文段的序列号字段上的正偏移,以产生紧急数据的最后一个字节的序列号。TCP紧急机制是一种让发送方给另一端提供特殊标志数据的方法。
2、TCP选项
图 2.1
图2.1所示的为TCP选项数值,每一个选项的头一个字节为“种类”,指明了该选项的类型。种类值为0或1的选项仅占用一个字节。最常见的选项字段就是MSS,连接的每个端点一般在它发送的SYN报文段上指定该选项。与MSS一样,窗口缩放因子选项也只能出现于SYN报文段中,因此当连接建立以后比例因子是与方向绑定的,每个方向的比例因子可各不相同,如果主动打开连接的一方发送了一个非0的比例因子但却没有接收到来自对方的窗口缩放选项,它会将自己发送与接收的比例因子数值都设置为0。
图 2.2
以图2.2为例,为窗口缩放因子选项,该选项占用三个字节:种类1字节、长度1字节、缩放比例1字节,缩放因子最大值为14,能提供窗口的最大值为:65535 * 2^14,该数值约为1GB。因此,TCP使用一个32位的值来维护这个“真实”的窗口大小。
选择确认选项允许TCP单独确认非连续片段;SACK选项只是针对失序的报文段,存在于ACK报文段中,包含一系列的非连续的没有确认的数据的seq range,可以帮助发送方进行有效的重传。
时间戳选项要求发送方在每一个报文段中添加2个4字节的时间戳数值。当使用时间戳选项时,发送方将一个32位的数值填充到时间戳数值字段作为时间戳选项的第一部分;而接收方则将收到的时间戳数值原封不动地填充至第二部分的时间戳回显重试字段。时间戳是一个单调增加的数值,使用该选项可以有效防止回绕序列号。
3、TCP滑动窗口
TCP是一种带累积正向确认的滑动窗口协议。
每个TCP头部的窗口大小字段表明接收端可用缓存空间的大小,以字节为单位。报文段发送方在相反方向上可接受的最大序列号值为TCP头部中ACK号和窗口大小字段之和。
TCP连接的每一端都可收发数据。每个TCP活动连接的两端都维护一个发送窗口结构和接收窗口结构。
图 3.1
图3.1为TCP发送窗口结构,由接收端通告的窗口称为提供窗口,提供窗口的大小是由接收端返回的ACK中的窗口大小字段控制。每个TCP报文段都包含ACK号和窗口通告信息,TCP发送端可以据此调节窗口结构。
窗口左边界不能左移,因为它控制的是已确认的ACK号,具有累积性,不能返回。当得到的ACK号增大而窗口大小保持不变时(通常如此),我们就说窗口向前“滑动”。若随着ACK号增大而窗口却减小,则左右边界距离减小。当左右边界相等时,称之为零窗口。此时发送端不能再发送新数据。
图 3.2
图3.2为TCP接收窗口结构,与发送窗口一样,该窗口结构也包含一个左边界和右边界,但窗口内的字节(图中的4—9字节)并没有区分。接收窗口结构可以帮助了解下次应接收的数据序列号,若接收到的数据序列号在窗口内,则可以存储,否则丢弃。
接收窗口左边界:rcv->ack_seq //接收方的确认号 即:接收方期待接收的发送方序列号!
接收窗口右边界:rcv->ack_seq + rcv->window * rcv->wscale //确认号+窗口大小*窗口缩放比例
对接收端来说,到达序列号小于左边界,被认为是重复数据而丢弃;超过右边界的则超过处理范围,也被丢弃。
注意到由于TCP的累积ACK结构,只有当到达数据序列号等于左边界时,窗口才能向前滑动。