TCP连接三次握手和四次挥手
什么是TCP
TCP 全称为Transmission Control Protocol(传输控制协议) 是面向连接的、可靠的、基于字节流的传输层通信协议。
TCP头部
- 控制位
- URG (urgent) 紧急
- ACK (acknowledgement) 确认
- PSH (push) 传送
- RST (reset) 重置
- SYN (synchronous) 建立联机
- FIN (finish) 结束
- 建立连接时名词解释
- MSL (Mximum Segment Lifetime) 报文最大生命周期
- SEQ (Sequence number) 序列号
- ACK Number 下次确认接受号
- syns queue 半连接队列
- accept queue 全连接队列
三次握手
- 服务器新建套接字,绑定地址信息后进入监听状态,等待请求连接,状态由CLOSED进入Listen。
- 客户端发送建立连接请求报文 SYN标志为1,Sequence number(以下简写为SEQ)为 x,状态由CLOSED改变为SYN_SENT。
- 服务器接收到客户端发送的请求连接报文后,回复一条报文(SYN标志为1,ACK标志为1,SEQ为 y,ACK Number为 x + 1)表示接收到。状态由Listen改变为SYN_RCVD。并把连接放入syns quene 半连接队列。
- 客户端接收到服务器回应时,发送确认报文(ACK标志为1,SEQ为 x + 1,ACK Number为 y + 1),状态由SYN_SENT改为ESTABLISHED。
- 服务器收到客户端回应,状态由SYN_RCVD改为ESTABLISHED。并把连接放入accept quene队列中,从半连接队列中删除。
- 连接建立完成,双方可进行通讯。
Tips
- 报文中序列号是随机的数字,这里使用 x 和 y 区分客户端和服务器的序列号。
- 第三次握手中报文体可携带数据传输,其余报文无法传输数据。
补充问题
-
那么全连接队列满了会影响半连接队列吗?
TCP三次握手第一步的时候如果全连接队列满了会影响第一步drop 半连接的发生。
-
如果client走完第三步在client看来连接已经建立好了,但是server上的对应连接实际没有准备好,这个时候如果client发数据给server会如何处理?
如果client走完第三步在client看来连接已经建立好了,但是server上的对应连接实际没有准备好,这个时候如果client发数据给server,由于server没有准备好,所以server没有回复,一段时间后client认为丢包了然后重传,一直到超时,client主动发fin包断开该连接。
-
TCP三次握手失败,服务端会如何处理?
握手失败的原因有两种,第一种是服务端没有收到SYN,则什么都不做;第二种是服务端回复了SYN+ACK后,长时间没有收到ACK响应,则超时后就会发送RST重置连接报文,释放资源
-
TCP为什么是三次握手。
- 因为三次可以保证双方都具有收发报文的能力。
- 可以避免历史连接 :如图客户端连续发送多次 SYN 建立连接的报文,在网络拥堵等情况下一个「旧 SYN 报文」比「最新的SYN」报文早到达了服务端;那么此
时服务端就会回一个 SYN + ACK报文给客户端;
客户端收到后可以根据自身的上下文,判断这是一个历史连接(序列号过期或超时),那么客户端就会发送 RST 报文给服务端,表示中止这一次连接。如果是正确的连接,客户端会发送ACK报文给服务端,表示建立这一次连接。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bX3P0o4a-1622731035718)(https://note.youdao.com/yws/res/9/WEBRESOURCE1cb8ba851ffd16f8c9323e65cc2f89a9)] - 同步双方初始序列号:TCP 协议的通信双方, 都必须维护一个「序列号」, 序列号是可靠传输的一个
关键因素。序列号可以用来丢弃重复数据,可以标识发送数据哪些被收到,可以根据序列号有序接受。而两次握手只保证了一方的初始序列号能被对方成功接收,没办法保证双方的初始序列号都能被确认接收。 - 避免资源浪费: 如果是两次握手的话,当服务器返回SYN报文后建立连接,但是如果这次报文丢失,客户端没有接收到,此时会造成一些服务器认为的全连接数据在队列中无法去除,造成资源的浪费。
- 不使用四次连接原因:因为第二次报文中SYN标志和ACK标志可以合为一条,所以无需多次连接,因为多次也无法保证稳定建立一个安全有效的连接。
四次挥手
- 客户端发送连接终止报文(FIN标志为1,SEQ为x),状态由ESTABLISEHED变为FIN_WAIT1。
- 服务器接收到客户端发来的终止报文,并同意此次终止,发回一条确认报文(ACK为1,SEQ为y,ACK Num为x+1),状态由ESTABLISHED变为CLOSE_WAIT。由于还有服务器是被动关闭,所以有可能有数据未处理完成,所以等待数据处理完成。
- 服务器处理完成数据后,发送一个终止报文(FIN标志为1,SEQ为y+1,ACK Num为X + 1),状态由CLOSE_WAIT变为LAST_ACK。
- 客户端接受到服务器的终止报文后,发送一个确认报文(ACK标志为1,SEQ为x+1,ACK Num为y+2),状态由FIN_WAIT2变为TIME_WAIT,等待两个MSL时间后进入CLOSE状态。
- 服务器接收到客户端的确认后,状态由LAST_ACK变为CLOSE状态。此时连接已经断开,四次挥手结束。
补充问题
- 客户端为什么要等待两个MSL?
因为由于网络状态不一定,所以客户端最后一次发送的ACK报文服务器可能接收不到,如果不等待直接进入CLOSE状态的话,会导致服务器有大量冗余的LAST_ACK状态的连接。如果服务器在没接收到客户端的ACK报文后会重传FIN报文,此时客户端接受到后会重新发送ACK报文并重新计时两个MSL。两个MSL代表着两个报文的最大存活时间,如果两个MSL过去还未收到服务器的FIN报文,代表服务器已经接收到并关闭。 等待两个MSL还可以去除掉历史的数据,因为没有一个报文能存活超过一个MSL。客户端如果在这个状态中接收到数据包会丢弃。 - 服务器可以主动关闭连接吗?
可以主动关闭,此时服务器会充当图中的客户端,并且会等待2MSL. - 为什么是三次握手四次挥手?
因为被动关闭的一方需要临时处理未处理完的数据,所以导致FIN报文和ACK报文无法同时发送,所以需要四次挥手。
补充
- TCP连接中存在保活机制。
通信中,双方长时间没有数据交流,服务器会向客户端发送一个探测报文,如果连续多次未接收到回应,就断开连接。长时间默认为7200s,每隔一段时间默认为75s,连续多次无响应默认为9次。这些数据都可以在套接字中修改。
参考连接
- https://blog.csdn.net/qq_44443986/article/details/115966274?utm_source=app&app_version=4.8.0&code=app_1562916241&uLinkId=usr1mkqgl919blen
- https://mp.weixin.qq.com/s/rX3A_FA19n4pI9HicIEsXg
- https://blog.csdn.net/feeltouch/article/details/83155607