TCP的三次握手和四次挥手理解,附带常见面试题

本文部分内容借鉴别人博客加以理解总结,不足之处欢迎指正!!!

1、TCP介绍

讲TCP之前必须先说一下TCP/IP协议,TCP/IP 意味着 TCP 和 IP 在一起协同工作。
TCP 负责不同应用程序之间的通信。IP负责两台设备之间的通信。
TCP 负责将数据分割并装入 IP 包,然后在它们到达的时候重新组合它们。IP 负责将包发送至接受者。
TCP/IP不是一个协议,而是一个协议族的统称,包括了IP协议,IMCP协议,TCP协议,以及我们更加熟悉的http、ftp、pop3协议等等。

IP协议虽然能把数据报文送到目的主机,但是并没有交付给主机的具体应用进程。而端到端的通信才应该是应用进程之间的通信。此时就需要用到UDP和TCP。

UDP,在传送数据前不需要先建立连接,远地的主机在收到UDP报文后也不需要给出任何确认。虽然UDP不提供可靠交付,但是正是因为这样,省去和很多的开销,使得它的速度比较快,比如一些对实时性要求较高的服务,就常常使用的是UDP。对应的应用层的协议主要有DNS,TFTP,DHCP,SNMP,NFS 等

TCP,提供面向连接的服务,在传送数据之前必须先建立连接,数据传送完成后要释放连接。因此TCP是一种可靠的的运输服务,但是正因为这样,不可避免的增加了许多的开销,比如确认,流量控制等。对应的应用层的协议主要有SMTP,TELNET,HTTP,FTP 等。

2、TCP/IP协议分层

在这里插入图片描述

  • 应用层:
    向用户提供一组常用的应用程序,比如电子邮件、文件传输访问、远程登录等。远程登录TELNET使用TELNET协议提供在网络其它主机上注册的接口。TELNET会话提供了基于字符的虚拟终端。文件传输访问FTP使用FTP协议来提供网络内机器间的文件拷贝功能。

  • 传输层:
    提供应用程序间的通信。其功能包括:一、格式化信息流;二、提供可靠传输。为实现后者,传输层协议规定接收端必须发回确认,并且假如分组丢失,必须重新发送。

  • 网络层 :
    负责相邻计算机之间的通信。其功能包括三方面。

    1. 处理来自传输层的分组发送请求,收到请求后,将分组装入IP数据报,填充报头,选择去往信宿机的路径,然后将数据报发往适当的网络接口。
    2. 处理输入数据报:首先检查其合法性,然后进行寻径–假如该数据报已到达信宿机,则去掉报头,将剩下部分交给适当的传输协议;假如该数据报尚未到达信宿,则转发该数据报。
    3. 处理路径、流控、拥塞等问题。
  • 网络接口层:
    这是TCP/IP软件的最低层,负责接收IP数据报并通过网络发送之,或者从网络上接收物理帧,抽出IP数据报,交给IP层。

3、 TCP的报文格式

