TCP协议三次握手和四次握手
前言
先说一下ip协议和tcp协议,ip协议是无连接的通信协议,ip不会占用两个设备之间通信的线路,ip实际上主要负责将每个数据包路由至目的地,但是ip协议并没有能够确保数据包是否到达,传过去的数据包是否按照顺序排列,所以ip数据包是不可靠的。而解决数据不可靠的问题就是由tcp协议来完成,接下来就介绍tcp协议,是如何让这些数据可靠的。
tcp概念
tcp(transmission control protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,前面的博客有介绍,在简化的计算机网络osi模型中,它完成第四层传输层所指定的功能,用户数据报协议(udp)是同一层内另一个重要的传输协议。数据传输时,应用程序向tcp层发送数据流,tcp就会将接受到的数据流切分成报文段(会根据当前网络环境来调整报文段的大小),然后经过下面的层层传递,最终传递给目标节点的tcp层。为了防止丢包,tcp协议会在数据包上标有序号,对方收到则发送ack确认,未收到则重传。这个步骤就是我们通常所说的tcp建立连接的三次握手。同时tcp会通过奇偶校验和的方式来校验数据传输过程中是否出现错误。下面来详细介绍三次握手的过程。
tcp报文中的6个标志位
先来简单介绍一下tcp报文
在这里主要介绍一下那6个标志位
urg:紧急指针标志,当为1时表示紧急指针有效,为0则忽略紧急指针
ack:确认序号标志,为1表示确认号有效,为0表示报文中不含有确认信息,确认号无效
psh:push标志,当为1时就是让接收方收到该tcp报文的时候不进入缓冲区排队而是快速发给应用程序
rst:重置连接标志,当连接出现错误时可以重置,或者用于拒绝非法的报文段和连接请求
syn:同步序号,用于建立连接过程
fin:finish标志,用于释放连接
tcp建立连接的三次握手
下面是示意图:
(注:seq代表序号,ack代表确认号)
第一次握手:当客户端需要去建立连接时,客户端就会发送syn包(seq=x)到服务器,然后客户端进入syn_send的状态,代表已经发syn包过去,并且在等待服务器确认。此时ack=0,syn=1.,这时候由于才第一次握手,所以没有ack标志
第二次握手:服务器收到syn包,就会进行确认,由上面的标志位介绍我们可以知道syn是表示同步序号,这时候会使得确认号=序号+1,即ack就会等于x+1,然后服务器也会像客户端发送一个syn包(seq=y),这时候也就是服务器会发送syn+ack包,来表示服务器确认到了客户端的一次握手并且二次握手建立,此时服务器进入syn_recv状态。此时syn=1,ack=1,这时候由于是第二次握手,所以就会有一个服务器给客户端的确认标志。
第三次握手:客户端收到服务器的syn+ack包,然后就会像服务器发送确认包ack(ack=k+1)和syn(seq=x+1),等到这个包发送完毕之后客户端和服务器就会进入established状态,完成三次握手,而后就可以在服务端和客户端之间传输数据。此时syn标志位已经不需要,因为当我们发送ack标志位的时候代表三次握手成功,已经建立完连接了,接下来可以传送数据过去了。
既然都有syn包那为什么还要ack来确认呢?syn是同步序号,当 syn=1 而ack=0 时,表明这是一个连接请求报文。对*同意建立连接,则应在响应报文中使 syn=1 和 ack=1。因此syn置1就表示这是一个连接请求或连接接受报文。而ack状态是用来确认是否同意连接。也就是传了 syn,证明发送方到接收方的通道没有问题,但是接收方到发送方的通道还需要 ack 信号来进行验证。
当tcp三次握手完之后,就代表连接已经建立完成,那么连接断开又是怎么样的呢?
tcp四次握手
当在传送完数据之后,客户端会和服务端之间有四次握手
第一次握手:客户端发送一个fin和序号过去(seq=u),用来表示客户端和服务端之间有关闭的请求,同时关闭客户端到服务端的数据传送,客户端就进入fin_wait_1的状态。
第二次握手:服务端收到fin=1的标志位时,就会发送一个ack标志位代表确认,然后确认序号就变成了收到的序号加1,即ack=u+1(fin和syn在这点上相同,但是作用不一样)这时候服务端进入close_wait状态,这是一个半关闭状态。只能服务端给客户端发送数据而客户端不能给服务端发送数据。
第三次握手:这次握手还是由服务端发起,这是服务端在传完最后的数据(没有就不传)就会发送一个fin=1和ack=1,且序号seq会改变(没有传数据则不变),而ack不变。这时候服务端就会进入last_ack状态,表示最后确认一次。
第四次握手:客户端在接收到fin之后,就会进入time_wait状态,接着就发送一个ack和seq=u+1,ack=w+1给服务端,这时候服务端就会进入closed状态。而客户端进入time_wait状态的时候必须要等待2msl的时间才会关闭
为什么会有time_wait状态呢?(msl:网络中数据报文存在的最大时间)
1、time_wait状态可以确保有足够的时间让对方接收到ack包,如果ack没有到达,在传输的过程丢失了或者一些其他原因,这样就可以让客户端重发ack包。如果客户端直接关闭了,那么就有可能导致服务端在一些情况下没有接收到ack包而无法与客户端断开连接。这样客户端发送ack包到服务端,服务端请求重发,一来一回就正好是2msl
2、保证迟来的tcp报文段有足够的时间被识别并丢弃,linux 中一个tcpport不能打开两次或两次以上。当client处于time_wait状态时我们将无法使用此port建立新连接,假设不存在time_wait状态,新连接可能会收到旧连接的数据。
服务器出现大量colse_wait状态的原因?这时候很可能是因为程序中在收到fin=1的tcp报文后,由于忙于读或者写,没有去及时发送fin回来,也就是无法及时关闭连接。这时候需要着重检查释放资源的代码和处理请求的线程配置,有可能是代码中有资源没有被释放掉,也有可能是线程池中的线程数不合理等等
上一篇: 如何提高河南特种水产养殖效益呢?