我们先来聊一聊网络超时的概念,以及模拟网络超时对我们程序的必要性
要想了解如何模拟网络超时的情况,我们需要先了解一下
为什么会网络超时呢
简单的说:就是你向服务端发送数据请求,然尔服务器没返回数据,或返回数据太慢导致未收到返回数据。
比如,你要下载一个东东,你向服务器发送下载这个东东的请求,但等了好长时间都没有收到服务器同意你接收下载数据的请求,所以也不能一直这样等下去,你的电脑就会报告网络超时,如果不是你的网络故障,那么就是对方服务器的问题。
我们知道在TCP建立连接的时候有3次握手的规则
1. 客户端发送’SYN’给服务端
2. 服务端返回确认’SYN_ACK’给客户端
3. 客户端最终确定’ACK’
在这3次握手的时间内,每一次都有可能网络会掉包,我们分析一下每一种掉包的情况:
1. SYN丢失第一次握手客户端发送SYN掉包的情况:这种情况下,客户端发送的SYN丢失在网络中,没有得到确认,客户端的TCP会超时重发SYN。发送7个SYN后等待一个超时时间(例如:127秒),如果在这段时间内仍然没有收到ACK,则connect返回超时。
2. SYN-ACK丢失从客户端的角度来讲以前面一种情况类似。从服务端的角度来讲,由LISTEN状态进入SYN_REVD状态。服务端的TCP会重发SYN-ACK,直到超时。SYN攻击正是利用这一原理,攻击方伪造大量的SYN包发送到服务器,服务器对收到的SYN包不断回应SYN-ACK,直到超时。这会浪费服务器大量的资源,甚至导致奔溃。对服务端的应用层来讲,什么也没有发生。因为TCP只有在经过3次握手之后才回通知应用层,有新的连接到来。
3. ACK丢失这对服务端来讲与2相同。对于客户端来讲,由SYN_SENT状态进入了ESTABLISED状态,即连接成功了。连接成功后客户端就可以发送数据了。
但实际上数据是发送不到服务端的(我们假设客户端收到SYN-ACK之后,客户端与服务端之间的网络就断开了),客户端发送出去的数据得不到确认,一般重发3次左右就会处于等待ACK的状态(win7)。而ubuntu 12.10下,调用send会返回成功,直到TCP的缓冲被填满(测试环境:局域网,感觉这个不是很合理,按照书上所说:应该是使用“指数退避”进行重传 -- TCP/IP协议详解,大概是我的测试环境中有NAT所致
吧)。最终,客户端产生一个复位信号并终止连接。返回给应用程序的结果是Connection time out(errno: 110)
好,理解了3次握手掉包的情况下,我们就很容易实现模拟超时情况的发生,
我们可以在端口上控制服务端无法与客户端握手成功来让超时的情况发生
具体的实现要用到 iptables 这个命令
iptables-A OUTPUT -p tcp -m tcp --tcp-flags SYN SYN --sport 9090 -j DROP
这个命令是用来drop 掉响应SYN的返回
之前我们看到第一次客服端向服务器请求SYN的握手信息,而这个命令就是阻止服务器返回SYN_ACK的确认握手信息,这样客户端就无法收到服务端的握手确认信息了.
上面这种情况是模拟连接没有成功的情况
下面还有一种情况,就是连接已经成功了,但是在传输数据的时候,服务端没有及时返回数据,我们来看看这种情况是如何模拟的:
iptables -A OUTPUT -p tcp -m tcp --tcp-flags PSH PSH --sport 9090 -j DROP
细心的童鞋会发现,这里用到的flags 是PSH ,对,PSH的意思是控制信息是可以正常传送的,也就是说握手是正常成功的,然后传输数据的时候,我们限制了服务器无法给客户端传送数据内容,这样就模拟了连接是成功的,但是无法正常读取到服务端的数据的超时情况了
上面说的是最简单手动设置超时的方式,当然还有神器可以使用,接着就献上这款神器名叫netem,地址在
http://www.linuxfoundation.org/collaborate/workgroups/networking/netem
Network Emulation 有兴趣的童鞋可以前往研究。
Gerry
文章转自于小张网校博客
http://www.xiaozhangwx.com/blog/archives/73
阅读原文