在前篇文章中介绍了TCP协议的三大特性,其中可靠性是依赖一系列的机制,如:校验和,分组发送,超时重传,流量控制得到保证。

一.数据交互

TCP在交互数据时,采用多种机制保证可靠性,同时也保证TCP的性能,主要是分组、延迟ACK等等。

1.分组确认

对于连续的数据传输有三种方式:

  1. 单个单个字节发送
  2. 将整个连续数据发送
  3. 将整个连续数据拆分成一个个的分组包,然后逐个发送

显然前两种方式都是比较极端,单个单个字节发送对于成块连续数据而言效率非常低,整块连续数据发送对于比较大的数据而言更不现实,TCP缓冲区有限,网络带框也是有限,对于过大数据不可能这样发送。

在TCP协议栈中,有发送缓冲区和接收缓冲区用于缓冲存储即将发送的数据和收到的数据。当应用需要发送连续数据时,TCP将应用的数据存储到缓冲区中,TCP会根据一定的机制将缓冲区数据发送出去,应用同时也将数据写入缓冲区。接收方TCP在收到数据后,存入接收缓冲区中,TCP根据一定机制再将缓冲区中数据提交给应用处理。

TCP将成块的数据发送分成一个个的分组报文发送出去,其中分组报文大小不会超过MSS(Max Segment Size,最大的报文段大小)。TCP对发送的每个字节都采用序号的方式进行标识追踪,序号在建立TCP连接时即已经确定。发送端发送第一个字节数据的序号为建立TCP连接时的SEQ + 1。序号在这里有以下几种作用:

  1. 序号用于标识追踪发送数据的每个字节
  2. 接收端根据序号进行ACK确认
  3. 序号保证数据的有序性,接收端根据序号可以进行排序

标识发送数据的起始序号为TCP报文中的序号,没增加一个字节序号就增加1,所以发送的下个TCP报文的序号为上一个序号加上个报文的大小。通过这种方式TCP可以表示每个已经发送的每个字节。

对成块连续数据分组发送的方式,会带来很多问题,比如发送方如何确认接收方已经收到数据?

TCP采用ACK确认机制解决该问题,接收方在接受到数据后,必须要回复一个ACK的确认包告诉发送方已经收到该报文。其中有个确认序号,标识期待下次接收到的数据的起始序号。这个ACK的确认序号就是TCP报文段中的确认序号。

看到这个机制,对于了解消息MQ读者应该能联想到MQ是如何解决消息丢失的问题。可以说MQ的消息回执确认机制也正式来源于TCP的这个机制。上层很多设计都是来源于底层的设计思想。

通过确认机制可以保证报文丢失时,发送方能够感知到,这一点也是TCP的可靠性保证之一。

从以上图中,可以看到客户端发送的报文都有相应的确认报文用于通知客户端服务器端已经接收到。分组发送,ACK确认机制是TCP可靠性保证的机制之一

2.延迟的ACK

大多数客户服务器之间的通信都是双方向的数据流动,在这种情况下如果是客户端应用请求TCP发送数据,然后服务端的TCP回复ACK确认,然后服务端TCP再发送应用层的响应值客户端,客户端再发送ACK。这样来回需要四次,无疑增加网络负担,使得网络拥塞。为了提升TCP的性能,尽可能的减小网络负担,延迟ACK策略决定接收端TCP在接手到发送方的数据后,不立即回复ACK,而是经过一个ACK的延迟时间段后再回复ACK。如果这个时间段内有数据需要发送,则放在缓冲区,然后将ACK和这个数据发送作为一个报文段发给发送方。

一般这个延迟的时间是200ms,可以看出,TCP是重复利用网络资源,重复利用TCP数据报,达到最大化的网络传输。

从上图可以看出,每个PSH包都会使捎带ACK的,这样将原本可能需要四次交互减低到只要两次。

3.Nagle算法

前面提到TCP有发送缓冲区,在发送时,应用的数据被内核写入该缓冲区后,TCP再发出去。分组发送时,如果是非常多的微小的分组数据包被不断发出去,则有可能造成网络拥塞,特别是在广域网上。

Nagle算法要求在一个TCP连接上最多只有一个未确认的分组,在该分组的确认包到达之前,发送将不能在发送其他的分组。应用层需要发的数据都被存在缓冲区,待收到确认包后,将缓冲区中的数据一块发送出去。该算法旨在解决大量的微小分组在低速带宽上频繁发送可能造成网络拥塞的问题。

