TCP三次握手、四次挥手全过程解析,TCP为什么需要三次握手?为什么需要TIME_WAIT状态?

tcp三次握手的发生情况:

首先服务端sockect、bind、listen,调用accept阻塞
客户端发送connect,此时发送SYN,服务端接收到SYN后发送SYN、ACK,在客户端接收到SYN、ACK之后connect返回并且发送ACK确认服务端的数据,服务端接收到ACK后accept返回

因此
服务端的三次握手发生在listen之后,accept之前,listen之后接收到SYN后内核处理相应信息(收到SYN创建连接将连接放入半连接队列,发送SYN、ACK后将连接从半连接队列放入全连接队列),accept成功返回后(accept只是从全连接队列里面取一个连接),服务端的连接建立,但是accept没有真正参与三次握手,accept只是从全连接队列里面取出一个连接
客户端的三次握手发生在connect之后,connect会触发SYN的发送,connect成功返回后客户端的连接建立

更具体的三次握手细节参考博文:
https://blog.csdn.net/jun2016425/article/details/81506353
里面讲解了半连接队列的状态、全连接队列的状态等
第三次握手失败怎么办?
修改

服务器重新进行第二次握手的次数/proc/sys/net/ipv4/tcp_synack_retries

的次数
在这里插入图片描述

为什么连接建立需要三次握手,而不是两次握手?
防止失效的连接请求报文段被服务端接收,从而产生错误。
假设连接建立只需要两次握手,即客户端不会发送最后一个ACK,服务端接收到SYN后发送SYN和ACK便会进入ESTABLISHED状态。当第一次客户端向服务端发起SYN后,这个SYN由于网络原因在网络中被滞留。而客户端会超时重传一个SYN,服务端接收到该SYN后进入ESTABLISED状态,客户端接收到SYN和ACK后成功建立连接,并且随后客户端和服务端已经完成了数据交换并且成功断开连接,断开连接后第一个SYN到达,服务端会以为客户端要建立新的连接,会发送SYN和ACK给客户端,并且自己进入ESTABLISHED状态,但是此时客户端早已进入CLOSED状态,服务端会一直等待客户端发送数据,造成服务端资源的浪费

tcp四次挥手:

假设客户端向服务端write数据,当数据写完后,
首先由客户端调用close主动发起关闭,客户端向服务端发送FIN包,在服务端接收到该FIN包后,read返回0,同时回复ACK,在服务端程序结束(exit或者main函数返回或者收到该进程终止的信号或者主动调用close(sockfd)后)会发送FIN告诉客户端,客户端收到FIN后回复服务端的ACK
在这里插入图片描述

因此,客户端的四次挥手发生在close之前,close成功返回后,客户端的状态处于TIME_WAIT,服务端为被动的四次挥手同时他也会调用close。谁处于TIME_WAIT状态取决于谁先发送FIN包,即谁先调用close

三次握手和四次挥手的11种状态转换如图:
在这里插入图片描述

对应到函数调用如图:
在这里插入图片描述

一个完整的数据发送和接收:
客户端首先调用connect发起连接,客户端发送SYN包,此时客户端处于SYN_SENT状态,当服务端收到客户端发送的SYN包后,listen被动打开,然后服务端向客户端发送SYN和ACK,此时服务端处于SYN_RCVD状态,随后客户端接收服务端的SYN和ACK,客户端的connect成功返回后,客户端的状态转为ESTABLISHED,并且向服务端发送ACK,服务端接收到ACK后accept返回,此时服务端的状态为ESTABLISED
经过上述状态的转变,客户端和服务端建立连接
客户端向服务端write数据,服务端read数据,并且向客户端回复ACK
在数据发送完毕后,客户端调用close函数向服务端发送FIN,并且客户端此时处于FIN_WAIT_1状态,服务端接收到FIN后,read返回0,此时服务端处于CLOSE_WAIT状态并且向客户端发送ACK,客户端接收到该ACK后,客户端转变状态到FIN_WAIT_2,在服务端exit或者main函数返回或者收到进程终止的信号后向客户端发送FIN或者调用close(),此时服务端转变状态为LAST_ACK,在客户端接收到FIN后转变状态为TIME_WAIT状态,然后客户端发送ACK,服务端接收到ACK后转变状态到CLOSED,在2MSL后客户端的状态也会由TIME_WAIT转为CLOSED。注意:TIME_WAIT状态是由主动一方产生的,也就是主动调用close的一方,因此客户端或者服务端都可能成为TIME_WAIT,这取决于谁主动调用.

TIME_WAIT状态存在的原因:
1.可靠地实现TCP全双工连接的终止
假设四次挥手的最后一个ACK丢失,那么服务端会超时重传一个FIN包,如果客户端不维护一个TIME_WAIT状态,那么客户端不会回复ACK包,它会响应一个RST给服务端,让服务端以为是一个错误发生(而事实上,这是正常的关闭连接过程,并非异常)
2.允许老的重复的分节在网络中消逝
假设如果不存在TIME_WAIT状态,如果此时在网络中有老的数据还在网络中传输,还未到达服务端,当当前连接断开后,有一个新的连接连接到相同的客户端和服务端,其端口号和IP地址都相同(代表和老的连接一样,但是内核无法识别他是一个新的连接还是原来的老的连接),连接建立成功后,此时老的数据到达服务端,服务端会根据以前的连接将数据发送到上层应用程序,导致不可预知的错误,因此主动方关闭的一方需要维护一个TIME_WAIT状态,处于该状态下的TCP连接不能立即以同样的四元组建立新连接,由于TIME_WAIT状态持续时间为2MSL(最长分节生命期,代表一个数据包在网络中最多存活多久),这样保证了旧TCP连接双工链路中的旧数据包均因过期(超过MSL)而消失,此后,就可以用相同的四元组建立一条新连接而不会发生前后两次连接数据错乱的情况。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值