写在前面:
在TCP/IP协议栈中,尽管TCP协议和UDP协议都是用网络层,但是他们向应用层却提供了不同的服务。TCP提供了一种面向连接的可靠地字节流传输,而UDP协议提供的是面向无连接的,简单不可靠的信息传输。
面向连接也就意味着客户端和服务器,在交换彼此数据之前,需要建议一个TCP连接,这篇博客就将会结束如何建立和释放一个TCP连接,也就是我们说的三次握手和四次挥手。
TCP报文格式:
(1)序号:Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。
(2)确认序号:Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。
(3)标志位:共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义如下:
(A)URG:紧急指针(urgent pointer)有效。
(B)ACK:确认序号有效。
(C)PSH:接收方应该尽快将这个报文交给应用层。
(D)RST:重置连接。
(E)SYN:发起一个新连接。
(F)FIN:释放一个连接。
三次握手:
三次握手(Three Way HandShake)的过程是为了建立可靠的通信信道,确保通信双方,即发送方与接收方处于正常状态,可以建议一个TCP连接。
我们用一张图来描述三次握手的过程:
在建立TCP连接的过程中,通信双方要发送3次数据包,才能完成建立连接的过程。
第一次握手:
Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,这时Client进入SYN_SENT状态,等待Server确认。
第二次握手:
Server收到数据包后由于标志位SYN=1,知道Client请求建立连接,Server将标志位的SYN和ACK都置为1,将确认序号ack=J+1,并随机产生一个值seq=K,将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
第三次握手:
Client收到确认后,检查确认序号ack是否为J+1,标志位ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态。
这样就完成三次握手,随后Client与Server之间可以开始传输数据了。
SYN攻击:
在三次握手过程中,Server发送SYN-ACK之后,收到Client的ACK之前的TCP连接称为半连接(half-open connect),此时Server处于SYN_RCVD状态,当收到ACK后,Server转入ESTABLISHED状态。SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server回复确认包,并等待Client的确认,由于源地址是不存在的,因此,Server需要不断重发直至超时,这些伪造的SYN包将产时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络堵塞甚至系统瘫痪。SYN攻击时一种典型的DDOS攻击,检测SYN攻击的方式非常简单,即当Server上有大量半连接状态且源IP地址是随机的,则可以断定遭到SYN攻击。
四次挥手:
所谓四次挥手(Four-Way Wavehand)即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个数据包以确认连接的断开。在socket编程中,这一过程由客户端或服务端任一方执行close来触发,整个流程如下图所示:
第一次挥手:
Client发送一个标志位FIN=1,用来关闭Client到Serve的数据传送,并随机产生一个值seq=X,将该数据包发送给Server,Client进入FIN_WAIT_1状态。
第二次挥手:
Server收到标志位FIN=1,知道Client要释放连接,将标志位ACK=1,确认序号ack=X+1,并生成一个随机值seq=Z。服务器进入 CLOSE_WAIT状态。
第三次挥手:
Server发送标志位FIN=1,用来关闭Server到Client的数据传送。Server进入LAST_ACK状态。
第四次挥手:
Client收到FIN后,CLient进入TIME_WAIT状态,发送ACk报文,并发送确认序号=Y+1,Server进入CLOSED状态,完成四次挥手。
四次挥手状态:
FIN_WAIT_1状态: 表示等待对方的FIN报文。Socket处于ESTABLISHED状态,向服务器发送FIN报文,立即进入 FIN_WAIT_1状态。
CLOSE_WAIT状态:表示等待关闭。当收到客户端的FIN报文,并返回一个ACK报文后Socket进入CLOSE_WAIT状态。接下来,只需要检查自己是否还有数据要发给客户端,如果没有,就向客户端发送FIN 报文。
FIN_WAIT_2状态:表示等待对方的FIN报文。当客户端收到了服务器的ACK后,进入FIN_WAIT_2状态。这个状态还是要告诉服务器,我还有ACK报文要发送,等下再关闭连接。
LAST_ACK状态:被动关闭连接的一方,在FIN报文之后,最后等待客户端的ACK报文。当收到了ACK报文之后,别动关闭的一方就会进入了CLOSED状态。
TIME_WAIT状态:表示收到了对方的FIN报文,也向对方发送了ACK报文。只要等待2MSL后,就可回到CLOSED状态。
CLOSED状态:表示连接中断。
为什么建立连接要3次,而关闭连接要4次?
TCP协议一种面向连接的,可靠的,基于字节流的传输层协议。且TCP是全双工模式,当客户端发出FIN报文后,意味着客户端告诉服务器自己没有数据要发送了,但客户端仍然可以接受数据。然后,当服务器发送ACK报文段时,表示服务器已经知道客户端不会再发送数据了。其次,当服务器发送FIN报文时,表示服务器也没有数据要发送。
建立连接时,这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,会把ACK和SYN放在一个报文里发送给客户端。