如果更加直接的说,Nagle算法即是将发送的积累沉淀,知道达到一定的条件后再作为大的分组发送,避免大量微小分组造成网络拥塞。这个条件是:

  1. 如果缓冲区中数据大于MSS
  2. 禁用Nagle算法或则TCP连接上没有未确认的分组
  3. 有紧急数据需要发送

满足以上条件之一,将才会发送缓冲区的数据。

4.延迟ACK和Nagle共同作用

Nagle算法旨在解决大量微小分组造成的拥塞问题,但是如果在带宽较大且网络负载不大的局域网上,且应用对延迟非常敏感的时,Nagle算法则不合适。因为应用需要发送的数据被缓冲,未被发出而得到响应,产生延迟。

特别当Nagle算法遇到ACK延迟,两者共同作用时,该情况尤为明显。因为一个TCP连接上只存在一个未确认的分组,且该分组又被ACK延迟。两者共同作用,带来更大的延迟。对于延迟敏感应用则加剧这种情况。

对于大多数局域网内的应用交互,可以通过设置TCP连接套接字,禁用Nagle算法。让一个连接上可以存在多个未确认分组,可以连续发多次分组,从而降低延迟。但是对于在广域网上由于流量较大和RRT较长原因,禁用Nagle算法不仅可能会造成网络拥塞,而且产生的网络延迟可能更严重。

Socket套接字提供应用层Socket参数TCP_NODELAY参数用于开启和关闭Nagle算法。可以通过Java的API了解:

4.ACK的累积

发送端通过Nagle算法累积发送数据,从而避免大量微小分组出现在网络中。从而发送一个较大分组,解决拥塞和一定的延迟问题。接收端如果对接收到的每个报文段都进行ACK,那么网络中将存在大量的ACK包,从而加重网络负载。

TCP设计ACK累积策略,该策略并不是针对每个TCP报文都需要进行ACK确认。接收端的TCP创建一个针对发送端IP的队列,接收到的报文都进入该队列。接收到TCP报文段后,启动延迟ACK定时器。在该定时时间段内,仍然会接收发送过来的数据进入队列。在一定条件下,然后回复已经收到的最大的数据SEQ + 1作为ACK回复确认序号。如下通信过程:

从上图可以看出,当svr和bsdi在建立连接后,svr连续发送了三个TCP报文,但是bsdi并不是对每个报文都进行了ACK,当序号为1的PSH包到达后,bsdi的TCP启动延迟ACK,然后又接收到了1025序号的TCP报文,此时有两个未确认的报文,所以发送了一个2049的ACK。当接收方收到2049的ACK后,即知道前面一个序号为1的报文也已经接收到了,不然接收端是不会回复2049的ACK的。

通过ACK累积,可以减少ACK包,从而提升网络利用率,降低拥塞的可能。

二.超时重传

TCP的可靠性另一方面的保证机制即超时重传。上节说到通过ACK的方式让发送方知道接收方是否收到了数据。但是数据和ACK包都有可能会丢,即使接收方收到了,但是ACK却丢失。那样对于发送方而言,仍然不知道接受方是否接受到了数据。

TCP协议设计超时重传机制。发送方的TCP在发送TCP报文后,针对该报文启动重传定时器,如果当定时器溢出超时后,仍然没有收到该报文的ACK,则重新发送该报文。然后再启动相应的定时器等待ACK,直到发送成功或者重发一定次数失败后。

以下客户单通过telnet程序演示TCP的超时重传机制的过程。

发送端发送"hello2."时由于网络连接断开,然后重复发送。通过tcpdump可以看出

参考

TCP的交互与成块数据流

