最近在设置http请求超时setReadTimeout和setConnectTimeout,其中ReadTimeout很好模拟,ConnectTimeout模拟有点麻烦。
HTTP协议是建立在TCP协议基础之上的,HTTP会通过TCP建立连接。
TCP协议通过三次握手来建立连接。
TCP建立连接的时候有3次握手:
客户端:发送数据包SYN给服务端
服务端:回复客户端的提问ACK,并且也发送一个数据包SYN给客户端
客户端:回复服务端的提问ACK
这个过程,类似我们在信号不好的时候打电话的过程:
客户端:喂,能听到我说话吗
服务端:我能听到,你能听到我说话吗
客户端:能听到
![](https://img-blog.csdnimg.cn/img_convert/56f4c687451e58ad86ad9c53ad81dca9.png)
在这3次握手的时间内。每一次都有可能网络会掉包,我们分析一下每一种掉包的情况:
1、第一次握手,客户端发送SYN掉包的情况:
这样的情况下。client发送的SYN丢失在网络中,没有得到确认。client的TCP会超时重发SYN。
发送7个SYN后等待一个超时时间(比如:127秒)。假设在这段时间内仍然没有收到ACK,则连接connect返回超时。
2、第二次握手,SYN-ACK丢失的情况:
从服务端的角度来讲,由LISTEN状态进入SYN_REVD状态。服务端的TCP会重发SYN-ACK,直到超时。
SYN攻击正是利用这一原理。攻击方伪造大量的SYN包发送到server,server对收到的SYN包不断回应SYN-ACK,直到超时。这会浪费server大量的资源,甚至导致奔溃。
对服务端的应用层来讲。什么也没有发生。由于TCP仅仅有在经过3次握手之后才回通知应用层,有新的连接到来。
3、第三次握手,客户端发送ACK丢失的情况。
对于client来讲,由SYN_SENT状态进入了ESTABLISED状态,即连接成功了。连接成功后client就能够发送数据了。
好,理解了3次握手掉包的情况下,我们就非常容易实现模拟超时情况的发生。
我们能够在端口上控制服务端无法与client握手成功来让超时的情况发生
详细的实现要用到 防火墙 这个命令
2个握手标识SYN,ACK,2个挥手标识FIN,RST
模拟ConnectTimeout连接超时
## 先开放8080端口
firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -p tcp --dport 8080 -j ACCEPT
##禁止挥手标识的输出流量,发现正常访问
firewall-cmd --permanent --direct --add-rule ipv4 filter OUTPUT 0 -p tcp --sport 8080 --tcp-flags FIN FIN -j DROP
##禁止握手标志SYN的输出流量,发现已经不能正常访问
firewall-cmd --permanent --direct --add-rule ipv4 filter OUTPUT 0 -p tcp --sport 8080 --tcp-flags SYN SYN -j DROP
这个命令是用来drop 掉响应SYN的返回
第一次握手是客户端向server请求SYN的握手信息。而这个命令就是阻止server返回SYN_ACK的确认握手信息,这样client就无法收到服务端的握手确认信息了.
上面这样的情况是模拟连接没有成功的情况
以下另一种情况。就是连接已经成功了,可是在数据传输的时候,服务端没有及时返回数据,我们来看看这样的情况是怎样模拟的:
模拟ReadTimeout、SO_TIMEOUT 读超时
## 先开放8080端口
firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -p tcp --dport 8080 -j ACCEPT
## 禁止数据传输
firewall-cmd --permanent --direct --add-rule ipv4 filter OUTPUT 0 -p tcp --sport 8080 --tcp-flags PSH PSH -j DROP
这里用到的flags 是PSH ,对。PSH的意思是控制信息是能够正常传送的,也就是说握手是正常成功的,然后数据传输的时候,我们限制了server无法给client传送数据内容,这样就模拟了连接是成功的。可是无法正常读取到服务端的数据的超时情况了