TCP三次握手
TCP通过三次握手建立连接,随后的数据通信通过该连接进行:

装逼:一个是讨论三次握手机制意味着 TCP 创建连接非常麻烦,所以需要池化技术;另外一个是讨论为啥恰好是三次握手,而不是两次握手,也不是四次握手
TCP三次握手是指建立一个可靠的TCP连接的过程。它的主要目的是让通信双方(客户端和服务器)确认彼此的接收和发送能力,并协商一些关键参数,确保数据传输的可靠性。
最开始,服务端要启动之后,要监听某个端口。
当客户端准备连接服务端的时候,发送 SYN 报文,并且带上自己的初始化序列号(ISN),而后进入 SYN-SENT 状态。这是第一次握手。
服务端收到 SYN 报文之后,会响应一个 SYN-ACK 报文,并且带上自己的初始化序列号(ISN),而后进入 SYN-RECV 状态。这是第二次握手。
当客户端收到 SYN-ACK 报文之后,发送一个 ACK 报文,客户端进入 ESTABLISHED 状态。当服务端收到了 ACK 报文之后,进入了 ESTABLISHED 状态。这是第三次握手。
完成这三次握手之后,客户端和服务端就可以互相发送数据了。
简述
SYN,SYN-ACK,ACK
重点
三次握手的状态变迁
引导
TCP状态;
池化?
从这个过程上也可以看到,三次握手这个过程虽然可靠性很强,但是性能很差。一方面三次握手过程增加了连接建立的延迟,尤其是在网络状况不佳的情况下;另外一方面是每次建立连接都需要消耗系统资源(如文件描述符、内存等)。
所以在当下来说,基本上使用 TCP 的时候都会使用池化技术,规避 TCP 连接频繁创建和销毁的
风险。
为什么是三次握手?
当然,我们也可以从一个更加本质的角度去理解三次握手的过程。对于 TCP 连接来说,初始化的时候有两个关键的点:确认网络是连通,同步初始化序列号,即 ISN。
TCP 是一个全双工通信的协议,这就意味着服务端要确认客户端的 ISN,客户端也要确认服务端的 ISN。因此从设计上来说是四个步骤:客户端发送 SYN 和 ISN,服务端确认,服务端发送 SYN 和 ISN,客户端确认。只不过这逻辑上的第二和第三个步骤,可以合并为一个步骤,也就是服务端在确认的时候,也顺手把自己的 ISN 返回去了。
这是三次握手设计的根源。从这个角度出发,就很容易理解为什么不能是两次握手,因为两次握手只是建立了客户端到服务端的单向通信,而服务端没有收到客户端的 ACK,它并不能确定客户端能否正确处理自己发过去数据,因此服务端到客户端这一个方向上的通信并没有建立。
简述
两次握手,客户端到服务端单向通信;三次握手,客户端到服务端双向通信;
重点
为什么一定是三次握手;
第三次握手时可以发送数据吗?
可以,这个就用到了TCP Fast Open机制,即第三次握手的时候可以将数据和ack一起携带过来
当然,这要客户端和服务端都支持 TFO 机制。
排除这种机制之后,也就是如果客户端发送第三次握手,而是直接发送数据,也就是报文里面不带 ACK 标记位。这种情况下,服务端会丢弃报文,并且返回 RST 报文,关闭连接。
TCP 协议是明确要求一定要完成三次握手才能正常通信的。
简述
ACK带数据,TFO;霸王硬上弓,直接丢弃;
重点
TFO机制;没有完成握手就发送数据,会发生什么;
引导
TFO;
为什么不是四次握手?
因为三次握手已经可以确认双方的发送接收能力正常,双方都知道彼此已经准备好,而且也可以完成对双方初始序号值得确认,也就无需再第四次握手了。
这个问题要从 TCP 的全双工通信角度开始说,全双工通信也就是意味着要做到客户端能把数据发到服务端,服务端也能把数据发到客户端。
因此理论上来说,不考虑什么优化的话,就是四次握手。也就是客户端发到服务端,服务端确认,这是两次。服务端发到客户端,客户端确认,也是两次。
而后就会发现,其中服务端确认和服务端发送到客户端的两次可以合并为一次,节省一次。因此最终的成果就是三次握手就够了。
SYN 洪水攻击
- 建立连接时超时了。Client发出syn后,Server接受到了,发给SYN-ACK后但这时候Client下线了怎么办?
那么这个连接就处于一个中间状态,没成功也没失败。收不到Client的ack一段时间后在Linux下,Server默认会采用一个重试措施,默认重试次数为5次,重试的间隔时间从1s开始每次都翻售,5次的重试时间间隔为1s, 2s, 4s, 8s, 16s,总共31s,而第5次后得等32秒才能停止等待,故总共是63s,这个时候tcp才会断开
- SYN Flood攻击。基于上述情况,就有人利用这种机制,恶意攻击你,发一个syn后,客户端下线,让你的syn连接的队列耗尽(syn队列就是存放那些半连接状态的连接的)。于是,Linux下给了一个叫**tcp_syncookies**的参数来应对这个事——当SYN队列满了后,TCP会通过源地址端口、目标地址端口和时间戳打造出一个特别的Sequence Number发回去(又叫cookie),如果是攻击者则不会有响应,如果是正常连接,则会把这个 SYN Cookie发回来,然后**服务端可以通过cookie建连接(即使你不在SYN队列中)**。
- 请注意,请先千万别用tcp_syncookies来处理正常的大负载的连接的情况。因为,synccookies是**妥协版的TCP协议**,并不严谨。对于正常的请求,你应该调整三个TCP参数可供你选择,第一个是:**tcp_synack_retries** 可以用他来**减少重试次数**;第二个是:**tcp_max_syn_backlog**,可以**增大SYN连接数**;第三个是:**tcp_abort_on_overflow** **处理不过来干脆就直接拒绝连接了**。
SYN 洪泛攻击是一种 DDoS 攻击,攻击者发送大量的 SYN 包,但是并不响应服务端返回来的 SYN-
ACK包
这样造成的后果是服务端需要消耗资源维护这些半开连接,并且因为没有收到客户端的 ACK 包,所以会不断重试,进一步加重了资源消耗。
SYN 洪泛攻击抵御起来,有多种手段。
最重要的手段就是 SYN Cookie 技术,也就是服务端在收到SYN包时,不立即分配资源,而是生成一个“cookie”作为初始序列号返回给客户端。客户端在回复ACK包时,必须包含这个“cookie”,服务器验证通过后才分配资源。
还有一些治标不治本的手段,例如说增大 TCP 连接队列大小、调整 TCP/IP 协议栈参数、延缓 TCB 分配等。
当然,我个人推荐的是不要自己去搞 DDoS 防范,直接购买成熟的服务性价比最高。
简述
SYN Cookie 比较好,其余治标不治本
引导
SYN Cookie技术
最后一次握手服务端一直收不到来自客户端的ACK,会怎么样
一句话就能说清楚,服务端会重试,直到重试超出最大次数,给客户端发RST报文后,则会关闭连接。