TCP协议 - 可靠性的更多相关文章

  1. TCP协议可靠性数据传输实现原理分析

    http://blog.csdn.net/chexlong/article/details/6123087 TCP 协议是一种面向连接的,为不同主机进程间提供可靠数据传输的协议.TCP 协议假定其所使 ...

  2. TCP协议可靠性是如何保证之滑动窗口,超时重发,序列号确认应答信号

    原创文章首发于公众号:「码农富哥」,欢迎收藏和关注,如转载请注明出处! TCP 是一种提供可靠性交付的协议. 也就是说,通过 TCP 连接传输的数据,无差错.不丢失.不重复.并且按序到达. 但是在网络 ...

  3. TCP协议-如何保证传输可靠性

    转自 https://blog.csdn.net/xuzhangze/article/details/80490362 TCP协议保证数据传输可靠性的方式主要有: (1)检验和 在发送数据时,为了计算 ...

  4. 基于UDP协议模拟的一个TCP协议传输系统

    TCP协议以可靠性出名,这其中包括三次握手建立连接,流控制和拥塞控制等技术.详细介绍如下: 1. TCP协议将需要发送的数据分割成数据块.数据块大小是通过MSS(maximum segment siz ...

  5. TCP协议与UDP协议的区别

    TCP协议与UDP协议的区别(转) 首先咱们弄清楚,TCP协议和UCP协议与TCP/IP协议的联系,很多人犯糊涂了,一直都是说TCP/IP协议与UDP协议的区别,我觉得这是没有从本质上弄清楚网络通信! ...

  6. tcp协议头窗口,滑动窗口,流控制,拥塞控制关系

    参考文章 TCP 的那些事儿(下) http://coolshell.cn/articles/11609.html tcp/ip详解--拥塞控制 & 慢启动 快恢复 拥塞避免 http://b ...

  7. TCP协议疑难杂症全景解析

    说明: 1).本文以TCP的发展历程解析容易引起混淆,误会的方方面面2).本文不会贴大量的源码,大多数是以文字形式描述,我相信文字看起来是要比代码更轻松的3).针对对象:对TCP已经有了全面了解的人. ...

  8. [转载] TCP协议缺陷不完全记录

    原文: http://www.blogjava.net/yongboy/archive/2015/05/07/424917.html tcp是一个非常复杂并且古老的协议, 之前教科书上将的很多东西应用 ...

  9. Linux下tcp协议socket的recv函数返回时机分析(粘包)

    http://www.vckbase.com/index.php/wv/10http://blog.csdn.net/zlzlei/article/details/7689409 文章一: 当前在网络 ...

随机推荐

  1. Educational Codeforces Round 77 (Rated for Div. 2) D A game with traps

    题意:x正轴上有着一个陷阱的位置,开关和灵敏度,如果一个士兵灵敏度输给陷阱,他是过不去这个陷阱的幸运的是,你可以先过去把开关给关了,没错你是不怕陷阱的接下来呢你有操作,你移动一个,耗费一秒而你的团队需 ...

  2. Java之线程安全

    什么是线程安全? 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的. 什么是线程安全问题? ...

  3. Help Hanzo (LightOJ - 1197) 【简单数论】【筛区间质数】

    Help Hanzo (LightOJ - 1197) [简单数论][筛区间质数] 标签: 入门讲座题解 数论 题目描述 Amakusa, the evil spiritual leader has ...

  4. filter,map,reduce三个数组高阶函数的使用

    filter ,map ,reduce三个高阶函数的使用 普通方法解决数据问题 const nums1= [10,20,111,222,444,40,50] // 需求1.取出小于100的数字 // ...

  5. HTML5 3D 在智慧物业/地产管理系统中的应用

    概述 该博文主要展示采用 HT for Web 提供的可视化技术,对智慧房产.智慧物业相关方向的可视化呈现做的一点尝试. 传统的 智慧房产/楼宇自动化/智慧物业 常会采用 BIM(建筑信息模型 Bui ...

  6. 图解Numpy的tile函数

    Numpy的tile(A, reps)函数,就是将原矩阵横向.纵向地复制.tile是瓷砖的意思,顾名思义,这个函数就是把数组像瓷砖一样铺展开来. 举个例子,原矩阵:  横向铺展:  纵向铺展: 横向铺 ...

  7. pandas.apply()函数

    1.介绍 apply函数是pandas里面所有函数中自由度最高的函数.该函数如下: DataFrame.apply(func, axis=0, broadcast=False, raw=False, ...

  8. SpringCloud微服务(05):Zuul组件,实现路由网关控制

    本文源码:GitHub·点这里 || GitEE·点这里 一.Zuul组件简介 1.基础概念 Zuul 网关主要提供动态路由,监控,弹性,安全管控等功能.在分布式的微服务系统中,系统被拆为了多个微服务 ...

  9. (三十八)c#Winform自定义控件-圆形进度条-HZHControls

    官网 http://www.hzhcontrols.com 前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kww ...

  10. Go-for循环

    一.第一种情况(死循环) package main import "fmt" func main() { for{ fmt.Println("fuck") } ...