目录
6、四次挥手中TIME-WAIT 状态为什么需要等待 2MSL?
1、TCP和UDP的区别
区别 | TCP | UDP |
连接方式 | 面向连接:数据交互前需要先三次握手建立连接),只能一对一连接 | 无连接:直接发送数据,可以一对一,也可以一对多 |
传输方式 | 可靠性传输:实行“顺序控制”或“重发控制”,保证不丢包、不重复。此外还具备“流量控制”、“拥塞控制”等提高网络利用率的功能 | 不可靠传输:细微的处理它会交给上层应用去完成。在UDP的情况下,虽然可以确保发送消息的大小,却不能保证消息一定会到达 |
首部格式 | 首部复杂:首部由源目的端口号、序列号、确认应答号、数据偏移、保留、控制位、窗口大小、校验和、紧急指针、选项、填充组成 | 首部简单:首部由源端口号、目的端口号、包长和校验和组成 |
传输效率 | 效率低,适用于连接可靠的应用场景,如网页访问、视频、邮件等 | 效率高,适用于实时性有要求或者是广播/组播通信,如直播应用等 |
典型应用 | HTTP、TELNET、SSH、FTP等 | DHCP、DNS、SNMP等 |
2、TCP报文首部有哪些字段,说说其作用?
字段 | 长度 | 含义 |
Source Port | 16比特 | 源端口,标识哪个应用程序发送。 |
Destination Port | 16比特 | 目的端口,标识哪个应用程序接收。 |
Sequence Number | 32比特 | 序号字段。TCP链接中传输的数据流中每个字节都编上一个序号。序号字段的值指的是本报文段所发送的数据的第一个字节的序号。 |
Acknowledgment Number | 32比特 | 确认号,是期望收到对方的下一个报文段的数据的第1个字节的序号,即上次已成功接收到的数据字节序号加1。只有ACK标识为1,此字段有效。 |
Data Offset | 4比特 | 数据偏移,即首部长度,指出TCP报文段的数据起始处距离TCP报文段的起始处有多远,以32比特(4字节)为计算单位。最多有60字节的首部,若无选项字段,正常为20字节。 |
Reserved | 6比特 | 保留,必须填0。 |
URG | 1比特 | 紧急指针有效标识。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据)。 |
ACK | 1比特 | 确认序号有效标识。只有当ACK=1时确认号字段才有效。当ACK=0时,确认号无效。 |
PSH | 1比特 | 标识接收方应该尽快将这个报文段交给应用层。接收到PSH = 1的TCP报文段,应尽快的交付接收应用进程,而不再等待整个缓存都填满了后再向上交付。 |
RST | 1比特 | 重建连接标识。当RST=1时,表明TCP连接中出现严重错误(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立连接。 |
SYN | 1比特 | 同步序号标识,用来发起一个连接。SYN=1表示这是一个连接请求或连接接受请求。 |
FIN | 1比特 | 发端完成发送任务标识。用来释放一个连接。FIN=1表明此报文段的发送端的数据已经发送完毕,并要求释放连接。 |
Window | 16比特 | 窗口:TCP的流量控制,窗口起始于确认序号字段指明的值,这个值是接收端正期望接收的字节数。窗口最大为65535字节。 |
Checksum | 16比特 | 校验字段,包括TCP首部和TCP数据,是一个强制性的字段,一定是由发端计算和存储,并由收端进行验证。在计算检验和时,要在TCP报文段的前面加上12字节的伪首部。 |
Urgent Pointer | 16比特 | 紧急指针,只有当URG标志置1时紧急指针才有效。TCP的紧急方式是发送端向另一端发送紧急数据的一种方式。紧急指针指出在本报文段中紧急数据共有多少个字节(紧急数据放在本报文段数据的最前面)。 |
Options | 可变 | 选项字段。TCP协议最初只规定了一种选项,即最长报文段长度(数据字段加上TCP首部),又称为MSS。MSS告诉对方TCP“我的缓存所能接收的报文段的数据字段的最大长度是MSS个字节”。 新的RFC规定有以下几种选型:选项表结束,无操作,最大报文段长度,窗口扩大因子,时间戳。
|
Padding | 可变 | 填充字段,用来补位,使整个首部长度是4字节的整数倍。 |
data | 可变 | 数据部分,TCP负载。 |
3、讲下TCP三次握手流程
客户端和服务器初始均为CLOSED状态,然后服务器开始侦听某个端口进入LISTEN状态
第一次握手:客户端发送SYN包(SYN=1,seq=x)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到SYN包后并响应SYN+ACK包(SYN=1,ACK=1,seq=y.ack=x+1),发送完毕服务器进入SYN_RCVD状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ACK=1,seq=x+1.ack=y+1)),此包发送完毕,客户端和服务器进入ESTABLISHED状态,后续开始交互数据。
4、为什么TCP是三次握手而不是两次、四次?
🔷原因1:确认双方的接收与发送能力是否正常
(1)第一次握手(Client->Server,SYN):
● Client无法确认任何信息
● Server确认了自身接收正常,Client发送能力正常
(2)第二次握手(Client<-Server,SYN+ACK):
● Client确认了自身收/发能力正常,Server收/发送能力正常
● Server确认了自身接收正常,Client发送能力正常
(3)第三次握手(Client->Server,ACK):
● Client确认了自身收/发能力正常,Server收/发送能力正常
● Server确认了自身收/发能力正常,Client收/发送能力正常
所以三次握手能保证双方收发能力正常,二次握手不能确认,四次握手设计显得多余
🔷原因2:协商确定发送数据包的单位,即“最大消息长度”(MSS:Maximum Segment Size)
举个例子:两个人互发微信交流如果一方直接发2000字长篇大论,另一方估计看都不想看,所以协商简洁的字数交流很有必要。
TCP交互也是一样,需要发送方和接收方协商能被双方认可的MSS才能有效交互,任何一方不能无限制的去乱发大包,这就会导致交互出现异常。过程如下:
MSS协商存在于TCP Option字段中,协商报文如下:
5、介绍下TCP四次挥手的过程?并解释为什么是四次
(1)第一次挥手:客户端发送FIN+ACK包(seq=a,ack=b)给服务器,并进入FIN_WAIT_1状态,等待服务器确认;
(2)第二次挥手:服务器响应ACK包(seq=b.ack=a+1),发送完毕服务器进入CLOSE_WAIT状态。客户端收到该确认包后进入FIN_WAIT_2状态;
(3)第三次挥手:服务器发送FIN+ACK包(seq=b,ack=a+1)给客户端,并进入LAST_ACK状态,等待来自客户端的最后一个ACK;。
(4)第四次挥手:客户端响应ACK包(seq=a+1,ack=b+1),并进入TIME_WAIT状态,服务器收到ACK包后关闭连接,进入CLOSED状态。而客户端则等待2个MSL(最大段生命周期:Maximum Segment Lifetime)时间,如果没有收到服务器的重传FIN+ACK则认为自己ACK包发送正常且服务已关闭连接,于是自身关闭连接并进入CLOSED状态。
相关报文如下(172为客户端,119为服务器):
:四次挥手并非一定是客户端作为发起者,也存在第一次挥手由服务器发起的情况。挥手流程与客户端发起一致,相关流如下:
小问:为什么挥手需要四次?
(1)客户端数据发送完毕需要关闭连接时会向服务端发送 FIN,但是自身此时还能接收数据;
(2)服务器收到客户端的 FIN包时会响应ACK 应答报文,但自身还有数据需要处理和发送;
()直到服务端数据发送完毕,才发送 FIN 报文给客户端关闭现有连接。
从上述流程不难看出服务器和客户端的FIN和ACK需要分别发送,故挥手需要四次。
6、四次挥手中TIME-WAIT 状态为什么需要等待 2MSL?
MSL(最大段生命周期:Maximum Segment Lifetime)是任何TCP报文在网络中存在的最大时长,如果超过这个时间,这个TCP报文就会被丢弃。
🔷原因1:为了可靠地实现全双工连接的终止
上图中假设客户端发出的最后一个ACK丢失服务器将会重传FIN,为了能够收到这个超时重传的FIN,客户端需要TIME_WAIT状态。TIME_WAIT为何必须是2MSL?这取决于服务器的超时重传时间RTO(Retransmission Timeout),一般情况下RT0<MSL,等待1个MSL客户端就能收到重传FIN包;如果MSL<RTO2≤MSL则需要等最多2MSL就能收到重传FIN包;若RTO>MSL,客户端即便等到2MSL也收不到重传FIN。上述中通常情况下RTO远远小于MSL,而大于2MSL的情况基本不存在。所以考虑最坏的情况RTO=2MSL所以等待时间设计为2MSL。
🔷原因2:避免旧TCP连接的数据包影响到新的TCP连接
如上图,假设客户端TIME_WAIT时长极短,发出ACK后即进入CLOSED状态关闭连接并释放内存和端口资源。若存在ACK丢包服务器端将会重传FIN报文,如果此时客户端以相同的端口向服务器建立TCP新连接,那么在新连接交互中就能收到来自服务器旧连接重传的FIN包,从而导致新TCP连接异常。因此,客户端TIME_WAIT时间为2MSL可以让经过重传时间RTO后服务器重传的FIN包在网络中失效掉(RTO一般远小于MSL,所以重传时间+FIN包失效时间是小于2MSL的),防止对新TCP连接产生影响。
7、TCP 是如何保证可靠性的?
(1)通过三次握手保证连接建立可靠性;
(2)通过确认应答(ACK)和序列号 实现可靠的数据传输。
- TCP 通过肯定的确认应答(ACK) 实现可靠的数据传输。当发送端将数据发出之后会等待对端的确认应答。如果有确认应答,说明数据已经成功到达对端。反之,则数据丢失的可能性很大:
- 如下图一定时间内没有等到确认应答,发送端就可以认为数据已经丢失,并进行重发。由此,即使产生了丢包,仍然能够保证数据能够到达对端实现可靠传输:
- 未收到确认应答并不意味着数据一定丢失,也有可能是数据对方已经收到只是返回的确认应答在途中丢失。这种情况也会导致发送端因没有收到确认应答而认为数据没有到达目的地,从而进行重新发送。如下所示:
(3)通过四次挥手保证连接断开的可靠性。
8、介绍下TCP重传机制
重发超时是指在重发数据之前,等待确认应答到来的那个特定时间间隔,即RTO((Retransmission Timeout 超时重传时间)。如果超过了这个时间仍未收到确认应答,发送端将进行数据重发。
那么这个RTO又是如何确定的呢?首先要了解RTT(Round-Trip Time往返时延),即数据从网络一端传送到另一端所需的时间,也就是包的往返时间,如下图:
如何确定RTO的大小?我们先来做两组假设:
● 若RTO 较大,丢包很久了发送方才重发报文,效率低性能差;
● 若RTO 较小,数据可能未丢失就重发,这会增加网络拥塞,并导致更多的超时出现。
基于此,重传时间RTO一般来说略大于RTT值效果最好。既能保证重传效率,又能保证能在收到回包后重传。
根据网络环境的不同往返时间可能会产生大幅度的摇摆,TCP/IP 的是即使在这种环境下也要进行控制,尽量不要浪费网络流量。
在BSD的Unix以及 Windows 系统中,超时都以0.5秒为单位进行控制,因此重发超时都是0.5秒的整数倍。过程如下:
(1)数据被重发之后若还是收不到确认应答,则进行再次发送;
(2)此时,等待确认应答的时间将会以2倍、4倍的指数函数延长;
(3)达到一定重发次数之后,如果仍没有任何确认应答返回,就会判断为网络或对端主机发生了异常,强制关闭连接并且通知应用通信异常强行终止。如Window10系统SYN重传报文如下:
9、TCP的滑动窗有什么作用?介绍下相关机制
【产生背景】
TCP 以1个段为单位,每发一个就需要进行一个确认应答的处理,这样的传输方式有一个缺点:包的往返时间越长通信性能就越低。
***打个比方好比两个人对话:张三说完一句话,得到李四的确认回答,张三才能说下一句。每一次都是你一句话我一句确认,沟通方式非常低下。
【机制介绍】
为解决这个问题,TCP 引人了“窗口“这个概念,它是操作系统开辟的一个缓存空间,即使RTT(往返时间)较长也能控制网络性能的下降。确认应答以更大的单位进行确认,也就是说,发送端主机在发送了1个TCP段以后不必要一直等待确认应答而是继续发送,转发时间将会被大幅度的缩短。
***也就是张三可以一次性连续说多句话,然后一次性等待李四回复OK就行,李四听不清楚的就重新说,完全听清楚了就继续往下说!
窗口大小就是指无需等待确认应答而可以继续发送数据的最大值,上图的窗口大小为4个段(每个段长度1000)。
【窗口类型】
TCP滑动窗口分为两种:发送窗口和接受窗口。
发送端的滑动窗口包含四个部分:
● 已发送且已收到ACK确认
● 已发送但未收到ACK确认
● 未发送但可以发送
● 未发送且不能发送
上图标注的虚线部分就是发送窗口,TCP发送缓存区,是发送端被允许发送的最大数据包大小
● SND.WND:表示发送窗口的大小,上图虚线框的格子大小就是4000个字节。
● SND.UNA:一个绝对指针,它指向的是已发送但未确认的第一个字节的序列号。
● SND.NXT:下一个发送的位置,它指向未发送但可以发送的第一个字节的序列号。
接收端的滑动窗口包含三个部分:
● 已成功接收并确认
● 未收到数据但可以接收
● 未收到数据并不可以接收的数据
上图虚线矩形框就是接收窗口,TCP接收缓存区,用于存储未被进程使用的传入数据。
● REV.WND:表示发送窗口的大小,上图虚线框的格子大小就是3000个字节。
● REV.NXT:下一个接收的位置,它指向未收到但可以接收的第一个字节的序列号。
【实现方式】
下面小云君用图解的方式说明TCP交互中滑动窗口的实现机制:
上述图解是接收端(服务器)进程能很好的处理掉接收的数据的情况,因此可以保证接收窗口大小不变,能持续很好的滑动窗口接收数据。但设想一下,如果来不及处理就会占满TCP接收缓存区,也就是接收端窗口为0,此时就会通知发送端停止发数据了,这也就是TCP流量控制机制。
10、说说半连接队列和 SYN Flood 攻击的关系
SYN Flood为DDoS攻击(分布式拒绝服务攻击Distributed Denial of Service)的一种,攻击利用TCP 三次握手的一个漏洞向目标计算机发动攻击,分为几步:
(1)攻击者向目标计算机发送 TCP连接请求 (SYN 报文),然后对于返回的 SYN-ACK 报文不作回应;
(2)目标计算机如果没有收到攻击者的 ACK 回应,就会一直等待形成半连接,直到连接超时才释放;
(3)攻击者利用这种方式发送大量 TCP SYN 报文,让目标计算机上生成大量的半连接,迫使其大量资源浪费在这些半连接上;
(4)目标计算机一旦资源耗尽,就会出现速度极慢、正常的用户不能接入等情况;
(5)攻击者还可以伪造 SYN 报文其源地址是伪造的或者不存在的地址,向目标计算机发起攻击。
11、TCP流量控制和拥塞控制有什么区别?
🔷流量控制:
作用:为了解决发送方和接收方速度不同而导致的数据丢失问题,当发送方发送的太快,接收方来不及接受就会导致数据丢失;
方式:由接收端采用滑动窗口的形式,告知发送方允许/停止发包解决TCP丢包问题。
🔷拥塞控制:
作用:为了解决过多的数据注入到网络导致网络崩溃和超负荷问题;
方式:由发送方采用拥塞窗口的形式去判断网络状态,从而采取不同算法执行TCP动态发包解决网络整体质量问题。
12、介绍下TCP 的流量控制?
作用:为了解决发送方和接收方速度不同而导致的数据丢失问题,当发送方发送的太快,接收方来不及接受就会导致数据丢失;
方式:由接收端采用滑动窗口的形式,告知发送方允许/停止发包解决TCP丢包问题。
发送端会根据自己的实际情况发送数据,但因为接收端接收不过来的话,接收方只能把处理不过来的数据存在缓存区里。如果缓存区都满了对方还在疯狂发送数据,接收方只能把收到的数据包丢掉,这就造成了网络资源的浪费!典型的场景如以太网场景中10G设备向1G设备发TCP包:
为了防止这种现象的发生,TCP 提供一种机制可以让发送端根据接收端的实际接收能力控制发送的数据量。这就是所谓的流控制。
它的具体操作是:
(1)接收端主机向发送端主机通知自已可以接收数据的大小;
(2)于是发送端会发送不超过这个限度的数据,该大小限度就被称作窗口大小。窗口大小的值由接收端主机决定,而在TCP 首部中,专门有一个字段用来通知窗口大小:
(3)接收主机将自己可以接收的缓冲区大小放入这个字段中通知给发送端,这个字段的值越大,说明网络的吞吐量越高。
不过,接收端的这个缓冲区一旦面临数据溢出时,窗口大小的值也会随之被设置为一个更小的值通知给发送端,从而控制数据发送量。也就是说,发送端主机会根据接收端主机的指示,对发送数据的量进行控制。这也就形成了一个完整的TCP流控制(流量控制)。当Window=0时,即告知发送方停止发送数据。
下图为根据窗口大小控制流量过程的示例:
如图所示,当接收端收到从 3001 号开始的数据段后其缓冲区即满,不得不暂时停止接收数据。之后,在收到发送窗口更新通知后通信才得以继续进行如果这个窗口的更新通知在传送途中丢失,可能会导致无法继续通信;为避免此类问题的发生,发送端主机会时不时的发送一个叫做窗口探测的数据段,此数据段仅含一个字节以获取最新的窗口大小信息。
13、介绍下TCP的拥塞控制?
作用:为了解决过多的数据注入到网络导致网络崩溃和超负荷问题;
方式:由发送方采用拥塞窗口的形式去判断网络状态,从而采取不同算法执行TCP动态发包解决网络整体质量问题。
先了解两个概念:
■ 拥塞窗口(cwnd):发送方维持的一个状态变量,其大小取决于网络的拥塞程度,并且动态变化。
■ 慢开始门限(ssthresh):为了防止拥塞窗口cwnd的增长过大引起网络拥塞所设置的一个门限值。
通过四种算法实现拥塞管理:
■ 慢开始
■ 拥塞避免
■ 超时重传(1988年TCP Tahoe版本,已废弃不用)
■ 快重传(1990年Reno版本,在用)
■ 快恢复(1990年Reno版本,在用)
也就是说发送方会动态判定网络状态并按照上述算法调整TCP的发包节奏,那么如何确认使用算法呢?如下:
|当cwnd < ssthresh时,使用慢开始算法;
|当cwnd > ssthresh时,停止使用慢开始算法而改用拥塞避免算法;
|当cwnd = ssthresh时,既可使用慢开始算法,也可使用拥塞避免算法。
🔷一:慢开始
发送方先探测网络拥塞程度,并不是一开始就发送大量的数据,发送方会根据拥塞程度增大拥塞窗口cwnd。
计算方法:每经过一个传输轮次cwnd值就加倍,让cwnd值呈指数增加。
如上图,大体过程:
① 当前发送方cwnd值为1,因此只能发送一个数据报文段(拥塞窗口cwnd值是几就能发送几个数据段)
② 接收方收到该数据报文段后回复一个确认报文段,发送方收到该确认报文后,将cwnd值变为2(加倍);
③ 发送方此时可以连续发送两个数据段,接收方收到该数据段后一次发回2个确认报文段;
④ 发送方收到这两个确认报文后,将cwnd值加2变为4(加倍)后可以连续发送4个数据段,以此类推直至cwnd=ssthresh。
🔷二:拥塞避免
继上图达到cwnd≥ssthresh后采用该算法用来控制拥塞窗口的增长速率。
计算方法:每经过一个传输轮次cwnd值加1,让cwnd值呈线性缓慢增大。
🔷三:拥塞发生
当网络发生拥塞丢包时(如图假定cwnd=24),会有两种情况:
● 超时重传(1988年TCP Tahoe版本,已废弃不用)
更新后的 ssthresh 值变为 12(即为出现超时时的窗口数值 24 的一半),拥窗口再重新设置为1,并执行慢开始算法。当cwnd = ssthresh = 12 时改为执行拥塞避免算法拥塞窗口按线性规律增长,每经过一个往返时间增加一个MSS的大小。在TCP拥塞控制的文献中经常可看见“乘法减小”(Multiplicative Decrease)和“加法增大”(Additive Increase)这样的提法。“乘法减小”是指不论在开始阶段还是拥塞避免阶段,只要出现超时(即很可能出现了网络拥塞),就把慢开始门限值 ssthresh 减半,即设置为当前的拥塞窗口的一半(与此同时,执行慢开始算法)。而“加法增大”是指执行拥塞避免算法后,使拥塞窗口缓慢增大,以防止网络过早出现拥塞。上面两种算法合起来常称为 AIMD算法(加法增大乘法减小)。
● 快重传和快恢复(1990年TCP Reno版本,在用)
超时重传算法直接把cwnd减小到1太过强烈,若还能收到连续3个ACK说明网络质量没那么差。同时采用快重传和快恢复算法,过程如下:
(1)当发送方连续收到3个重复确认时即执行“乘法减小”算法,把慢开始门限ssthresh 减半;
(2)由于发送方现在认为网络不那么差,于是把cwnd值设置为开始门限ssthresh 减半后的数值;
(3)开始执行拥塞避免算法 (“加法增大”)使拥塞窗口缓慢地线性增大。
扫描下方二维码关注微信公众号:小云君网络
原创不易,感谢大家支持!!