为什么TCP要进行三次握手
在谢希仁着“计算机网络”第四版中讲“三次握手”的目的是“ 为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
“在另一部经典的”计算机网络“(Andrew S.Tanenbaum着,第四版)一书中讲”三次握手“的目的是为了解决”网络中存在延迟的重复分组“的问题。这两种不同的表述其实阐明的是同一个问题。
TCP
TCP(传输控制协议,传输控制协议)是一种面向连接的,可靠的,基于字节流的传输层通信协议,由IETF的RFC 793定义。在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能,用户数据报协议(UDP)是同一层内另一个重要的传输协议。在因特网协议族(Internet protocol suite)中,TCP层是位于IP层之上,应用层之下的中间层。不同主机的应用层之间经常需要可靠的,像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换。
UDP一般用于即时通信(QQ聊天 对数据准确性和丢包要求比较低,但速度必须快),在线视频(RTSP 速度一定要快,保证视频连续,但是偶尔花了一个图像帧,人们还是能接受的),网络语音电话(VoIP 语音数据包一般比较小,需要高速发送,偶尔断音或串音也没有问题)等等。
应用层向TCP层发送用于网间传输的,用8位字节表示的数据流,然后TCP把数据流分区成适当长度的(通常受该计算机连接的网络的数据链路层的最大传输单元(MTU)的限制)。之后TCP把结果包传给IP层,由它来通过网络将包传送给接收端实体的TCP层.TCP为了保证不发生丢包,每个就给包一个序号,同时也。序号保证了传送到接收端的实体的包的按序接收然后接收端的实体对已成功收到的包发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传.TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。
TCP是因特网中的传输层协议,使用三次握手协议建立连接。当主动方发出SYN连接请求后,等待对方回答SYN + ACK ,并最终对对方的SYN执行ACK确认。这种建立连接的方法可以防止产生错误的连接, TCP使用的流量控制协议是可变大的滑动窗口协议。
两个序号和三个标志位:
(1)序号:seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。
(2)确认序号:ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,ack=seq+1。
(3)标志位:共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义如下:
(A)URG:紧急指针(urgent pointer)有效。
(B)ACK:确认序号有效。
(C)PSH:接收方应该尽快将这个报文交给应用层。
(D)RST:重置连接。
(E)SYN:发起一个新连接。
(F)FIN:释放一个连接。
需要注意的是:
(A)不要将确认序号ack与标志位中的ACK搞混了。
(B)确认方ack=发起方req+1,两端配对。
TCP三次握手的过程如下:
- 客户端发送SYN(SEQ = x)报文给服务器端,进入SYN_SEND状态。
- 服务器端收到SYN报文,回应一个SYN(SEQ = y)ACK(ACK = x + 1)报文,进入SYN_RECV状态。
- 客户端收到服务器端的SYN报文,回应一个ACK(ACK = Y + 1)报文,进入成立状态。
三次握手完成,TCP客户端和服务器端成功地建立连接,可以开始传输数据了。
终止连接
建立一个连接需要三次握手,而终止一个连接要经过四次握手(“四次挥手”),这是由TCP的半关闭(half-close)造成的。具体过程如下图所示。
- 某个应用进程首先调用close,称该端执行“主动关闭”(active close)。该端的TCP于是发送一个FIN分节,表示数据发送完毕。
- 接收到这个FIN的对端执行“被动关闭”(被动关闭),这个FIN由TCP确认。
- 一段时间后,接收到这个文件结束符的应用进程将调用接近关闭它的套接字。这导致它的TCP也发送一个FIN。
- 接收这个最终FIN的原发送端TCP(即执行主动关闭的那一端)确认这个FIN。
注意:FIN的接收也作为一个文件结束符(end-of-file)传递给接收端应用进程,放在已排队等候该应用进程接收的任何其他数据之后,因为,FIN的接收意味着接收端应用进程在相应连接上再无额外数据可接收。
既然每个方向都需要一个FIN和一个ACK,因此通常需要4个分节。
【问题1】为什么连接的时候是三次握手,关闭的时候却是四次握手?
答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
【问题2】为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
答:每个具体TCP实现必须选择一个报文段最大生存时间MSL(Maximum Segment Lifetime),虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假设网络是不可靠的,有可能最后一个ACK丢失,所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。
【问题3】TIME_WAIT是TCP四次握手哪个阶段的状态,为什么要有这个状态。这个状态带来的好处和坏处是什么。在网络中,什么与这个状态相似
答:TIME_WAIT状态是四次挥手中server向client发送FIN终止连接后进入的状态,
TIME_WAIT: 表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带 FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。
【问题4】为什么不能用两次握手进行连接?
答:3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。
把三次握手改成仅需要两次握手,可能发生死锁。作为例子,考虑计算机Client端和Server端之间的通信,假定Client端给Server端发送一个连接请求分组,Server端收到了这个分组,并发 送了确认应答分组。按照两次握手的协定,S认为连接已经成功地建立了,可以开始发送数据分组。可是,Client端在Server端的应答分组在传输中被丢失的情况下,将不知道Server端是否已准备好,不知道Server端建立什么样的序列号,Client端甚至怀疑Server端是否收到自己的连接请求分组。在这种情况下,Client端认为连接还未建立成功,将忽略服务器端发来的任何数据分组,只等待连接确认应答分组。而服务器端在发出的分组超时后,重复发送同样的分组,这样就形成了死锁。
【问题5】关闭TCP连接一定需要4次挥手吗?
答: 不一定,4次挥手关闭TCP连接是最安全的做法。但在有些时候,我们不喜欢TIME_WAIT 状态(如当MSL数值设置过大导致服务器端有太多TIME_WAIT状态的TCP连接,减少这些条目数可以更快地关闭连接,为新连接释放更多资源),这时我们可以通过设置SOCKET变量的SO_LINGER标志来避免SOCKET在close()之后进入TIME_WAIT状态,这时将通过发送RST强制终止TCP连接(取代正常的TCP四次握手的终止方式)。但这并不是一个很好的主意,TIME_WAIT 对于我们来说往往是有利的。
来源:CSDN
作者:Charles_yy
链接:https://blog.csdn.net/u010899985/article/details/80965123