TCP协议设计原理

  最近去了解TCP协议,发现这是一个特别值得深思的协议。在本篇博客中,不会长篇大论的给大家介绍TCP协议特点、包头格式以及TCP的连接和断开等基本原理,而是会带大家深入理解为什么要这么设计,如果不这么设计,会产生什么后果,希望能帮助大家对TCP协议的理解。TCP弥补了IP尽力而为服务的不足,实现了面向连接、高可靠性、报文按序到达、端到端流量控制。

  • 面向连接

  一提到TCP是面向连接的协议,必然是介绍其的3次握手和4次挥手,为了说明为什么需要三次握手和四次挥手,我们还是拿两个图来说明连接建立和断开的过程。

 

  为什么要三次握手呢?若两次握手怎样。假设客户端发起连接请求(SYN=1,seq=client_isn),服务器端收到请求后返回消息(SYN=1,seq=server_isn,ack=client+1)连接建立。

  现在说明为什么两次握手不可以。若客户端发送连接请求request1(SYN=1,seq=client_isn),这时这个请求由于网络阻塞没有及时到达服务器端,而客户端一段时间后又发送了一个连接请求request2 (SYN=1,seq=client_isn),该request2建立了连接完成了本次通信,然后断开连接。此时客户端发送的第一个连接请求request1到达了服务器端,此时服务器端发现是一个连接请求,服务端并不知道这是由于网络阻塞导致已经无用的连接请求,服务器收到request1则给客户端发送消息(SYN=1,seq=server_isn,ack=client_isn+1)。如果是两次握手那么客户端在收到这条消息后则客户端和服务器端建立连接。但客户端并不是真正想建立连接,所以不能通过两次握手就建立连接。

  那为什么需要四次挥手呢?如果三次挥手又会怎样。我们假设客户端向服务器发送了断开请求,服务器在收到断开请求后也向客户端发送断开请求(FIN=1,ACK=1,seq=w,ack=u+1),客户端收到此消息后向服务器发送断开连接(ACK=1,seq=u+1,ack=w+1)。可想而知这种方法是不可行的。因为当客户端没有数据需要发送给服务器时,客户端主动发起了断开请求,但是并不代表服务器端没有数据发给客户端。所以为了保证服务器端正常传输完数据,服务器端在收到客户端发送的断开请求后先发送一个ACK(ACK=1,seq=v,ack=u+1)给客户端,当服务器端数据传输完后发送断开请求(FIN=1,ACK=1,seq=w,ack=u+1)。

  不知道大家有没有注意到客户端在发送了最后一个断开请求的ACK后,又等待了2MSL的时间才关闭连接。为什么不直接关闭连接呢?如果客户端直接关闭连接,而此时客户端最后发送的ACK又在网络中丢失,从而可能导致服务器端的连接无法正常关闭。那为什么又要设置为2MSL呢?1MSL表示一个IP数据报在网络中的最多存活时间。假设客户端最后发送的ACK经过将近1MSL快要到达服务器端的时候丢失了,那么服务器端在规定的时间内未收到最后客户端发送的ACK,则服务器端重新发送最后的FIN给客户端,请求客户端重发ACK,该FIN经过1MSL到达客户端。所以如上最坏情况,如果客户端在2MSL内没有收到FIN请求,则表明服务器端已经断开连接。

  • 传输高可靠性

  不用多说,大家都知道TCP的传输可靠性是依据确认号实现的。简单说就是客户端每发送一个分段给服务器端,服务端收到后会给客户端发送一个确认号,表示服务器端收到该分段。如果客户端在RTT时间周期内未收到服务器端的确认号,则引发超时重传。因此TCP协议中需要计时器。那么问题就来了,TCP有那么多分段,是要给每一个分段都生成一个计时器吗?

  给每个分段都生成一个计时器当然是最简单也最好理解的,每个计时器在RTT时间后到期,如果没有收到确认号则重传该分段。然而给每个分段都生成计时器将带来巨大的内存开销和调度开销。因此在实际中采取给每个TCP连接生成一个计时器,那么问题又来了,一个TCP连接有那么多分段,如何利用一个计时器管理这么多分段呢?设计原则如下(大家可以思考一下为什么这么设计):

  1. 发送TCP分段时,如果没有开启重传定时器,则开启;
  2. 发送TCP分段时,如果有重传定时器开启,则不再开启;
  3. 收到一个非冗余的ACK时,如果有数据在传输,重新启动重传定时器;
  4. 收到一个非冗余的ACK时,如果没有数据在传输,则关闭重传定时器;
  5. 如果连续收到3个冗余ACK时,则不用等到重传定时器超时,直接重传。
  • 报文按序到达

  确认号是TCP两端通信的数据传输的“标志”,TCP的发送端在收到一个确认号后,就认为接收端已经收到了该确认号之前的所有数据。早期的TCP标准中,只要TCP有一个分段丢失,该分段后的其他分段即使正确到达接收端,发送端还是会重传丢失分段后的所有分段,从而导致了大量不必要的超时重传。现在的TCP实现了一种选择确认的方式,接收端会显示的告诉发送端重传哪些分段,不需要重传哪些分段,避免了重传风暴。

  不知道大家在学习TCP协议时,有没有考虑TCP序列号回绕的问题。从TCP报文头部知道序列号占32位,能传输2的32次方个字节。如果一个1Gbps的网络,TCP端1s会发送125MB的数据,从而在32s内可发送2的32次方个字节,导致序列号回绕,而32s是小于MSL值的。一旦序列号回绕会导致接收端对TCP报文的排序发生错乱。当然可以通过加时间戳的方式来辅助序列号的识别,在接收端发现序列号回绕时,比较时间戳字段的值,如果回绕的序列号时间戳较大,则说明确实发生了回绕,从而将该数据放在最大的序列号之后。TCP还有其他方法判断序列号是否发生回绕,从而有效的确定数据报的排列顺序。

  • 端到端流量控制

  端到端流量控制使用滑动窗口来实现,一提到滑动窗口大家张口就来的是慢开始、拥塞避免、快重传、快恢复。那么问题来了:①快重传和快恢复确实提高了TCP的传输效率,但是如果发送端每次发送的TCP报文中仅有少量的数据,而包含大量的报头字段,从而也会影响效率,那么如何增大发送端发送数据的大小呢。②接收端在收到数据后返回给发送端一个ACK,如果接收端针对每个分段都返回ACK的话,网络中的ACK也会消耗大量的带宽,那么如何减少网络中ACK的发送呢。

  大家可能看到这样的长篇大论,已经没有了任何兴趣,那就放一张卡车拉煤图吧。我想通过卡车拉煤来说明如何解决这两个问题。其中括号中的是TCP中问题用拉煤的例子解释。

  我们先说第一个问题,就是TCP每次携带数据量少(卡车每次都拉一点煤,都不够油钱的)的问题。TCP中为什么会存在这个问题呢?接收端通过ack告诉发送端接收端窗口大小,决定发送端还可以发送多少数据(北京发电厂告诉山西煤场我这最多还可以接受5kg煤,你下次就送5kg煤就可以了,然后山西煤场就真的开着卡车送来了5kg煤)。这种情况显然需要从接收端着手解决,如果接收窗口为0,则告诉发送端不要在发送数据了,只有当接收端可接受的数据达到接收窗口的一半时,再告诉发送窗口发送数据(也就是说北京发电厂已经腾出了一半的空地可放煤了,才告知山西煤场送煤)。那还存在问题,虽然接受窗口已经有一半空闲,但是发送窗口发送的TCP携带的数据量还是较少(虽然发电厂已经有一半的地可以放煤了,但是煤场每次只送5kg煤)。这就是发送端的问题了,从而利用Nagle算法解决发送端持续发送小块数据分段的问题。如下我们就来看看这个Nagle算法:

