首先要明白TCP中的SYN和ACK是什么
SYN:同步标志 同步序列编号(Synchronize Sequence Numbers)栏有效。该标志仅在三次握手建立TCP连接时有效。它提示TCP连接的服务端检查序列编号,该序列编号为TCP连接初始端(一般是客户端)的初始序列编号。其实就是客户端的初始序列编号。
ACK:确认标志 确认编号(Acknowledgement Number)栏有效。大多数情况下该标志位是置位的。TCP报头内的确认编号栏内包含的确认编号(w+1,Figure-1)为下一个预期的序列编号,同时提示远端系统已经成功接收所有数据。
所谓的tcp三次握手其实就是建立Tcp连接。刚开始客户端处于Closed状态,服务器端处于Listen状态。
三次握手:
(1)第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。
(2)第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
(3)第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。
图解:
为什么需要采取三次握手,两次不行吗?
采用三次握手的目的其实就是确认客户端和服务端的发送能力和接收能力是否正常,
第一次握手由客户端向服务器发包,服务器收到。能确定客户端的发送能力是正常的服务端的接收能力是正常的。
第二次握手由服务端向客户端发包,客户端收到。能确定服务器发送能力正常,但如果没有第三次握手服务器就不能确定客户端的接收能力是否正常(因为客户端没反馈)。
采用三次握手其实就是客户端确定服务端的发包接收能力都正常,服务器确定客户端的发包接收能力都正常。
如果两次握手会产生什么问题:
如果客户端发送连接请求,由于网络原因连接请求报文丢失,于是客户端再次发送连接请求。后来收到了服务端确认建立连接。数据传输完毕之后,就释放了连接。等到网络环境好了,上一个请求连接到达服务器如果不采用第三次握手,直接建立连接,客户端也不会向服务器发送数据,服务器一直等待客户端发送数据,浪费资源。(再多的线程终究会用完)。
什么是半连接状态:
服务器第一次收到客户端SYN之后,就会处于SYN_RCVD状态,此时双方还没有完全建立连接,服务器就会把此种状态下请求连接放在一个队列里,我们把这种队列称为半连接队列。
当然还有一个全连接队列,就是已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了就有可能出现丢包现象。
关于SYN_ACK重传:
就是如果服务器发送SYN_ACK包,如果未收到客户端确认包,服务器就会重传,如果重传次数大于系统规定的最大次数,系统将该连接信息从半连接队列中删除。
三次握手可以携带数据吗?
第一次第二次不可以,第三次可以。
如果有人要恶意攻击服务器的话,他每次在第一次握手中的SYN报文中放入大量数据,然后重复发送这样的数据,就会让我们的服务器花费大量时间,内存来接受这些报文。
而对于第三次握手这时客户端已经处于ESTABLISHED(established)对客户端来说已经建立了连接,并知道服务器的接受、发送能力正常,因此可以携带数据。
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攻击了,使用如下命令可以让之现行:
#netstat -nap | grep SYN_RECV
四次挥手:
(1)第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
(2)第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
(3)第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
(4)第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。