TCP协议中的三次握手
本文是从各位大牛博客和百科以及书籍资料中整理,如有出错和补充希望大家指正。
首先根据百科的定义介绍了解:
def: 所谓的“三次握手”即对每次发送的数据量是怎样跟踪进行协商使数据段的发送和接收同步,根据所接收到的数据量而确定的数据确认数及数据发送、接收完毕后何时撤消联系,并建立虚连接。
第一次握手:由客户端发起,发送请求报文段生成随机序列号,并发送一个syn包(同步序列编号),并进入SYN_SENT状态. 设置此处seq=x;
第二次握手: 服务器收到syn包,必须确认客户的SYN(ACK(ack是期望对方继续发送的那个数据包的序列号)=x+1),同时自己也发送一个SYN包(seq=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到了额syn+ack包后,返回一个ack=y+1。来表示自己知道服务器已经准备好,然后进行连接双方进入TCP连接成功状态(established).
定义补充:
- seq:随机序列号,占4字节,序列号seq就是这个报文段中的第一个字节的数据编号。
- ack:确认号,当前报文段最后一个字节的编号+1。
- ACK:占1位,仅当ACK=1时,确认号字段才有效。ACK=0时,确认号无效。
- SYN:SYN=1,ACK=0时表示:这是一个连接请求报文段。SYN=1表示这是一个连接请求,或连接接受报文。SYN这个标志位只有在TCP建产连接时才会被置1,握手完成后SYN标志位被置0。
- RST:对方要求重新建立连接,复位。
- 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状态,完成四次挥手。
SYN-ACK 重传次数是有限制的:服务器发送完SYN-ACK包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传,如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。注意,每次重传等待的时间不一定相同。
半连接存活时间:是指半连接队列的条目存活的最长时间,也即服务从收到SYN包到确认这个报文无效的最长时间,该时间值是所有重传请求包的最长等待时间总和。有时我们也称半连接存活时间为Timeout时间、SYN_RECV存活时间。
其他定义补充:
- TCP提供可靠的面向连接的服务,TCP是全双工的,即任意一端可以发送数据,也可以接受数据,需要有一个发送序列号和接受序列号。
- TCP三次握手的目的是同步连接双方的序列号和确认号,并交换TCP窗口大小信息,确认双方有收发数据的能力。
- 为什么需要三次握手?两次不行吗?两次会造成一些意外,比如客户端的请求在某些情况暂时失效(即报文段没有传到服务器),于是再次请求连接后服务器建立连接,此时客户端之前的请求恢复作用,但是指向的服务器已经处于established状态,所以客户端会处于断开阶段,浪费服务器资源。
网上一些相关面试题整理:
- 第一类: 为什么建立连接是三次握手,而关闭连接却是四次挥手呢?
因为服务端在LISTEN状态下,当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,并不会立即关闭SOCKET,对方不再发送数据了但是还能接收数据,所以先回复一个ACK报文,表示同意关闭连接。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,所以ACK和FIN一般都会分开发送,故需要四步握手。 - 为什么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连接。 - 如果已经建立了连接,但是客户端突然出现故障了怎么办?
TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
Reference:
https://www.cnblogs.com/duan2/p/9180861.html
https://blog.youkuaiyun.com/qq_38950316/article/details/81087809