热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

TCP协议的高可靠性及其应用分析

本文深入探讨了TCP协议的高可靠性特点及其广泛应用。TCP协议通过多种机制确保数据传输的准确性与稳定性,包括但不限于校验和验证、数据包分割与重组以及超时重传机制。这些机制共同作用,使得TCP成为互联网通信中最可靠的数据传输协议之一。

在前篇文章中介绍了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的交互与成块数据流

转:https://www.cnblogs.com/lxyit/p/10643394.html



推荐阅读
  • 使用Python在SAE上开发新浪微博应用的初步探索
    最近重新审视了新浪云平台(SAE)提供的服务,发现其已支持Python开发。本文将详细介绍如何利用Django框架构建一个简单的新浪微博应用,并分享开发过程中的关键步骤。 ... [详细]
  • Java 中的 BigDecimal pow()方法,示例 ... [详细]
  • 本文介绍了Java并发库中的阻塞队列(BlockingQueue)及其典型应用场景。通过具体实例,展示了如何利用LinkedBlockingQueue实现线程间高效、安全的数据传递,并结合线程池和原子类优化性能。 ... [详细]
  • 使用 Azure Service Principal 和 Microsoft Graph API 获取 AAD 用户列表
    本文介绍了一段通用代码示例,该代码不仅能够操作 Azure Active Directory (AAD),还可以通过 Azure Service Principal 的授权访问和管理 Azure 订阅资源。Azure 的架构可以分为两个层级:AAD 和 Subscription。 ... [详细]
  • 网络攻防实战:从HTTP到HTTPS的演变
    本文通过一系列日记记录了从发现漏洞到逐步加强安全措施的过程,探讨了如何应对网络攻击并最终实现全面的安全防护。 ... [详细]
  • 本文探讨了如何在给定整数N的情况下,找到两个不同的整数a和b,使得它们的和最大,并且满足特定的数学条件。 ... [详细]
  • 在使用 MUI 框架进行应用开发时,开发者常常会遇到 mui.init() 和 mui.plusReady() 这两个方法。本文将详细解释它们的区别及其在不同开发环境下的应用。 ... [详细]
  • libsodium 1.0.15 发布:引入重大不兼容更新
    最新发布的 libsodium 1.0.15 版本带来了若干不兼容的变更,其中包括默认密码散列算法的更改和其他重要调整。 ... [详细]
  • 本文详细探讨了Java中的24种设计模式及其应用,并介绍了七大面向对象设计原则。通过创建型、结构型和行为型模式的分类,帮助开发者更好地理解和应用这些模式,提升代码质量和可维护性。 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • 本文介绍了如何使用JQuery实现省市二级联动和表单验证。首先,通过change事件监听用户选择的省份,并动态加载对应的城市列表。其次,详细讲解了使用Validation插件进行表单验证的方法,包括内置规则、自定义规则及实时验证功能。 ... [详细]
  • 本文详细介绍了Java中org.eclipse.ui.forms.widgets.ExpandableComposite类的addExpansionListener()方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。这些示例来源于多个知名开源项目,具有很高的参考价值。 ... [详细]
  • 前言--页数多了以后需要指定到某一页(只做了功能,样式没有细调)html ... [详细]
  • 探讨一个显示数字的故障计算器,它支持两种操作:将当前数字乘以2或减去1。本文将详细介绍如何用最少的操作次数将初始值X转换为目标值Y。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
author-avatar
zf72ayw
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有