TCP传输控制协议(Transmission Control Protocol,縮寫:TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议。----维基百科
TCP 三次握手的目的是为了建立**安全可靠的全双工【双发都可收发】**通信通道 。三次握手确定双发链路通畅,并商定初始数据通信序列号,确保数据完整及重传机制可行。
TCP为什么需要三次握手 一次两次不行吗 ?
只有通过对方对A Message的反馈,才能知道A—Message是否被收到【参考发短信】,无法通过A-Message前面的信息确认,通信双方彼此确认信息,达成共识的最小交互路径就是三次。
TCP协议中任何消耗了序列号的报文都需要ACK确认其发送成功,否则,就要重传。
一次握手不可以:一次压根不算握手,等于零次
只通过一次握手客户端压根不知道服务端是否开启,就好比你对隔壁房子的人喊话:我明天去你家,如果不考虑回应,你压根不知道邻居是否同意,这种情况下,握手对自己而言等于没有,无法确定链路是否通畅。
两次握手不可以:虽然能客户端确定服务端的收发能力,但服务端无法确定客户端的收发能力【比如对方防火墙限制不能接受海外的数据】
每一端在正式Established状态的时候,都要确信对方能收到自己的信息,不然在这个点,这个通信链路就不算可靠建立。两次握手Established的时候,服务端无法确认这个点客户端的收发能力是否正常【无法确定客户端是否可以收到第二次握手信息】,如果强制确立,出现异常后,会导致Server端建立虚假链接,浪费Server资源。个人感觉可能有两种情况:
上面这种发生的场景如下:
* 客户端发送SYN
* 服务端收到SYN,并回复客户端,同时确定建立链接
* 服务端回复的数据丢失
* 客户端重发SYN,并丢失
* 客户端重发SYN,并丢失
* 客户端放弃链接,并且可能服务端收不到任何响应
* 服务端白白等待
这种情况下,服务端就白白的浪费了一个链接资源,因为:在未确认信息被收到的情况,服务端就私自建立了链接,这种情况下,客户端是可能放弃建立链接的,不过两次握手,对于客户端单项发送数据是没有问题的。
还有一种场景是SYN信息之后到达,如下:
* 客户端发送SYN
* SYN超时,客户端重发
* 服务端收到SYN,并回复客户端,同时确定建立链接
* 客户端收到响应,确定建立链接
* 客户端与服务端传输数据
* SYN延迟到达服务端
* 服务端收到SYN,并回复,同时确定建立链接
* 客户端已经关闭了链接通道,不会有任何响应
* 服务端白白等待
上面两种场景不可靠的最终原因都是:服务端没有收到反馈的情况下,私自建立链接,想要避免这种情况,必须要等待第二次信息被客户单确认,这就是增加第三次握手的必要性。
三次握手可以
三次握手:三次握手保证了双方都能收到对方对于自己发送信息的反馈。对于第一种错误场景的纠正:
客户端在没有收到第二次握手,而放弃链接服务端的场景下,服务端是不可能收到客户端的ACK的,这时,服务端是不会成功建立链接的。对于第二种场景。
在延迟SYN到达服务端后,服务端需要等待Client端的ACK,才会确认链接建立,已经关闭链接的前提下,应该是没有有效ACK返回的,服务端会重发几次后,关闭半开放链接。对于链接存活状态的下的延时SYN,理论上都能通过丢弃来解决,不考虑这种场景。
从客户端角度来说,发送SYN后,一直没收到ACK 就会重发,从服务端的角度来说,发送SYN-ACK后,没有收到ACK就会重发,两者理论上也能同时发生,服务端在重发SYN-ACK的时候,客户端可能也在重发SYN,不过客户端不会重发ACK,一旦客户单收到SYN-ACK就认为链接已经建立。可以发送数据,如果服务端在没收到ACK的情况下先收到了DATA(还没触发重发逻辑),会怎么样?也就是说ACK丢失会如何,个人理解,服务端也可以看做链接建立,TCP协议框架下本身是支持第三次握手携带用户数据的,只不过可能有些系统需要配置才能启用而已。参考
握手时候确认的序列号保证了第一份数据的准确定,同时也保证了后续数据不乱序。
TCP不同名词概念
- 同步报文段:携带SYN标志的报文段,用来同初始序列ISN
- 确认报文段:携带ACK标志的报文段,在连接建立后所有传送的报文段都会把ACK设置为1【其实只有发起SYN的时候没设置】
- 复位报文段:携带RST标志的报文段,一般发生异常的时候启用
- 结束报文段:携带FIN的报文段,表示发送方的数据发送完毕,要求释放TCP连接
- Sequence Number是包的序号,用来解决网络包乱序问题。
- Acknowledgement Number就是ACK——用于确认收到,用来解决丢包的问题。ACK报文可以携带数据。如果不携带数据,则不消耗序号,下一数据报文段的序号仍是seq=x+1。
握手中各种异常的处理
第三次的ACK在网络中丢失,Server端根据 TCP的超时重传机制,会等待3秒、6秒、12秒后重新发送SYN+ACK包,次数可以通过设置/proc/sys/net/ipv4/tcp_synack_retries修改,默认值为5.如果重发指定次数之后,仍然未收到 client 的ACK应答,那么一段时间后,Server自动关闭这个连接。
客户端connect()在 TCP的三次握手的第二次握手完成后就返回成功。也就是说 client 在接收到 SYN+ACK包,它的TCP连接状态就为 established (已连接),表示该连接已经建立。在第三次握手中的ACK包丢失的情况下,Client 向 server端发送数据,Server端将以 RST包响应,方能感知到Server的错误。
关闭为什么四次挥手
四次挥手比三次握手【三步握手】多了一次,原因是:全双工数据传输正在进行,且同时确保数据传输完毕。三次握手的时候,没有数据传输,所以Server返回的ACK与第二个SYN可以合并到一个,但是挥手的时候,其实是存在数据传的,无法同时传输完毕【或者某个确定时间】,双发传输完毕的时机都是随机的,所以完毕通知的也会不同步的,只能分开通知等ACK,无法像三次握手一样合并,所以才多了一次,客户端或服务器均可主动发起挥手动作,任何一方Socket执行 close() 操作即可产生挥手动作。
|