三次握手
什么是TCP协议?
- tcp是面向连接的、可靠的、基于字节流的通信协议
- 面向连接:发送数据之前先建立连接的通信方式
- 可靠的:无论网络中发生怎样的链路变化,TCP都可以保证一个报文能到达接收端
- 基于字节流:程序中所有数据都以流的形式储传输或保存,tcp是使用字节为基本单位的流格式进行传输的。tcp会把大的用户消息分割成小的tcp报文,进行分组传输。
- 基于这三点,他保证tcp传输的是无损坏、有序的、无间隔和非冗余的数据
TCP连接
- Tcp连接维护了某些状态信息,用来保证可靠性和流量控制,这些信息的组合,就是tcp连接。这些信息包括
- socket
- 窗口大小
- 序列号
三次握手
- TCP报文结构
序列号:在建立时有系统随机生成的随机数作初始值,通过syn包传给接收端主机,每发送一次数据,就累计一次数据字节数大小。用来解决网络乱序问题
确认应答号:指下一次期望收到的数据号(序列号+1),发送端收到这个确认应答以后认为这个序号以前的数据都被正常接收。用来解决丢包问题
控制位:
- ACK:改位为1时,确认应答的字段变为有效,TCP规定除了最初建立连接时的syn包之外时,改位必须设为1
- RST:该位为1时,表示TCP连接中出现异常必须强制断开连接
- SYN:该位为1时,表示希望建立连接,并在其序列号的字段进行序列号初始值的设定
- FIN: 该位为1时,表示之后不再发送数据,希望断开连接
过程
- 一开始,服务端和客户端处于关闭状态,先是服务端会监听某个接口
- 客户端会生成一个随机初始化序号,将这个字段置于首部的【序列号】字段中,同时把syn控制位置为1,表明想要建立一个连接。该报文包含数据
- 服务端接收到客户端的syn报文后,首先也会初始化自己的一个序列号,填到tcp首部的的序列字段中。其次把tcp首都的确认应答好填入 syn_num + 1 ,接着吧syn和ack都置为1。最后把报文发送给客户端。该报文也不包含数据
- 客户端接收到服务端报文后,还要向服务端发送一个应答报文,ack标志位设为1,确认应答号是上次收到的应答号+1。最后把报文发送给服务端。这第三次握手是可以携带数据的,前两次握手不可以携带数据
注意:第三次握手之后才可以建立连接,第三次握手可以携带数据,前两次不可以
- 服务端收到确认应答报文后,进入连接状态,客户端和服务端就可以互发数据了
为什么是三次握手
只有三次握手才能保证服务端和客户端双方都有接收和发送的能力
- 避免历史连接(防止旧的重复连接初始化造成混乱)
- 客户端连续发送多次syn建立连接的报文。如果客户端第一次握手发送一个建立连接的请求a,然后因为网络阻塞等原因没有被服务端接收到,这时候客户端又重新发送了一个请求b
- 然后呢在b发出去后,报文a比b先到,而这时候服务端会发送一个a的应答报文,但是客户端在接收到a的应答报文之后会判断根据上下文判断这是一个历史连接(过期或超时),客户端就会发送rst报文,表示中断这个连接
- 但是这是在没有成功连接之前(三次握手),发送断开连接请求
- 而如果是两次连接呢?
- 在服务端会在第一次收到syn请求报文的时候就建立连接,它不会知道这是一个历史连接,当然也可以根据应答报文中断连接,这就浪费了资源
- 同步双方初始序列号
- TCP协议的通信双方,都必须维护一个序列号,它的作用是
- 去除重复数据
- 接收方根据序号按序接收
- 可以表示发送的数据包中,那些已经被对方接收(通过应答报文的确认应答号)
- 序列号在tcp连接中起到很重要的作用,所以当客户端发送携带
初始序列号
的syn报文时,才会需要服务端回一个ack应答报文(就是期望下一次的序列号 = syn的序列号+1),表示客户端接收syn报文成功。然后客户端依旧需要根据这个ack报文回复一个ack报文,一来一回,同步双方的初始序列号 - 四次握手其实也能同步双方的序列号,就是在第二次握手的时候发送一次ack报文,又发送一次syn报文,但是这两次可以被合并成一次
- 避免资源浪费
- 如果网络阻塞导致客户端发送了多个syn请求建立多个连接的报文,只有两次报文的话,就会建立多个冗余无效的连接,会重复分配资源
四次挥手
- 客户端打算关闭连接时,会发送一个fin报文,表示自己要关闭连接了,这时候客户端进入了fin_wait1状态
- 服务端接收到了fin报文,恢复一个ack报文,表示自己知道了,服务器也进入了close_wait状态
- 客户端收到了ack报文之后,会进入fine-wait2状态,这时候客户端到服务器的连接会释放
- 然后服务端在处理完数据后,也打算断开连接,会发送一个fin报文给客户端,之后服务器进入last_ack状态
客户端收到了fin报文后,会发送一个ack报文,自身进行time_wait状态,等待2MSL(报文可以存在的最长时间)之后断开连接,进入close状态,至此到服务端的连接断开
- 然后服务端收到了ack报文,进入close状态,至此到客户端的连接断开