IF 数据的大小和窗口的大小都超过了MSS
Then 发送数据分段
ELSE
IF 还有发出的不足MSS大小的TCP分段没有收到确认
Then 积累数据到发送队列的末尾的TCP分段
ELSE
发送数据分段
EndIF
EndIF

  第二个问题就是网络中ACK消耗大量带宽的问题(也就是说卡车把煤拉到北京,直接带着北京的口信,空着车就回山西了)。RFC建议了一种延迟的ACK,也就是说接收端在收到数据并不立即回复ACK,而是等一段时间,看看接收端是否也有数据要发送给发送端,同时通过要发送的数据一同传输给发送端。等一段时间,可能后续的TCP分段到达,这样就可以取最大者一起返回,从而也能减少网络中ACK的数量。当然RFC的建议延迟的ACK最多等待两个分段的积累确认。

TCP协议设计原理的更多相关文章

  1. TCP工作过程;TCP Flood的攻击的原理和现象;TCP协议设计的安全隐患与防范对策

    TCP分三个阶段 连接建立(三次握手) 数据传输 连接释放(四次挥手) TCP工作过程 TCP连接建立阶段 第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给S ...

  2. 从TCP协议的原理来谈谈rst复位攻击

    在谈RST攻击前,必须先了解TCP:如何通过三次握手建立TCP连接.四次握手如何把全双工的连接关闭掉.滑动窗体是怎么数据传输的.TCP的flag标志位里RST在哪些情况下出现.以下我会画一些尽量简化的 ...

  3. TLS1.2协议设计原理

    目录 前言 为什么需要TLS协议 发展历史 协议设计目标 记录协议 握手步骤 握手协议 Hello Request Client Hello Server Hello Certificate Serv ...

  4. [转帖]Linux TCP/IP协议栈,数据发送接收流程,TCP协议特点

    Linux TCP/IP协议栈,数据发送接收流程,TCP协议特点 http://network.51cto.com/art/201909/603780.htm 可以毫不夸张的说现如今的互联网是基于TC ...

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

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

  6. 转 tcp协议里rst字段讲解

    TCP协议的原理来谈谈rst复位攻击 http://russelltao.iteye.com/blog/1405349 几种TCP连接中出现RST的情况 https://blog.csdn.net/c ...

  7. TCP协议 - 可靠性

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

  8. [网络编程之客户端/服务器架构,互联网通信协议,TCP协议]

    [网络编程之客户端/服务器架构,互联网通信协议,TCP协议] 引子 网络编程 客户端/服务器架构 互联网通信协议 互联网的本质就是一系列的网络协议 OSI七层协议 tcp/ip五层模型 客户端/服务器 ...

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

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

