Skip to content
本页目录

三次握手

握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。

第一次握手

客户端发送syn包(seq=x)到服务器,并进入SYN_SEND状态,等待服务器确认;

第二次握手

服务器收到syn包,必须确认客户的SYNack=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应答,但由于网络原因,此应答丢失

  • 若只有二次握手,此时连接建立,客户端却并没有收到次应答,同时服务器也不知道客户端收到应答与否, 便一直将端口开着(此无效的连接增加服务器开销,浪费资源)。直到客户端因超时重新发出请求时,服务器就重新开启一个端口连接;
  • 若还有第三次握手,通过此次握手告诉服务端,客户端有没有收到服务器第二次握手时传过去的数据,避免服务器浪费资源。