3

我有一个用 java 编写的应用程序,它需要找到网络上所有可访问的主机。

我用InetAddress.isReachable()2000 毫秒的超时来执行此操作。

我查找当前本地机器的 IP 地址,并据此尝试访问以 1-255 结尾的其他 IP 地址,而丢失了本地机器的 IP 地址。

这一切都工作正常单线程,只是需要很长时间,因为大多数 IP 地址不存在,因为它们不存在,所以用完 2 秒超时。

为了加快速度(并在行动中尝试并发性 :: Brian Goetz),我尝试使用FutureCallable

这一切也很顺利。

但是我想用ExecutorCompletionService它来给我的用户一个响应速度更快的应用程序,这样他们就可以看到结果,因为他们可以使用

Future<Reach> reachedFuture = completionService.take();

在具有以下配置的单处理器机器上运行此程序会导致四个可访问主机中的一个被识别:

private static final int poolSize = 10;
private static final int maxPoolSize = 10;
private static final long keepAliveTime = 120;

private static final LinkedBlockingQueue<Runnable> queue
        = new LinkedBlockingQueue<Runnable>(20);

private static final ExecutorService executorService
        = new ThreadPoolExecutor(poolSize, maxPoolSize, keepAliveTime, TimeUnit.SECONDS, queue);

private static final CompletionService<Reach> completionService
        = new ExecutorCompletionService<Reach>(executorService);

在四核机器上将其更改为这样也使其无法检测到所有可访问的主机:

private static final int poolSize
        = Math.max(2,Runtime.getRuntime().availableProcessors());

private static final int maxPoolSize
        = Math.max(2,Runtime.getRuntime().availableProcessors());

通过将InetAddress.isReachable()超时更改为 10 秒,使最后一个配置正常工作。

此外,通过在四核机器上按如下方式更改配置,也使其在 2 秒超时下工作:

private static final int poolSize = 2;
private static final int maxPoolSize = 2;

我是否遗漏了一些非常明显的东西,为什么会发生这种情况?

是什么阻止InetAddress.isReachable(2000)了检测我网络上所有可访问的主机?

为什么尝试运行多个InetAddress.isReachable()调用会失败?

4

1 回答 1

1

所以我在我的 Mac 上写了一个小测试脚本,我不能让它失败——不管池的大小。我确实将其更改LinkedBlockingQueue为无限制,否则我无法提交所有工作。此外,过了一段时间,该isReachable()方法抛出了一个ConnectException,所以我必须专门处理它。这是您的代码@user423199 的问题吗?

这是代码:

http://pastie.org/2460991

我想知道你在什么操作系统上运行它?某些 IP 堆栈可能不喜欢多个线程在同一进程中执行 ICMP 数据包。我原以为所有现代操作系统都会对此很聪明,但这可能是一个潜在问题。它也可能是 Java JRE 和操作系统堆栈之间的一些错误。

希望这可以帮助。

于 2011-08-31T17:23:51.940 回答