三次握手的过程
注意不要遗漏全双工下两缓存(读/写缓存)的分配和变量的分配。
CLOSED:表示初始状态。
LISTEN:该状态表示服务器端的某个SOCKET处于监听状态,可以接受连接。
SYN_SENT:这个状态与SYN_RCVD遥相呼应,当客户端SOCKET执行CONNECT连接时,它首先发送SYN报文,随即进入到了SYN_SENT状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT状态表示客户端已发送SYN报文。
SYN_RCVD: 该状态表示接收到SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂。此种状态时,当收到客户端的ACK报文后,会进入到ESTABLISHED状态。
ESTABLISHED:表示连接已经建立。
为什么不可以是两次握手?
为了确保链路的可靠性,两次握手的过程并不能确保链路以及可靠的建立。
这时因为C端和S端并不是一方发送之后就可以确认自己可以正常发送,它们之间隔着网络环境,真正能够确认自端可以正常发送需要依靠对端返回的确认,即ACK。
下面具体分析三次握手过程中通信双端的确认状态,?
表示未知,✔
表示可以确定没有问题:
第一次握手:
客户端: 自己 【发送 ?| 接收 ?】 对端【发送 ?| 接收 ?】
服务端: 自己 【发送 ?| 接收 ✔】 对端【发送 ✔| 接收 ?】
第二次握手:
客户端: 自己 【发送 ✔| 接收 ✔】 对端【发送 ✔| 接收 ✔】
服务端: 自己 【发送 ?| 接收 ✔】 对端【发送 ✔| 接收 ?】
第三次握手
客户端: 自己 【发送 ✔| 接收 ✔】 对端【发送 ✔| 接收 ✔】
服务端: 自己 【发送 ✔| 接收 ✔】 对端【发送 ✔| 接收 ✔】
【例子】
当client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。
本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。
假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。
由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。
采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。
为什么不是四次握手?
没有必要,四次也可以但是会产生性能消耗上的增加,即冗余。
SYN洪范攻击
SYN Flood是一种非常危险而常见的DoS攻击方式。到目前为止,能够有效防范SYN Flood攻击的手段并不多,SYN Cookie就是其中最著名的一种。
SYN Cookie是对TCP服务器端的三次握手协议作一些修改,专门用来防范SYN Flood攻击的一种手段。它的原理是,在TCP服务器收到TCP SYN包并返回TCP SYN+ACK包时,不分配一个专门的数据区(缓存及相关变量),而是根据这个SYN包计算出一个cookie值。在收到TCP ACK包时,TCP服务器再根据那个cookie值检查这个TCP ACK包的合法性。如果合法,再分配专门的数据区(缓存及相关变量)进行处理未来的TCP连接。