【痛定思痛】TCP 三次握手学习

前言:今天滴滴面试失败,痛定思痛,好好复习面试中最惨淡的计算机网络部分

面试中,面试官问我TCP与UDP最大的区别是什么,答:TCP可靠,UDP不可靠,一个面向有连接,一个面向无连接,一个快一个慢;追问tcp,答:tcp建立了连接,所以丢包或者不完整会重传;问:只有这些吗? 答:卡壳 ;问:其实还有顺序传输。问:知道TIME WAIT吗? 答:不知道

TCP特点:TCP和UDP差别相当大,TCP充分实现了数据传输中的各种控制功能,可以进行丢包时的充发控制,可以对次序乱掉的分包进行顺序控制。而且TCP作为面向有连接的协议,只有确认通信端存在时,才会发送数据,从而可以控制通信流量的浪费。

一.TCP服务模型

TCP服务由发送端和接收端创建一种套接字(socket)的端点来获得,每个套接字有一个套接字编号(地址),该编号由主机的IP地址以及一个本地主机的16位数值组成。这个16位数值称为端口(port)。为了获取TCP服务,必须显式地在一台机器和另一台机器的套接字之间建立一个连接。

所有TCP连接都是全双工的,并且是点到点的。所谓全双工,意味着同时可以在两个方向上传输数据,点到点则意味着每个连接恰好有两个端点。TCP不支持组播或者广播的方式。一个TCP连接就是一个字节流,而不是消息流。端到端之间不保留消息的边界。接收端不知道数据被写成字节流时切分成多大,只知道最终接收到了多大的数据。

当一个应用将数据传递给TCP时,TCP可以立即发出消息,也可以缓存到更多数据后一起发出去。因此TCP有一个PUSH标志位,告诉TCP不要延时传输。

二.TCP协议

每个网络都有一个最大传输单元MTU,发送端和接收端的每个段都必须适合MTU,才能单个不分段的传输数据,MTU通常是1500字节。

ACK被设置为1表示确认号字段是有效的。如果ACK为0,则该段不包含确认信息。

RST被用于突然重置一个以及变得混乱的连接,混乱有可能是由于主机崩溃,或者其他的原因。该标志位可以用来拒收一个无效的字段,或者拒绝一个连接请求。

SYN被用于建立连接的过程。在连接请求中,SYN=1 和 ACK = 0,表示该字段没有使用稍待的确认字段,但是,连接应答稍待的一个确认,因此SYN=1和ACK=1。本质上SYN位被用来同时表示CONNECTION REQUEST 和 CONNECTION ACCEPTED,然后进一步用ACK位来区分这两种可能。

FIN被用来释放一个连接。然而,在关闭一个连接之后,关闭进程可能会在一段不确定的时间内继续接受数据,SYN和FIN段都有序号,从而保证了这种段以正确的方式被处理。

TCP中的流量控制是通过一个可变大小的滑动窗口来控制的。窗口大小字段制定了从被确认字节算起可以发送多少个字节。窗口大小字段可以为0,说明到现在为之已经接收了多个确认号为-1的字节,但是接收端没有更多的机会来消耗数据,希望别再发数据,以后接收端可以通过发送一个具有同样确认号但是非零的窗口大小字段来通知重新发段。

   需要注意的是:
                (A)不要将确认序号Ack与标志位中的ACK搞混了。
                (B)确认方Ack=发起方Req+1,两端配对。

三.TCP连接建立

TCP使用三次握手来建立连接。它要求一方检查连接请求是否是确实是当前的。主机一选择一个序号x,并且发送一个包含x的CONNECTION REQUEST段给主机二。主机二回复一个ACK段作为对x的确认,并且宣告他自己的初始序号为y。最后主机一在他发送的第一个字段的数据中,对主机二的初始序号进行确认。

【痛定思痛】TCP 三次握手学习_第1张图片

 

正常情况下应该是:

 【痛定思痛】TCP 三次握手学习_第2张图片

【痛定思痛】TCP 三次握手学习_第3张图片

