TCP详解(三)

TCP报文段的首部格式

在这里插入图片描述

  • 源端口和目的端口:各占2个字节,分别写入源端口号和目的端口号。
  • 序号:占4个字节,简单的说,就是本报文段中所发送的数据的第一个字节的序号。范围是【0 ~ 2^32-1】,也就是说,序号增加到 2 ^32 - 1后,下一个序号就又回到0。
  • 确认号:占4个字节,是期望收到对方下一个报文段的第一个数据字节的编号。例如:B正确收到了A发送过来的一个报文段,其序号字段值是501,而数据长度是200字节(序号501-700),这表明B正确收到了A发送的到序号700为止的数据。因此,B期望收到A的下一个数据序号是701,于是B在发送给A的确认报文字段中把确认号置为701.
    • 由于序号字段有32位长,可对4GB的数据进行编号。在一般情况下可保证当序号重复使用时,旧序号的数据早已通过网络到达终点了。
  • 数据偏移(头部长度):占4位,这个字段指出TCP报文段的首部长度。单位是4字节。由于4位可以表示的最大数字是15,因此说,TCP首部最大是60字节,即选项长度不能超过40字节。
  • 保留:占6位,保留以后使用,但是现在应置为0。
  • 紧急URG:当URG为1时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于优先级高的数据)。而不是按原来的排队顺序来传送。
    • 当URG置为1时,发送应用进程就告诉发送方的TCP有紧急数据需要传送。于是发送方TCP就把紧急数据插入到本数据段数据的最前面,而在紧急数据后面的数据任然是普通数据。这时要与首部的紧急指针配合一起使用。
  • 确认ACK:仅当ACK为1时确认号字段才有效。当ACK为0时,确认号字段无效。TCP规定,在建立连接后所有传送的数据报文段都必须把ACK设置为1。
  • 推送PSH:当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令之后立即就能够收到对方的响应。在这种情况下,TCP就可以使用推送操作。这时,发送方TCP把PSH置为1,并立即创建一个报文段数据发送出去,接收方TCP在收到PSH为1的段后,就尽快的交付给应用程序,而不是等到整个缓存满了以后才向上交付。
  • 复位RST:当RST为1时,表明TCP出现了严重的差错(如主机崩溃),必须释放连接。然后在重新建立运输连接。RST置为1还用来拒绝一个非法的报文段或拒绝打开一个连接。
  • 同步SYN:在建立连接时用来同步序号,当SYN=1而ACK=0时,表明这是一个连接请求报文段。对方若同意建立连接,则应该在响应的报文段中使用SYN=1和ACK=1。因此SYN=1就表示一个连接请求或连接接受报文。
  • 终止FIN:用来释放一个连接。当FIN=1时,表明此报文段的发送方的数据已发送完毕,并要求释放运输连接。
  • 窗口:占2个字节,窗口值【0~2^16 - 1】之间的一个整数,窗口值告诉对方:从报文段首部中的确认号算起,接收方目前允许对方发送的数据量(以字节为单位)。之所以要有这个限制,是因为接收方的数据缓存空间是有限的。总之,窗口值作为接收方让发送方设置其发送窗口的依据。
    • 窗口字段明确指出了现在允许对方发送的数据量,窗口值经常在动态变化着。
  • 检验和:占2个字节,检验和检验的字段包括首部和数据这两部分。在计算检验和时,要再TCP报文段的前面加上12字节的伪首部。
    • 伪首部包括:4字节的源IP地址、4字节的目的IP地址、1字节的全0、1字节的协议号(TCP的协议号是6)、2字节的长度(TCP的长度)。
    • 计算方法和UDP的计算方法是一样的。
  • 紧急指针:占2字节,紧急指针只在URG=1时才有意义,它指出本报文段中的紧急数据的字节数。紧急指针指出了紧急数据的末尾在报文段中的位置。当所有紧急数据处理完之后,TCP就告诉应用程序恢复到正常操作。即使窗口为0时也可发送紧急数据。
  • 选项:长度可变,最长可达40字节。
    • 最大报文段长度MSS,MSS是每一个TCP报文段中的数据字段的最大长度。 MSS要适当大,要考虑对网络的利用率、要考虑在IP层最好不要分片等等。还有在一条路径上确定的不需要分片的MSS,如果该走另一条路径就可能需要分片,因此,最佳的MSS是很难确定的。在连接建立的过程中,双方都把自己能够支持的MSS写入这一字段,以后就按照这个数值传送数据,两个传送方向可以有不同的MSS值。若主机未填写这一字段,则MSS的默认值是536字节,因此所有在互联网上的主机能够接受的报文段应为长度556字节。
    • 窗口扩大选项:TCP首部中窗口字段长度是16位,因此最大的窗口大小是64K字节,虽然对于早期的互联网是足够用的,但是对于包含卫星信道的网络(长粗管道),传播时延和带宽都很大,要获得高吞吐量需要更大的窗口大小。窗口扩大选项占3字节,其中有一个字节表示移位值S。新的窗口值等于TCP首部中的窗口位数从16到(16+S)。S的最大值是14,相当于窗口最大值增大到2^30 - 1。窗口扩大选项可以在双方建立TCP连接时进行协商。如果连接的一端实现了窗口扩大,当它不再需要扩大其窗口时,可发送S=0的选项,使窗口的大小回到16。
    • 时间戳:占10字节,其中主要的字段是时间戳值字段(4字节)和时间戳回送回答字段(4字节)。时间戳有以下两个功能:
      • 第一:用来计算往返时间RTT。发送方在发送报文段时把当前时间值放入到时间戳字段中,接收方在确认该报文段时把时间戳字段值复制到时间戳回送回答字段。因此,发送方在接收到确认报文后,可以准确计算出RTT来。
      • 第二:用于处理TCP序号超过2^32的情况,这又防止序号绕回。我们知道,TCP序号只有32位,而每增加2 ^32个序号就会重复使用原理的序号,当我们使用高速网络时,在一次TCP连接的数据传送的序号会被重复使用。为了使接收方把新的报文段和迟到很久的报文段区分开,可以在报文段加上这种时间戳。

