切换主题
三次握手
握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。
第一次握手
客户端发送syn
包(seq=x
)到服务器,并进入SYN_SEND
状态,等待服务器确认;
第二次握手
服务器收到syn
包,必须确认客户的SYN
(ack=x+1
),同时自己也发送一个SYN
包(seq=y
),此时服务器进入SYN_RECV
状态;
第三次握手(可携带数据)
客户端收到服务器的SYN
包与ACK
包后,向其发送确认包ACK
(ack=y+1
),此包发送完毕,客户端和服务器进入ESTABLISHED
状态,完成三次握手。
三次握手全过程图示:
null
咦?为什么第三次握手可以携带数据?前两次握手也行吗
因为对第三次握手而言,此时的客户端已经处于
ESTABLISHED
状态,已经建立起连接了,自然可以携带数据。而前两次握手则不能,因为在此时携带数据会让服务器容易受到SYN
攻击。
什么又是SYN
攻击?
由于服务器端的资源分配是在二次握手时分配的,而客户端的资源是在完成三次握手时分配的,所以服务器容易受到
SYN
洪泛攻击。所谓的SYN
洪泛攻击就是客户端在短时间内伪造大量不存在的IP
地址,并向服务器不断发送SYN
,服务器回复确认包并等待客户端确认,由于IP
地址不存在,服务器会不断重发至超时,这些伪造的SYN
包将长时间占用未连接队列,导致正常的SYN
请求因为队满而被丢弃,从而引起网络拥塞甚至系统瘫痪。
灵魂问题:为什么是三次握手?两次不行?四次不行?
从通信问题的本质来讲,要在不可靠的信道中想要模拟出可靠的双向传输,最少也得是三次通信,两次只能建立可靠的单向传输。
举俩例子来讲讲为什么最少要三次通信?
=> 第一次握手失败:若某个时间点,客户端向服务端发起了SYN=1, seq=x
第一次握手,由于网络原因滞留到了连接关闭后才到达服务器, 此时服务器将此(已过期)请求视为客户端正常发出的新请求处理,并发出ACK=1, ack=x+1, SYN=1, seq=y
应答,同意建立连接:
- 若只有二次握手,此时连接建立,但实际上客户端并没有发出请求,会忽略第二次握手的应答,但服务器不知并一直等待客户端发来数据,至此无效的连接增加了服务器开销,浪费资源;
- 若还有第三次握手,此时的服务器处于等待客户端确认状态,由于客户端并没有发起此连接请求(已过期),故不会确认,那么服务器也不会收到确认请求,就不会建立连接。
=> 第二次握手失败:客户端第一次握手请求正常到达服务器,第二次握手服务器发出ACK=1, ack=x+1, SYN=1, seq=y
应答,但由于网络原因,此应答丢失:
- 若只有二次握手,此时连接建立,客户端却并没有收到次应答,同时服务器也不知道客户端收到应答与否, 便一直将端口开着(此无效的连接增加服务器开销,浪费资源)。直到客户端因超时重新发出请求时,服务器就重新开启一个端口连接;
- 若还有第三次握手,通过此次握手告诉服务端,客户端有没有收到服务器第二次握手时传过去的数据,避免服务器浪费资源。