三次握手
三次握手(Three-way Handshake)的目的是连接服务器端口,建立TCP连接,并同步连接双方的序列号和确认号,同时交换TCP窗口大小信息。在socket编程中,客户端执行connect()时触发3次握手
①客户端发送一个SYN标记位为1的TCP报文,表示“请求建立新连接“,还包含客户端打算连接的服务器的端口,以及初始序号Seq=X;随后客户端进入SYN-SENT阶段。
②服务器端收到来自客户端的TCP报文后,结束LISTEN阶段。服务器端返回一段TCP报文,其中SYN和ACK标记为为1,通知客户端,服务器接收到了客户端的数据并同意创建新连接。这段TCP报文的序号Seq=Y,确认号Ack=X+1;随后服务器进入SYN-RCVD阶段。
标志位ACK和确认号Ack是不同的
③客户端收到服务器的TCP报文后,明确客户端和服务端之间的数据传输是正常的,结束SYN-SENT阶段,并返回最后一段TCP报文。
这段TCP报文中,标志位ACK为1,表示知道服务器收到了自己发送的数据;序号Seq=X+1,表示收到服务器端的确认号ACK,并将其作为自己的序号;确认号Ack=Y+1;随后客户端进入ESTABLISHED阶段。
服务器端收到这段报文后,结束SYN-SENT阶段,进入ESTABLISHED阶段。
在客户端与服务器端传输的 TCP 报文中,双方的确认号 Ack 和序号 Seq 的值,都是在彼此 Ack 和 Seq 值的基础上进行计算的,这样做保证了 TCP 报文传输的连贯性。
SYN攻击
在三次握手过程中,服务器发送SYN-ACK之后,收到客户端的ACK之前的TCP连接称为半连接(half-open connect).此时服务器处于Syn_RECV状态.当收到ACK后,服务器转入ESTABLISHED状态。
Syn攻击就是在短时间内伪造大量不存在的IP地址,向服务器不断地发送syn包,服务器回复确认包,并等待客户的确认,由于源地址是不存在的,服务器需要不断的重发直 至超时,这些伪造的SYN包将长时间占用未连接队列,正常的SYN请求被丢弃,目标系统运行缓慢,严重者引起网络堵塞甚至系统瘫痪。
Syn攻击是一个典型的DDOS攻击。检测SYN攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次SYN攻击.
在Linux下可以如下命令检测是否被Syn攻击netstat -n -p TCP | grep SYN_RECV一般较新的TCP/IP协议栈都对这一过程进行修正来防范Syn攻击,修改tcp协议实现。主要方法有SynAttackProtect保护机制、SYN cookies技术、增加最大半连接和缩短超时时间等.但是不能完全防范syn攻击。
四次挥手
客户端和服务器端都可以发起挥手动作,在socket编程中,任何一方执行close()操作将触发挥手动作。
①假设是客户端想释放连接,那么客户端会向服务器端发送一段TCP报文,标志位FIN为1,表示请求释放连接,序号Seq=U;随后客户端进入FIN-WAIT-1阶段,即半关闭阶段,并停止向服务器端发送数据,但是可以继续接收来自服务器端的数据。
注意:这里不发送的是正常连接时传输的数据(非确认报文),而不是一切数据,所以客户端仍然能发送 ACK 确认报文。
②服务器端接收到TCP报文后,进入CLOSE-WAIT阶段(半关闭阶段),并返回一段TCP报文。
报文中标记为ACK为1,表示“接收到客户端发送的释放连接的请求“;序号Seq=V,确认号Ack=U+1;随后服务器端准备释放服务器端到客户端方向的连接。
客户端收到TCP报文后,确认服务器收到了自己发出的释放连接的请求,随后客户端进入FIN-WAIT-2阶段。
前两次挥手让服务器知道了客户端想要释放连接,客户端也知道服务器接收到了自己的请求,所以可以确认关闭客户端到服务器端方向的连接了。
③服务器端可以释放服务器端到客户端方向的连接后,向客户端发出一段TCP报文。报文的标记位FIN、ACK为1,表示服务器准备释放连接;序号Seq=W,确认号Ack=U+1,表示是在收到客户端报文的基础上断开连接的。
随后服务器端进入LAST-ACK阶段,停止发送数据给客户端,但服务器端仍能收到客户端发送的数据。
④客户端收到TCP报文后,确认服务器准备释放连接;客户端进入TIME-WAIT阶段,并向服务器端发送一段报文。
报文的标记位ACK为1,表明接受到服务器准备释放连接的通知;序号Seq=U+1,表明是在收到服务器端报文的基础上,将其确认号Ack值作为本段报文序号的值;确认号Ack=W+1;随后客户端在TIME-WAIT阶段等待2MSL。
服务器端收到客户端的TCP报文后,结束LAST-ACK阶段,进入CLOSED阶段,正式关闭服务器端到客户端方向的连接。
客户端等待完2MSL后,结束TIME-WAIT阶段,进入CLOSED阶段,由此完成“四次挥手”
MSL:Maximum Segment Lifetime,报文最大生存时间,也就是报文被丢弃前在网络内的最长时间。
三次握手、四次挥手过程中,客户端和服务器端TCP的状态变化
等待2MSL的原因
①服务器端在1MSL内没有收到客户端发出的ACK确认报文,就会再次向客户端发出FIN报文:
- 如果客户端在 2MSL 内,再次收到了来自服务器端的 FIN 报文,说明服务器端由于各种原因没有接收到客户端发出的 ACK 确认报文。客户端再次向服务器端发出 ACK 确认报文,计时器重置,重新开始 2MSL 的计时。
- 否则客户端在 2MSL 内没有再次收到来自服务器端的 FIN 报文,说明服务器端正常接收了 ACK 确认报文,客户端可以进入 CLOSED 阶段,完成“四次挥手”。
②假设在12.106.32.254的1500端口和206.168.1.112.219的21端口之间有一个TCP连接。我们关闭这个链接,过一段时间后在 相同的IP地址和端口建立另一个连接。后一个链接成为前一个的化身。因为它们的IP地址和端口号都相同。
TCP必须防止来自某一个连接的老的重复分组在连接已经终止后再现,从而被误解成属于同一链接的某一个某一个新的化身。为做到这一点,TCP将不给处于TIME_WAIT状态的链接发起新的化身。既然 TIME_WAIT状态的持续时间是MSL的2倍,这就足以让某个方向上的分组最多存活1 MSL即被丢弃,另一个方向上的应答最多存活1 MSL秒也被丢弃。 通过实施这个规则,我们就能保证每成功建立一个TCP连接时。来自该链接先前化身的重复分组都已经在网络中消逝了。
为什么不能用两次握手进行连接
把三次握手改成仅需要两次握手,死锁是可能发生的。
作为例子,考虑计算机S和C之间的通信,假定C给S发送一个连接请求分组,S收到了这个分组,并发 送了确认应答分组。按照两次握手的协定,S认为连接已经成功地建立了,可以开始发送数据分组。
可是,C在S的应答分组在传输中被丢失的情况下,将不知道S 是否已准备好,不知道S建立什么样的序列号,C甚至怀疑S是否收到自己的连接请求分组。在这种情况下,C认为连接还未建立成功,将忽略S发来的任何数据分组,只等待连接确认应答分组。而S在发出的数据分组超时后,重复发送同样的数据分组。这样就形成了死锁。
参考https://network.51cto.com/art/202001/609110.htm
https://blog.csdn.net/whuslei/article/details/6667471/
https://www.cnblogs.com/zmlctt/p/3690998.html