随机推荐

  1. ER图,以及转化成关系模式

    1.找出条件中的实体(矩形),属性(椭圆),关系(菱形)关系分为1:1,1:N,M:N,列出ER图 2. -1:1联系的转换方法 -两个实体分别转化为一个关系模式,属性即是本来的属性 -关系可以与任意 ...

  2. 对lua中_ENV表的理解(lua5.2版本以后)

    当我拿到_ENV表的时候,会去想这个_ENV表是干什么用的? 首先看如下代码: print(_ENV) --0x1d005f0 print(_G) --0x1d005f0 ViewCode 看了上面的 ...

  3. MyEclipse+Tomcat开发Web项目时修改内容不能及时显示问题解决方法

    问题描述:MyEclipse+Tomcat开发Web项目时,修改的内容不能从浏览器即时显示 原因:缓存问题 解决方法:开启Tomcat的Debug模式 点击如下图红色标记中的图标(Restart th ...

  4. 在C语言中以编程的方式获取函数名

    仅仅为了获取函数名,就在函数体中嵌入硬编码的字符串,这种方法单调乏味还易导致错误,不如看一下怎样使用新的C99特性,在程序运行时获取函数名吧. 对象反射库.调试工具及代码分析器,经常会需要在运行时访问 ...

  5. .NET Core 最小化发布

    .NET Core 应用最小化独立部署发布,.NET Core 默认应用独立发布,大概占用50m左右的空间,不同的系统大小有所区别. .NET Core 的发布之前我也有所介绍,.NET Core 跨 ...

  6. Mysql数据库连接查询

                                    Mysql数据库连接查询 连接是关系数据库模型的主要特点.连接查询是关系数据库中最主要的查询,主要包括内连接.外连接等.通过连接运算可以 ...

  7. jquery mobile多页面跳转等,data-ajax="false" 问题,

    当我们的网站引用了jquery mobile的js后,点击页面的链接,你会发现页面无法跳转,因为jquery mobile默认是采用ajax方式来加载网站的,如果你需要跳到另一个页面,需要在a标签加上 ...

  8. SharePoint 2016 文档库的新功能简介

    今天,重装了一下SharePoint 2016,想多了解了解,看到一些自己平时没注意的功能,或者新的功能,分享一下给大家. 1.界面上操作的变换,多了一排按钮,更像SharePoint Online了 ...

  9. oozie配置安装与原理

     概述 当前开源的hadoop任务工作流管理主要有oozie和Azkaban,本文先介绍oozie的配置安装与基本运行原理. 配置安装 (参考https://segmentfault.com/a/11 ...

  10. Angular2的模块架构浅谈

    引言angular2相比1引入了更完善的模块系统,回忆ng1的应用中通常在页面的html标签或body标签中添加ng-app节点,值为应用的模块名,整个应用都将围绕这个模块来展开,到了ng2,模块概念 ...