TCP可靠传输的实现

一、以字节为单位的滑动窗口

在这里插入图片描述- 对于发送方A的发送窗口。发送窗口表示:在没有收到B的确认的情况下,A可以连续把窗口的内的数据都发送出去。凡是已经发送过的数据,在未收到确认之前都必须暂时保留,以便在超时重传时使用。

  • 发送窗口后沿的后面部分表示已经发送且已收到了确认,这些数据不需要再保留了。而发送窗口前沿的前面部分表示不允许发送,因为接收方都没有为这部分数据保留临时存放的缓存空间。
  • 发送窗口后沿的变化情况有两种,即不动(没有收到新的确认)和前移(收到了新的确认)。发送窗口后沿不可能向后移动,因为不能撤销已收到的确认。发送窗口前沿通常是不断向前移动,但也有可能不向前移动。有两种情况,一是没有收到新的确认,对方通知的窗口大小也不变,二是收到了新的确认但是对方通知的窗口缩小了,使得发送窗口前沿正好不动。
  • 一般来说,不允许发送窗口前沿向后移动,这回产生很多的错误。
  • 发送缓存用来暂时存放:1、发送应用程序传送给发送方TCP准备发送的数据。2、已经发送的数据但是还没有收到确认应答的数据
  • 接收缓存用来暂时存放:1、按序到达的、但尚未被接收应用程序读取的数据。2、未按序到达的数据。
  • 如果收到分组被检测出有差错,那么直接丢弃。如果接收应用程序来不及读取收到的数据,接收端缓存最终会被存满,是接收窗口减小到0。反之,如果接收应用程序及时从接收缓存中读取收到的数据,接收窗口就可以增加,但是最大不能超过接收缓存的大小。
  • 虽然A的发送窗口时根据B的接收窗口进行设置的,但是在同一时刻,A的发送窗口并不总是和B的接收窗口一样大,这是因为通过网络传送窗口值需要经历一定的时间滞后(这个时间是不知道的)。
  • 对于不按序到达的数据应如何处理,标准并没有明确的规定。如果接收方把不按序到达的数据丢弃掉,那么处理起来就特别简单,但这样做对网络资源的利用率太低,发送方会重传很多没有必要的数据。因此TCP通常对不按序到达的数据是先临时存在接收窗口中,等到字节流所缺少的字节收到之后,再按序交付给上层的应用程序。
  • TCP要求接收方必须有累积确认的功能,这样可以减少传输开销。接收方可以在适当的时候发送确认,也可以在自己有数据要发送时把确认消息捎带上。但是一定要注意:一是接收方不应过分推迟发送确认,否则会导致发送方没有必要的重传,这反而会会浪费了网络的资源。TCP规定,确认推迟的时间不应超过0.5秒。若收到一连串具有最大长度的报文段,则必须每隔一个报文段就放一个确认。二是捎带确认实际上并不经常发生,因为大多数程序很少在两个方向上发送数据。
