一、源端口与目的端口

1. 源端口

16位的源端口号

2. 目的端口

16位的目的端口号

二、序列号

在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。

  • 长度32位,可表示的序列号范围:0 ~ 2^32-1
  • 序列号,表示当前TCP报文的数据部分的第一个字节的序号

三、确认号

  • 长度32位,可表示的序列号范围:0 ~ 2^32-1
  • 确认号,表示告诉对方我已成功收到所有序号小于该确认号的字节,所以也同样可以表示我期望收到的下一个字节的序号

四、数据偏移量

  • 本字段表示TCP报文段的数据部分起始位置距离TCP报文段的起始位置的偏移量,即TCP报文段首部长度
  • 长度4位,但该字段的单位是32位,即实际偏移量为该字段的数值乘32
  • 4位二进制数最大值为15,故可得到TCP报文最大头部长度为15 * 32bits = 60 Bytes

    五、保留

占6位,保留为今后使用,但目前应置0。

六、控制位

1. 紧急(URGent)

当URG=1的时候,表示该报文段中有紧急数据。

举一个例子,两个主机在进行TCP通信,主机A通过TCP连续给主机B发送一个较大的文件,这时如果主机A想要立刻停止发送这个文件,他当然可以给B发送一个正常的报文段,里面告诉主机B:“ 我不想继续发这个文件了,你也可以把之前的那些数据扔了吧!”,但在这种情况下,主机B收到这个报文段,会先将数据放到接收缓存中,等待之前接收到的数据处理完再处理你这条数据,这就造成了一些不必要的开销。所以紧急指针,顾名思义,它提供了一种更加紧急的做法,发送方将应用程序要紧急发送的数据加入到一个正常的TCP报文的数据部分的最前端,并且对该TCP报文的URG标记和紧急指针字段进行相应的设置。而在接收方,TCP可以很快的检测到这个报文段带有URG标记,从而直接将你的紧急数据交付给上层应用程序,以减少上文所说的不必要的开销。

值得注意的是,在查找相关资料的时候,很多资料都表示TCP的URG数据由于定义和实现上的混乱,当前已不建议使用

2. 确认(ACKnowledgment)

  • 仅当ACK=1时确认号字段才有效
  • TCP规定,在连接建立后所有传送的报文段都必须把ACK置1

    3. 推送(PuSH)

    在一个使用TCP协议的通信的过程中,TCP会尝试将数据组合成一个一个的逻辑上的块(logical chunks)从而优化传输的吞吐量,例如每次应用send()的数据就可以看作一个逻辑块,而PSH标记就和这个过程相关。

PSH标记通常用于标志一个逻辑块的末尾,例如发送方send()了2000Bytes的数据到发送缓存,而TCP会分两次将2000Bytes的数据发走,而通常只有第二个TCP数据包才会有PSH标记,因为这个数据包是一个逻辑块的“末尾”。

PSH标记通常并不是由发送方应用程序控制的,而是由操作系统的TCP层控制。

由于发送方应用程序无法控制PSH标记,所以我们更关心PSH标记对于接收方的作用。在接受方,PSH标记告诉TCP层立刻将接收缓存中的全部数据交付应用程序而不是等待接收缓存被填满
接收方的recv()函数只有在以下三个情况下才会从接收缓存中收到数据:

  • 接收到的数据带有PSH标记
  • 接收缓存被占满
  • 距离上一次收到数据过去了0.5秒
    所以可以说PSH对接收方的作用就是使得应用程序更快的接收数据。

参考资料:http://smallvoid.com/article/winnt-tcp-push-flag.html

4. 重置(ReSeT)

当RST=1的时候,表明TCP连接中出现某些差错,必须关闭或重建连接。一种比较常见的例子是客户端给服务器的某个关闭的端口或者处于TIME_WAIT状态的端口发送数据,会收到服务器发回的RST数据段。

5. 同步(SYNchronization)

在建立TCP连接时用来同步序号。

三次握手的前两次的报文段的SYN都为1。

6. 终止(FIN)

用来释放一个连接。当FIN=1时,表明此报文段的发送方的数据已发送完毕,并要求释放连接

七、窗口

窗口值表示,本报文段发送方的接收窗口的大小。

八、校验和

用于校验数据段首部和数据部分是否出现比特差错。

九、紧急指针

仅当URG标记等于1时才有意义。它指出本报文段中的紧急数据部分的字节数。

十、选项和填充

TCP最初只规定了一种选项即最大报文段长度MSS(Maximum Segment Size)。我们知道,如果TCP报文段的数据部分非常小如只有1Byte,那么加上40Bytes的TCP首部和IP首部,通信的传输效率是很低的,所以我们希望TCP的数据部分要尽可能地大。但由于MTU的限制,IP层会对数据分片,分片同样会造成很多不必要的开销,所以我们又希望TCP数据部分不要太大导致最终需要下层分片,这就引入了MSS。在一个TCP通信中,MSS规定了TCP报文段的数据部分的最大长度

在TCP建立的时候,通信双方互相告知对方自己支持的MSS值,而两个传输方向允许有不同的MSS,如果MSS不被特别设置,则默认值为536Bytes。

可以看出,TCP的MSS正常情况下保证了最终的IP数据包不会太长超过MTU以至于需要IP层分片。但这里有一个疑问,既然IP层的分片就是为了保证IP层数据不超过MTU,那么为什么TCP又要规定MSS来保证数据不会过长呢?可以想到,如果TCP对数据长度不做限制,交给IP层一个很长的TCP报文段,而IP层对这个报文段做了分片处理,但如果传输过程中某一个分片丢失了,在接受方就不可能组装出一个完整的IP报文,最终会导致TCP把这个很长的报文段全部重传,花销就会很大。而当设置了MSS后,TCP交给IP层的数据就不会超过MSS+20,所以就算传输出现了差错,TCP也只用重传这个小的报文段,就可以减小花销。

随着互联网的发展,又陆续增加了几个选项。如窗口扩大选项、时间戳选项、选择确认(SACK)选项,这里不做详细说明。

填充(Padding) 是为了保证最终的选项字段是32bits的整数倍。

最后修改:2019 年 09 月 23 日
如果觉得我的文章对你有用,请随意赞赏