在这里插入图片描述

  1. 源端口,16比特,标识哪个应用程序发送。
  2. 目的端口,16比特,标识哪个应用程序接收。
  3. 序号字段。32比特,TCP链接中传输的数据流中每个字节都编上一个序号。序号字段的值指的是本报文段所发送的数据的第一个字节的序号。
  4. 确认号,32比特,是期望收到对方的下一个报文段的数据的第1个字节的序号,即上次已成功接收到的数据字节序号加1。只有ACK标识为1,此字段有效。
  5. 数据偏移,4比特。即首部长度,指出TCP报文段的数据起始处距离TCP报文段的起始处有多远,以32比特(4字节)为计算单位。最多有60字节的首部,若无选项字段,正常为20字节。
  6. 保留,6比特,必须填0。
  7. URG:紧急指针有效标识。1比特,它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据),紧急标志为"1"表明该位有效。
  8. ACK:确认序号有效标识。 1比特,只有当ACK=1时确认号字段才有效。当ACK=0时,确认号无效。大多数情况下该标志位是置位的。TCP报头内的确认编号栏内包含的确认编号(w+1)为下一个预期的序列编号,同时提示远端系统已经成功接收所有数据。
  9. PSH :标识接收方应该尽快将这个报文段交给应用层,1比特。接收到PSH = 1的TCP报文段,应尽快的交付接收应用进程,而不再等待整个缓存都填满了后再向上交付。
  10. RST,1比特,重建连接标识。 当RST=1时,表明TCP连接中出现严重错误(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立连接。
  11. SYN,1比特,同步序号标识,用来发起一个连接。 SYN=1表示这是一个连接请求或连接接受请求。该标志仅在三次握手建立TCP连接时有效。它提示TCP连接的服务端检查序列编号,该序列编号为TCP连接初始端(一般是客户端)的初始序列编号。在这里,可以把TCP序列编号看作是一个范围从0到4,294,967,295的32位计数器。通过TCP连接交换的数据中每一个字节都经过序列编号。在TCP报头中的序列编号栏包括了TCP分段中第一个字节的序列编号。
  12. FIN,1比特,发端完成发送任务标识。 用来释放一个连接。FIN=1表明此报文段的发送端的数据已经发送完毕,并要求释放连接。
  13. 窗口, 16比特:TCP的流量控制,窗口起始于确认序号字段指明的值,这个值是接收端正期望接收的字节数。窗口最大为65535字节。
  14. 校验字段,16比特,包括TCP首部和TCP数据,是一个强制性的字段,一定是由发端计算和存储,并由收端进行验证。在计算检验和时,要在TCP报文段的前面加上12字节的伪首部。
  15. 紧急指针,16比特,只有当URG标志置1时紧急指针才有效。TCP的紧急方式是发送端向另一端发送紧急数据的一种方式。紧急指针指出在本报文段中紧急数据共有多少个字节(紧急数据放在本报文段数据的最前面)。
  16. 选项字段,可变。TCP协议最初只规定了一种选项,即最长报文段长度(数据字段加上TCP首部),又称为MSS。MSS告诉对方TCP“我的缓存所能接收的报文段的数据字段的最大长度是MSS个字节”。
    新的RFC规定有以下几种选型:选项表结束,无操作,最大报文段长度,窗口扩大因子,时间戳。
    • 窗口扩大因子:3字节,其中一个字节表示偏移值S。新的窗口值等于TCP首部中的窗口位数增大到(16+S),相当于把窗口值向左移动S位后获得实际的窗口大小。
    • 时间戳:10字节,其中最主要的字段是时间戳值(4字节)和时间戳回送应答字段(4字节)。
    • 选项确认选项:
  17. 填充字段,可变,用来补位,使整个首部长度是4字节的整数倍。
  18. 数据部分,可变,TCP负载。

4、三次握手

在这里插入图片描述

  • 第一次握手:Client将标志位SYN置为1,随机产生一个值seq=x,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。
  • 第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=y,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
  • 第三次握手:Client收到确认后,检查ack是否为x+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=y+1,并将该数据包发送给Server,Server检查ack是否为y+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。

5、四次挥手

四次挥手(Four-Way Wavehand)就是终止TCP连接,意思是断开一个TCP连接时,需要客户端和服务器总共发送4个包以确认连接的断开。在socket编程中,这一过程由客户端或服务器任一方执行close来触发,整个流程如下图所示:在这里插入图片描述
由于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭,上图描述的即是如此。

  • 第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
  • 第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
  • 第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
  • 第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。

四次挥手的状态
FIN_WAIT_1: 这个状态和FIN_WAIT_2状态都在再等待对方的回复,但是这两种状态是有区别的,FIN_WAIT_1就是主动方在ESTABLISHED状态的时候,想要主动关闭连接,向对方发送FIN报文,这时候就进入了FIN_WAIT_1状态。当他收到对方回复的ACK报文后,就进入了FIN_WAIT_2状态。 但是在实际操作中是很难遇到FIN_WAIT_1状态的,因为无论对方是什么情况都应该立刻回应ACK报文,但是FIN_WAIT_2状态还是可以在主动方中用netstat看到的。

FIN_WAIT_2: 上面已经对FIN_WAIT_2讲解过了,当主动方进入FIN_WAIT_2时,就表示着半连接状态,也就是主动方还有数据要发给对方,这个数据就是之后的ACK,所有他要等一会儿才关闭连接。

CLOSE_WAIT: 这个状态从表面也可以看出它的作用,就是等待关闭。当被动方接收到FIN时,会立刻回复一个ACK给对方,接下来就是进入CLOSE_WAIT状态。在这个状态中,被动方需要考虑自己还有没有数据要发送给对方,如果有可以继续发送,如果没有了就可以关闭连接了,发送一个FIN给对方。 这个状态其实也就是给自己一个缓冲的时间,让自己处理完需要处理的事,然后去关闭连接。

TIME_WAIT: 这个状态就是一段时间后进行一些操作。当主动方收到了对方发来的FIN报文,并发出ACK报文,接下来就等2MSL就可以进入CLOSED状态了。其实,如果主动方在FIN_WAIT_1状态下,收到了对方的FIN+ACK标志的报文,就可以跳过FIN_WAIT_2状态直接进入TIME_WAIT状态了。

LAST_ACK: 这个状态从表面不难不理解他的意思,这个状态就是被动方发送了FIN报文后,最后等待对方的ACK报文,收到ACK报文后就可以进入CLOSED状态了。

CLOSED: 上面提到了几次这个状态,相比也猜出来了,这个状态表示的就是连接中断,已经关闭。

6、常见面试题

①、为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

  • a、保证TCP协议的全双工连接能够可靠关闭
    如果Client直接CLOSED了,那么由于IP协议的不可靠性或者是其它网络原因,导致Server没有收到Client最后回复的ACK。那么Server就会在超时之后继续发送FIN,此时由于Client已经CLOSED了,就找不到与重发的FIN对应的连接,最后Server就会收到RST而不是ACK,Server就会以为是连接错误把问题报告给高层。这样的情况虽然不会造成数据丢失,但是却导致TCP协议不符合可靠连接的要求。所以,Client不是直接进入CLOSED,而是要保持TIME_WAIT,当再次收到FIN的时候,能够保证对方收到ACK,最后正确的关闭连接。
  • b、保证这次连接的重复数据段从网络中消失
    如果Client直接CLOSED,然后又再向Server发起一个新连接,我们不能保证这个新连接与刚关闭的连接的端口号是不同的。也就是说有可能新连接和老连接的端口号是相同的。一般来说不会发生什么问题,但是还是有特殊情况出现:假设新连接和已经关闭的老连接端口号是一样的,如果前一次连接的某些数据仍然滞留在网络中,这些延迟数据在建立新连接之后才到达Server,由于新连接和老连接的端口号是一样的,又因为TCP协议判断不同连接的依据是socket pair,于是,TCP协议就认为那个延迟的数据是属于新连接的,这样就和真正的新连接的数据包发生混淆了。所以TCP连接还要在TIME_WAIT状态等待2倍MSL,这样可以保证本次连接的所有数据都从网络中消失。

②、为什么连接的时候是三次握手,关闭的时候却是四次握手?

当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

③、为什么不能用两次握手进行连接?

3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。

④、如果连接已经建立,但是客户端突然出现故障了怎么办?

TCP设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

原创文章 12 获赞 6 访问量 431

猜你喜欢

转载自blog.csdn.net/Hzfeng666/article/details/105613048
今日推荐