TCP三次握手与四次挥手详解(最全面)
TCP的三次握手与四次挥手
TCP报文段的首部格式
- 源端口和目的端口字段各占 2个字节。端口是运输层与应用层的服务接口。运输层的复用和分用功能都要通过端口才能实现。
- 序号字段占 4字节。TCP连接中传送的数据流中的每一个字节都编上一个序号。序号字段的值则指的是本报文段所发送的数据的第一个字节的序号。
- 确认号字段占 4字节,是期望收到对方的下一个报文段的数据的第一个字节的序号
- 数据偏移(即首部长度)占 4位,它指出TCP报文段的数据起始处距离TCP报文段的起始处有多远。“数据偏移”的单位是32位字(以4字节为计算单位)
- 保留字段占 6位,保留为今后使用,但目前应置为0。
- 紧急URG 当URG= 1 时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据)。
- 确认 ACK 只有当ACK= 1 时确认号字段才有效。当ACK= 0 时,确认号无效。
- 推送 PSH(PuSH)接收TCP收到PSH= 1 的报文段,就尽快地交付接收应用进程,而不再等到整个缓存都填满了后再向上交付。
- 复位 RST(ReSeT)当RST= 1 时,表明TCP连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。
- 同步 SYN 同步SYN= 1 表示这是一个连接请求或连接接受报文。
- 终止 FIN(FINis) 用来释放一个连接。FIN= 1 表明此报文段的发送端的数据已发送完毕,并要求释放运输连接。
- 窗口字段占2字节,用来让对方设置发送窗口的依据,单位为字节
- 检验和占2字节。检验和字段检验的范围包括首部和数据这两部分。在计算检验和时,要在TCP报文段的前面加上12字节的伪首部。
- 紧急指针字段占16位,指出在本报文段中紧急数据共有多少个字节(紧急数据放在本报文段数据的最前面)。
- 选项字段长度可变。TCP最初只规定了一种选项,即最大报文段长度 MSS。MSS告诉对方TCP:“我的缓存所能接收的报文段的数据字段的最大长度是MSS个字节。
- 填充字段这是为了使整个首部长度是4字节的整数倍。
TCP的工作原理
注意:
-
在发送完一个分组后,必须暂时保留已发送的分组的副本。
-
分组和确认分组都必须进行编号。
-
超时计时器的重传时间应当比数据在分组传输的平均往返时间更长一些。
TCP 的流量控制
一般说来,我们总是希望数据传输得更快一些。但如果发送方把数据发送得过快,接收方就可能来不及接收,这就会造成数据的丢失。
流量控制(flow control)就是让发送方的发送速率不要太快,既要让接收方来得及接收,也不要使网络发生拥塞。
利用滑动窗口机制可以很方便地在 TCP 连接上实现流量控制。
举个例子:
TCP的拥塞控制
在某段时间,若对网络中某资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏——产生拥塞(congestion)。
出现资源拥塞的条件:
对资源需求的总和 > 可用资源
若网络中有许多资源同时产生拥塞,网络的性能就要明显变坏,整个网络的吞吐量将随输入负荷的增大而下降。
拥塞控制与流量控制的关系
拥塞控制所要做的都有一个前提,就是网络能够承受现有的网络负荷。
拥塞控制是一个全局性的过程,涉及到所有的主机、所有的路由器,以及与降低网络传输性能有关的所有因素。
流量控制往往指在给定的发送端和接收端之间的点对点通信量的控制。
流量控制所要做的就是抑制发送端发送数据的速率,以便使接收端来得及接收。
拥塞控制所起的作用
慢开始和拥塞避免
发送方维持一个叫做拥塞窗口 cwnd (congestion window)的状态变量。拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化。
发送方让自己的发送窗口等于拥塞窗口。如再考虑到接收方的接收能力,则发送窗口还可能小于拥塞窗口。
发送方控制拥塞窗口的原则是:只要网络没有出现拥塞,拥塞窗口就再增大一些,以便把更多的分组发送出去。但只要网络出现拥塞,拥塞窗口就减小一些,以减少注入到网络中的分组数。
慢开始算法的原理
在主机刚刚开始发送报文段时可先设置拥塞窗口 cwnd = 1,即设置为一个最大报文段 MSS 的数值。
在每收到一个对新的报文段的确认后,将拥塞窗口加 1,即增加一个 MSS 的数值。
用这样的方法逐步增大发送端的拥塞窗口 cwnd,可以使分组注入到网络的速率更加合理。
发送方每收到一个对新报文段的确认(重传的不算在内)就使 cwnd加
三次握手建立TCP连接
第一次握手:A 的 TCP 向 B 发出连接请求报文段,其首部中的同步位 SYN = 1,并选择序号 seq = x,表明传送数据时的第一个数据字节的序号是 x。
第二次握手:B 的 TCP 收到连接请求报文段后,如同意,则发回确认。B 在确认报文段中应使 SYN = 1,使 ACK = 1,其确认号ack = x + 1,自己选择的序号 seq = y。
第三次握手:
- A 收到此报文段后向 B 给出确认,其 ACK = 1,确认号 ack = y + 1。A的TCP通知上层应用进程,连接已经建立。
- B 的 TCP 收到主机 A 的确认后,也通知其上层应用进程:TCP 连接已经建立。
四次挥手释放TCP连接
第一次挥手:
-
数据传输结束后,通信的双方都可释放连接。现在 A 的应用进程先向其 TCP 发出连接释放报文段,并停止再发送数据,主动关闭 TCP 连接。
-
A 把连接释放报文段首部的 FIN = 1,其序号seq = u,等待 B 的确认。
第二次挥手:
- B 发出确认,确认号 ack = u + 1,而这个报文段自己的序号 seq = v。
- TCP 服务器进程通知高层应用进程。
- 从 A 到 B 这个方向的连接就释放了,TCP 连接处于半关闭状态,B若发送数据,A还是要接收的
第三次挥手:
- 若 B 已经没有要向 A 发送的数据,其应用进程就通知 TCP 释放连接
第四次挥手:
- A 收到连接释放报文段后,必须发出确认。 •在确认报文段中 ACK = 1,确认号 ack = w + 1,自己的序号 seq = u + 1。
常见面试题
为什么TCP连接的时候是三次握手,关闭的时候却是四次握手?
答:
因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。
但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
为什么不能用两次握手进行连接?
答:
3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。
现在把三次握手改成仅需要两次握手,死锁是可能发生的。作为例子,考虑计算机S和C之间的通信,假定C给S发送一个连接请求分组,S收到了这个分组,并 发送了确认应答分组。按照两次握手的协定,S认为连接已经成功地建立了,可以开始发送数据分组。可是,C在S的应答分组在传输中被丢失的情况下,将不知道S 是否已准备好,不知道S建立什么样的序列号,C甚至怀疑S是否收到自己的连接请求分组。在这种情况下,C认为连接还未建立成功,将忽略S发来的任何数据分 组,只等待连接确认应答分组。而S在发出的分组超时后,重复发送同样的分组。这样就形成了死锁。
如果已经建立了连接,但是客户端突然出现故障了怎么办?
答:
TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
答:
虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。