如何重现一个无声的TCP/IP连接被断开?

29

我有一个情况,一个Java程序与服务器建立了一个长时间运行的TCP/IP连接,并且该连接完全按照文档描述的方式运作,但在我的控制范围之外的环境中出现了一件事情。

每个星期六,该服务器都会重新启动,但由于某种原因,客户端没有得到正确通知,因此连接会一直挂起等待响应。这与陈旧的JDBC连接具有完全相同的行为,其中服务器和客户端之间的某个路由器发现连接空闲并在未经通知的情况下丢弃它。

我需要能够重现这种情况,以便能够创建适当的修复方案。

因此,我想知道是否有一种好的方法可以在我控制下模拟路由器静默丢弃连接的情况?

我可以在开发环境和服务器之间放置一个Linux框或Mac框。如果可以在虚拟机(vmware player)中进行断开,则可以运行JVM。

欢迎提供建议。


编辑2012-12-18:对我有用的解决方案是在本地使用基于Java的SOCKS5代理,可以随时使用Ctrl-Z暂停它,并告诉我的应用程序通过它进行。


你在客户端和服务器的套接字上使用TCP Keepalives(SO_KEEPALIVE选项)吗? - Mike Pennington
@Mike,可能不行。套接字代码在第三方库中。 - Thorbjørn Ravn Andersen
1
如果客户端无限期挂起是不可接受的,那么保持连接可能会很有用。 - Mike Pennington
1
正确的解决方法是让客户端设置TCP keepalive,如果您不介意等待两个小时,或者使用更现实的超时值调用Socket.setSoTimeout(),例如几分钟。 - user207421
@Mike,很遗憾,除非我不能更改该第三方库。 - Thorbjørn Ravn Andersen
显示剩余2条评论
5个回答

13

您可以使用iptables暂时应用规则,以拦截来自远程服务器(a.b.c.d)的所有数据包。以下是一个示例:

iptables -A INPUT -s a.b.c.d -j DROP

当你想要关闭过滤器时

iptables -D INPUT -s a.b.c.d -j DROP

你可以根据这些规则来丢弃其他特定的数据包,但我认为这将准确地模拟出如果服务器简单消失客户端软件会看到什么。

但需要注意的是,当你重新开启连接时,远程服务器可能仍然有旧的连接处于活动状态,因此这并不能完美地模拟重启。


或者在TCP连接建立后的某个时候,使用Windows防火墙阻止该连接。 - Mike Pennington
2
这对于已经建立的连接是不起作用的。 - Brice M. Dempsey

10

使用 Socat 将您的连接转发(非常容易设置为 TCP 转发器/代理),即使在同一台机器上,如果需要的话(通过引入一个新端口来操作代理并将其指向“官方”终点)。

查看简单 TCP 转发器 的示例。

然后,当您想测试故障时,可以关闭它(套接字将被关闭),或者尝试停止进程(Linux 中的 CTRL Z),以查看目标如何处理停滞的连接。

有任何问题吗?我会尽力回答...祝你好运!


1
我熟悉socat - 我使用它通过SOCKS代理进行远程桌面。 - Thorbjørn Ravn Andersen
事实证明,该场景涉及多个网络端口,使用JSocks(http://jsocks.sourceforge.net/)比socat更容易正确处理它们,因为`-DsocksProxyHost=...`系统属性透明地指示JVM使用Socks代理。我仍然使用Ctrl-Z技巧 - 效果非常好。 - Thorbjørn Ravn Andersen
啊,太酷了!谢谢分享,下次我玩连接逻辑的时候会去看看 :) - HaveAGuess
我在Windows 7上使用Java 7尝试了JSocks。它很容易使用,但是当被终止时会立即触发“SocketException:Connection reset”错误。因此,在我的情况下,静默丢弃连接并不合适。 - Emmanuel Bourg
我用socat得到了相同的结果,“连接重置”。 - Emmanuel Bourg

5

一种基于本地Linux的解决方案是使用tcnetem。Netem是一个特殊的队列,可以附加到各种网络接口上以引起延迟、重新排序和丢失(有关详细信息,请参见网页)。 netem的一些示例用法包括:

tc qdisc change dev eth0 root netem loss 0.1%

为了使eth0丢弃所有发送数据包的0.1%,并且...
tc qdisc change dev eth0 root netem loss 0.3% 25%

创建数据包丢失的突发情况:

这将导致0.3%的数据包丢失,每个后继概率取决于上一个概率的四分之一。

如果您需要删除传入的数据包,可以使用ifb(中间功能块设备)。您可以设置它,将eth0接收的所有数据包转发到ifb,并将netem附加到ifb以创建丢失或延迟。有关更多详细信息,请参阅ifb的文档。


2

拔掉计算机的网络电缆。

只测试此模块的简单测试。连接到服务器并进入等待阶段。然后,拔掉您的网络电缆。

当您运行此测试时,重要的是要隔离此模块并仅启动此模块。您的程序可能有其他需要网络访问的方面,请确保它们没有运行。


0
在Windows上,你可以运行clumsy: https://github.com/jagt/clumsy/releases,无需设置显式代理,只需将其配置为在所需的接口/端口组合上丢弃数据包。这是一个非常方便的工具。

很高兴看到有人已经开发出了这样一个好工具。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接