三.TCP连接的释放

 为了释放连接,任何一方都可以发送一个设置了FIN标志位的TCP段,这表示它已经没有必要发送了。当FIN段被另一方确认之后,这个方向上的连接就被关闭,不再发送任何数据,然而另一方可能还在发送数据,当两个方向都关闭后,连接才算是彻底释放。通常情况下,释放一个连接需要4个TCP段。每个方向上一个FIN和一个ACK。【第一个ACK和第二个FIN有可能被组合在同一个段内,变成三次握手】。

为了避免两军对垒问题,需要使用计时器,如果两倍于最大数据包的生存周期内,针对FIN的响应没有出现,那么FIN的发送端也直接释放链接。另一方最终会注意到无人监听,也会超时释放链接。

四.TCP连接管理模型

建立连接和释放连接所需的步骤可以用一个有限状态机来表示,该状态机的11种状态如下:

CLOSED:没有活跃的链接或者被挂起------------ 表示初始状态。

LISTEN:服务器等待入境呼叫---------------------这个也是非常容易理解的一个状态,表示服务器端的某个SOCKET处于监听状态,可以接受连接了。

SYN RCVD:到达了一个连接请求,等到ACK----------这个状态表示接受到了SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,基本上用netstat你是很难看到这种状态的,除非你特意写了一个客户端测试程序,故意将三次TCP握手过程中最后一个ACK报文不予发送。因此这种状态时,当收到客户端的ACK报文后,它会进入到ESTABLISHED状态。

SYN SENT:应用已经启动了打开了一个连接------------这个状态与SYN_RCVD遥相呼应,当客户端SOCKET执行CONNECT连接时,它首先发送SYN报文,因此也随即它会进入到了SYN_SENT状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT状态表示客户端已发送SYN报文。

ESTABLISHED:正常的数据传送状态-----------------------这个容易理解了,表示连接已经建立了。

FIN WAIT1:应用没有数据要发了---------------------这个状态要好好解释一下,其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。

FIN WAIT2:另一端同一释放连接------------------上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你,稍后再关闭连接。 

TIME WAIT:等待所有数据包寿终正寝-----------表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。

CLOSING:两端同时试图关闭连接------------这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当你发送FIN报文后,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却收到了对方的FIN报文。什么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是如果双方几乎在同时close一个SOCKET的话,那么就出现了双方同时发送FIN报文的情况,也就会出现CLOSING状态,表示双方都正在关闭SOCKET连接。

CLOSE WAIT :另一端已经发起关闭连接-----这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是查看你是否还有数据发送给对方,如果没有的话,那么你也就可以close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。

LAST ACK:等待所有数据包寿终正寝------------这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。

【痛定思痛】TCP 三次握手学习_第4张图片

TIME_WAIT状态存在的理由:
1)可靠地实现TCP全双工连接的终止
   在进行关闭连接四次挥手协议时,最后的ACK是由主动关闭端发出的,如果这个最终的ACK丢失,服务器将重发最终的FIN,
因此客户端必须维护状态信息允许它重发最终的ACK。如果不维持这个状态信息,那么客户端将响应RST分节,服务器将此分节解释成一个错误(在。
因而,要实现TCP全双工连接的正常终止,必须处理终止序列四个分节中任何一个分节的丢失情况,主动关闭的客户端必须维持状态信息进入TIME_WAIT状态。
 
2)允许老的重复分节在网络中消逝 
TCP分节可能由于路由器异常而“迷途”,在迷途期间,TCP发送端可能因确认超时而重发这个分节,迷途的分节在路由器修复后也会被送到最终目的地,这个原来的迷途分节就称为lost duplicate。
在关闭一个TCP连接后,马上又重新建立起一个相同的IP地址和端口之间的TCP连接,后一个连接被称为前一个连接的化身(incarnation),那么有可能出现这种情况,前一个连接的迷途重复分组在前一个连接终止后出现,从而被误解成从属于新的化身。
为了避免这个情况,TCP不允许处于TIME_WAIT状态的连接启动一个新的化身,因为TIME_WAIT状态持续2MSL,就可以保证当成功建立一个TCP连接的时候,来自连接先前化身的重复分组已经在网络中消逝。

 常见面试题

【问题1】为什么连接的时候是三次握手,关闭的时候却是四次握手?

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

【问题2】为什么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连接。
————————————————
版权声明:本文为CSDN博主「青柚_」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_38950316/article/details/81087809

你可能感兴趣的:(【痛定思痛】TCP 三次握手学习)