超时重传时间的选择
  • TCP的发送发给在规定时间内没有收到确认应答就要重传已经发送的报文段。重传的概念是简单的,但是重传时间的选择却是TCP最复杂的问题之一。
  • 如果把这个时间设置的太短,就会引起很多报文段没有必要的重传,使网络的负荷增大;如果把这个时间设置的太长,就会使网络的空闲时间增加,降低了传输效率。
  • TCP采用一种自适应的算法,需要用到上面所说的时间戳。
  • 这个算法我不说了。
选择确认SACK
  • 在收到的报文无差错,只是未按序号,中间还缺少一些序号的数据,能否设法只传缺少的数据而不重传已经正确到达接收方的数据?当然是可以,用到选择确认SACK机制。
  • 比如:我要发送1~1000的数据,第一次发送1 ~ 100,接收成功,并且收到确认应答,在发送101 ~ 200,没有收到,201 ~ 300收到了,301 ~ 400没有收到。那么在一个数据报中有两个边界1和101或者101和201。在建立连接时,在TCP首部的选项中加上“允许SACK”的选项,一个边界要用4个字节来表示,并且还需要两个字节,一个字节用来指明是SACK选项,另一个字节是知名这个选项要占用多少个字节。因为选项部分最大40字节,因此只能存储4个字节块的信息。
  • 但是SACK文档并没有指明发送方应当怎样响应SACK,因此大多数的实现还是重传所有未被确认的数据块。

TCP的流量控制

利用滑动窗口实现流量控制
  • 流量控制就是让发送方的发送速率不要太快,要让接收方来得及接收。
  • 主要是通过接收方向发送方告诉自己的窗口大小,然后,发送方的发送窗口不能超过接收方给出的接收窗口,而且TCP的窗口单位是字节。
  • 还有一个问题,B在给A发送了零窗口的报文段后不久,B的接收缓存又有了一些存储空间。于是B给A发送了窗口大小为400字节的数据报,但是这个数据报在传输过程中丢失了。这时,B一直等待A发送的数据,A一直等待收到B发送非零窗口的数据报。那么这种互相等待的死局将一直延续下去。
  • 为了解决这一问题,TCP为每一个连接设有一个持续计时器,当接收到一个零窗口时,这个持续计时器开始计时。当这个计时器设置的时间到期,就发送一个零窗口探测报文段,而对方就在确认这个探测报文段中给出自己现在的窗口大小,如果还是零,那么收到后重新启动持续计时器。如果不是零,那么很好,这个死局打破了。
TCP的传输效率
  • 应用程序将数据传送费TCP的发送缓存后,剩下的发送任务就由TCP来控制了。可以用不同的机制来控制TCP报文段的发送时机。例如:第一种机制就是TCP维持了一个变量,他等于最大报文段长度MSS。只要缓存中的数据达到了MSS字节时,就组装成一个TCP数据发送出去。第二种机制是由发送方的应用程序指明要求发送报文段,即TCP支持的推送操作。第三种机制就是发送方的一个计时器期限到了,这时就把当前的已有的缓存数据装入到报文段(但是长度不能超过MSS)发送出去。
  • 但是如何控制TCP发送报文段的时机任然是一个较为复杂的问题。
  • 在TCP的实现中广泛使用了Nagle算法。算法:若发送应用进程要把发送的数据逐个字节地送到TCP的发送缓存,则发送方就把第一个数据字节先发送出去,把后面到达的数据字节重新都缓存起来。当发送方收到对第一个数据字符的确认后,再把发送缓存中所有数据组装成一个报文段发送出去,同时继续对随后到达的数据进行缓存。只有在收到对前一个报文段的确认后才继续发送下一个报文段。当数据到达较快而网络速率较慢时,用这样的方法可以明显地减少所用的网络带宽。同时,当到达的数据已达到发送窗口大小的一半或已达到报文段的最大长度时,就立即发送一个报文段。这样做,可以有效提高网络的吞吐量。
  • 还有一种情况就是,接收方的接收进程一次只从接收缓存中读取一个字节,于是接收窗口就只有一个字节。那么发送一个字节的数据报最少41字节。这样以此下去,使网络的效率很低。要解决这个问题,那么可以让接收方等待一段时间,使得接收缓存已有足够的空间容纳一个最长的报文段,或者等到接收缓存已有一半空闲的空间。此时,接收方就发出确认报文,并告知此时的窗口大小。并且,此时在发送方也不要发送太小的报文段,而是把数据积累成足够大的报文段,或者到接收缓存空间的一半大小。
  • 上面的两种方法配合起来使用,使的发送不发送很小的报文段的同时,接收方也不要再缓存刚刚有点小空间就急忙的把这个很小的窗口大小信息通知给发送方。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值