vlambda博客
学习文章列表

一篇文章搞明白TCP协议的三次握手四次挥手

网络模型及对应协议、功能

OSI层 功能 TCP/IP协议
应用层 文件传输、电子邮件、文件服务、虚拟终端等应用程序之间的通信 TFTP、HTTP、SNMP、FTP、SMTP、DNS、Telnet
表示层 数据格式化、代码转换、数据加密等 没有协议
会话层 负责建立和维护会话 没有协议
传输层 负责提供端到端的可靠传输 TCP、UDP
网络层 负责根据目标地址选择路由来传输数据 IP、ICMP、RIP、OSPF、BGP、IGMP
数据链路层 传输有地址的帧,错误检测功能 SLIP、CSLIP、PPP、ARP、RARP、MTU
物理层 以二进制数据形式在物理媒体上传输数据 ISO2110、IEEE802、IEEE802.2

TCP/IP 连接

TCP 协议可以对上层网络提供接口,使上层网络数据的传输建立在 “无差别” 的网络之上。


三次握手

第一次握手:客户端发送 syn 包 (syn=j) 到服务器,并进入 SYN_SEND 状态,等待服务器确认;

第二次握手:服务器收到 syn 包,必须确认客户的 SYN(ack=j+1),同时自己也发送一个 SYN 包(syn=k),即 SYN+ACK 包,此时服务器进入 SYN_RECV 状态;

第三次握手:客户端收到服务器的 SYN+ACK 包,向服务器发送确认包 ACK (ack=k+1),此包发送完毕,客户端和服务器进入 ESTABLISHED 状态,完成三次握手

握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP 连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。断开连接时服务器和客户端均可以主动发起断开 TCP 连接的请求,断开过程需要经过 “四次挥手”。

tcp的三次握手是很有意思的,基本思想就是“让我知道你已经知道”了。服务器监听请求,客户端发起连接请求(第一次连接),请求在路上可能存在丢失的风险,所以当请求到了服务器后如果服务器同意建立连接会给客户端一个回信(第二次连接),告诉它:我已经收到请求,可以连接。但是回信也存在一个问题,那就是回信能不能到客户端?它需要客户端给他一个回信说我已经收到批准通知了,如果客户端一直不回复的话意味着客户端没有收到批准通知。因此客户端一收到批准通知就立马回复(第三次握手):OK老铁我收到你的批准通知了。至此,三次握手结束。一个很类似的例子就是投简历:先投简历,然后对方公司会通知你通过简历筛选,你收到这个通知后一般会回复一下我知道了。这种“让我知道你已经知道了”的想法是一种约定俗成的可靠信息交互的基本方式,基于此想法构建的信息交互框架叫做协议。————摘自网友的通俗理解

断开四次挥手

四次挥手类似:
学生(客户端):老师下课铃响了,该下课了
老师(服务端):好,我知道了,我说完这点
老师(服务端):好,说完了,下课吧
学生(客户端): 谢谢老师,老师再见

另外一种解释:

释放连接的时候也是如此:客户端发起关闭连接的请求,关闭连接意味着客户端结束了自己的工作即发送数据,但此时仍然处于数据传输的过程中,服务器可能未数据传输完毕,因此当请求到服务器时服务器知道了这个请求,但服务器数据传输未完成无法关闭连接,因此服务器先发送一个ack告诉客户端关闭请求已收到,但老子正忙,一会再关,你再等一会。等服务器工作完成了,就把fin信号发送给客户端,此时服务器要等着客户端给他一个回信,让服务器知道客户端已经知道了。因此客户端收到后就给服务器一个回信,为了防止回信丢失,客户端就再等2MSL个时间,之所以是2个,是因为涉及到来回,第一个MSL中是回信在路上的最大时间,第二个MSL是万一回信没到服务端,服务端重发的FIN确认在路上的时间 ————来自网友通俗解释

为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?

这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的连接请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可能未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。