经过上面繁杂的介绍,那么我们来一步步分析一下“三次握手”的过程:
1、服务端处于LISTEN状态,客户端处于CLOSED状态;
2、客户端打开,并进行SYN的发送,处于SYN_SENT状态;
3、服务端收到此条消息后,转为SYN_RCVD状态,并对客户端进行消息回复;
4、客户端收到此条消息后,转为ESTABLISHED状态,并发送一个ACK的确认消息。
5、服务端收到此条消息后,转为ESTABLISHED状态。
至此,三次握手完成。
然而,聪明的你,通过上面的分析,你可能会得到这样的结论:accept()发生在第3步,原因是,此时accept()函数需要给此次连接分配资源。的确,最初是想这样设计的。但是,设想一个情景,若有10000个客户端都和该服务端进行连接,发送SYN,服务端收到之后,这些客户端却不再理会服务端的回复,然而此时服务端的资源却都用accept()分配了。这就是所谓的“DDOS攻击”。
为了解决这个问题,accept()于是被放在三次握手之后。
当然,这样也不能保证不能被攻击,当然这是后话。
第一次握手:客户端发送syn包(syn=j)到服务器。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个ASK包(ask=k)。
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1)。
三次握手完成后,客户端和服务器就建立了tcp连接。这时可以调用accept函数获得此连接。