在这篇文章(水文)中你将会简单了解到TCP协议以及TCP协议的握手和挥手的环节
什么是TCP协议
- TCP协议是位于TCP/IP协议族中传输层的协议。
TCP(Transmission Control Protocol)传输控制协议,是面向连接,可靠的,基于字节流的传输层通信协议,为应用层 提供计算机之间的数据传输。
- TCP协议接收到由应用层传输下来的大块数据之后会对其进行分割成最适宜的以报文段为单位的数据包进行管理(数据包是网络传输中最小的单位),并会将每个包进行编号,这样才能保证目标机器接收到数据包之后进行有序的排列并重组成原请求报文。
与目标机器建立连接
- TCP协议会将每个报文段发送给对方,在此之前我们要先与目标机器建立连接。
- 三次握手就是TCP建立连接的过程:
- 假设现在客户端向服务端建立TCP连接,此时客户端作为主动方,首先向目标服务器发送带有【SYN】标志的数据包,此时客户端会处于SYN-SEND状态。
- 服务端接收到客户端的【SYN】包之后,会回复【SYN,ACK】数据包并且此时服务端进入SYN-RCVD(RECEIVED)状态。
- 客户端接收到服务端的【SYN,ACK】数据包后,会向服务端发送【ACK】确认包,并且此时处于ESTABLISHED(建立)状态,服务端接收到ACK之后也会同样进入ESTABLISHED状态。此时就可以进行正常的数据传输了。
三次握手异常
- 上述呢是TCP正常建立连接的过程,为什么这么说,还有不正常的?
- 对!还有不正常的情况!我们列举以下几种情况。
- 客户端【SYN】包 丢包了,服务端没有接收到【SYN】包。正常情况下来讲,服务端接收到【SYN】包之后会回复【SYN,ACK】包给客户端。但是现在客户端收不到因为服务端根本都没收到连接请求更别提回复【SYN,ACK】包了,那么在一定的时间范围内,会触发超时重传机制,tcp_syn_retires 的参数来限制重传次数,默认为5次。
- 服务端向客户端【SYN,ACK】丢包了,客户端迟迟等不到ack确认,又会认为自己的【SYN】丢包了,所以此时还会重新发送【SYN】包(与1一致),而服务端同时也会因为迟迟不到【ACK】确认而触发重传,tcp_synack_retires 的参数来限制重传次数,默认也为5次。
- 客户端向服务端发送的【ACK】包 丢包了。在发送完ACK之后客户端此时会进入 ESTABLISHED状态。但是服务端迟迟收不到【ACK】确认,所以仍然处于SYN-RCVD状态,在一定时间内还是会触发重传的。但是之前说过在进入ESTABLISHED状态后可以正常传输数据了,所以此时如果客户端向服务端发送数据,那么接收到数据包之后怎么处理?答案就是服务端会正常接收并且进入ESTABLISHED状态。这是因为在ESTABLISHED状态下,开始发送数据包的时候会携带上【ACK】确认包,这样就能通过这个【ACK】包进行确认了。
- 客户端故意不发送【ACK】,在接收到【SYN,ACK】之后就不进行回复了,这样对服务器的压力比较大,属于Dos攻击的一种,利用的就是TCP的连接缺陷问题。
通信结束(断开连接)
- 在通信结束之后,需要断开与服务的连接,此时要经历的就是四次挥手来进行服务的断开。
- 四次挥手就是断开连接的过程:
- 假设所有数据发送完毕了,客户端想要与服务端断开连接,此时双方都是处于ESTABLISHED状态的,那么客户端作为主动方要先向服务端发送【FIN】包,此时客户端会进入FIN-WAIT-1状态。
- 那么服务端在接收到了客户端的【FIN】包之后首先会回复【ACK】确认,并且服务端进入CLOSE-WAIT阶段,客户端收到ACK之后会进入FIN-WAIT-2阶段
- 此时如果还有数据从服务端向客户端发送,客户端仍然还会接受,如果没有要发送的内容了那么服务端会向客户端发送【FIN,ACK】包进行确认,此时服务端进入LAST-ACK阶段
- 客户端收到【FIN】之后会向服务端发送【ACK】进行确认并且此时客户端进入TIME_WAIT状态会进行长达2MSL的等待时间,服务端在接收到ACK之后就会处于CLOSE。经过了2MSL之后客户端也会进入CLOSE。
异常情况
下面来列举一下有关四次挥手过程中可能会出现的异常情况。
- 客户端作为主动方,主动与服务端断开连接,【FIN】丢包了。还是像前面的握手一样,客户端会触发超时重传机制,直到达到限制次数之后则断开。
- 服务端向客户端回复【ACK】丢包了,一样的,客户端还是没有接收到ACK确认,它还是会认为自己发送的【FIN】丢包了,所以依然还是会进行超时重传机制,服务端在接收到客户端的【FIN】后又会重新发送ack确认。还有一种情况,就是如果服务端没有数据要向客户端发送了那么就会发送【FIN,ACK】,这个数据包是携带了ACK的所以即使刚刚的ACK,客户端没有收到,只要这个包能收到客户端就可以凭借这个从FIN-WAIT-1阶段直接进入到TIME_WAIT阶段。
- 如果【FIN,ACK】丢包了,情况一:如果之前的ACK也丢包了,那么客户端还是存在于收不到ACK确认而自身也触发超时重传的情况之中,依然的服务端会触发超时重传机制进行重发;情况二:之前的ACK收到了所以当前客户端的状态是处于FIN-WAIT-2阶段的,那么在这段时间内客户端仍然还在等候【FIN】,服务端仍会触发超时重传机制进行重发,但是并不是一直进行等待的,在经过了对这个状态的所限制的最长超时时间之后客户端则会直接断开。
- 客户端回复的【ACK】丢包了,在这时间内,服务端由于没有接收到【ACK】确认,所以会重传【FIN】那么客户端在接收到之后会重传【ACK】,但是服务器并不是一直进行等待的,如果超过了等待的时间那么服务器会主动进行断开。如果在等待的过程中,有其他的客户端等待接入,那么新的客户端会向服务端发送【SYN】想要建立连接,服务端此时回复的【FIN,ACK】新的客户端是不认可的,所以会向服务端回复【RST】进行服务端的状态重置。
Q & A
那么来对上面的一些知识点进行一个提问:
- 为什么分手需要四次
我们上面了解到了握手需要进行三次:发送【SYN】进行状态连接,回复【SYN,ACK】进行应答,最后回复【ACK】确认连接。
但是为什么挥手不能三次呢?我客户端先发【FIN】,服务端接收到再回复【FIN,ACK】,最后确认断开回复【ACK】这不是也很合理么。
是这样的,在挥手环节【FIN】首先用来进行断开连接的请求,此时服务端回复的【ACK】目的是为了告诉客户端:“我收到了你断开的请求,但是我可能还有数据没发给你,你等我发完最后的数据,再向你关闭。” 所以这也就是说也许有数据要继续发送的可能性,那么此时如果直接就发送【FIN】是不是不太合理了。所以要等待可能数据不再发送了才会发送【FIN】。
所以挥手的环节:
- 客户端:哥,我没有东西要发给你了咱们先断开连接吧! -> 发送【SYN】断开请求
- 服务端:行,没问题,我收到了你的断开连接的请求,但是我可能还有数据没发完,先和你说一声,你等等我发完。 -> 发送【ACK】确认收到
- 服务端: 好嘞,都发完了,那我现在也回复断开报文。 -> 发送【FIN,ACK】
- 客户端:好嘞哥,我收到了,我向你确认,我已经收到了,你可以断开了。 -> 发送【ACK】
- 挥手环节最后主动方进入TIME_WAIT 阶段为什么要等2MSL,而不是直接关闭。
MSL(Maximum Segment Lifetime)最大报文段寿命,其实指的就是TCP报文段在一次传输过程中所能存活的最长时间。
为什么主动方不直接断开连接: 客户端(主动方)向服务端(被动方)发送【ACK】进行确认,如果【ACK】丢包,那么服务端就会迟迟等不到ACK确认而重发【FIN,ACK】,那么客户端收到了就会再次发送【ACK】进行确认。如果客户端在发送完了ACK确认之后就直接断开连接,如果丢包,服务端就会重发【FIN,ACK】但是客户端根本就接收不到了。
所以客户端不能直接关闭要等待服务端是否有消息发送,有消息发送就代表着没有收到【ACK】确认,所以要重传,没有消息就代表服务端已经收到了【ACK】确认并且已经断开了。所以客户端接收不到消息,等待2MSL之后也会断开连接。
那么为什么要等待2 * MSL呢,这刚好是可以一来一回的过程。对就是这样的,上面写到,如果客户端能收到消息(服务端发送的【FIN,ACK】)就是代表【ACK】丢包了,那么这样的话,报文去一来回刚好可以让客户端收到重传的【FIN,ACK】报文。然后客户端就会重传【ACK】,客户端的计时器也会重置,重新开始计时(2MSL)。
- 在连接已经建立的情况下,客户端出现了问题怎么办?
如果客户端出现了问题,服务端不会一直等待,白浪费资源。所以会有一个东西叫做保活计时器,服务器每收到一次请求,就会重置一次计时器,在长时间没有接收到请求且计时器timeout的时候,服务器就会每隔75秒向客户端发送探测报文段,若发了10个探测报文段之后都没有响应,就会认为该客户端出现了故障,客户端则主动进行断开。
- TCP的重传机制?
由于可能会出现丢包(网络层出现丢失)的情况,为了保证数据传输的可靠性,TCP会重传认为丢失的包,TCP使用两套机制来完成这个任务。一个是基于时间,一个是基于确认信息(报文中的错误)。TCP在发送一个数据之后,就会开启一个定时装置,若在这段时间内没有收到ACK确认就会对该报文重传,但是达到限定次数之后则会复位。
写在最后:
看完了上面的操作,你是否觉得TCP在面对异常的sao操作的时候也总是能那么的化险为夷,要不为什么说TCP是可靠的传输层通信协议呢!当然TCP的东西还远不止如此,比如:丢弃重复的数据,延迟传送,流量控制等等等....
文章呢就是用来记录学习笔记和自己理解的东西的,即使忘记了知识点也可以跑来看看。当然内容还是比较笼统和浅显的,如果有理解上的错误,还烦指出,Thanks~