延迟从Java到同一台计算机的多个TCP连接

rip*_*234 9 java tcp http

(在ServerFault中查看此问题)

我有一个Java客户端,它使用Socket打开到同一台机器的并发连接.我正在目睹一种请求完成速度非常快的现象,但其他请求的延迟时间为100-3000毫秒.使用Wireshark进行数据包检查会在离开客户端之前显示所有SYN数据包超出第一个等待很长时间.我在Windows和Linux客户端都看到了这一点.可能是什么导致了这个?当客户端是Windows 2008或Linux机器时,会发生这种情况.

附加代码:

import java.util.*;
import java.net.*;

public class Tester {
    public static void main(String[] args) throws Exception {
        if (args.length < 3) {
            usage();
            return;
        }
        final int n = Integer.parseInt(args[0]);
        final String ip = args[1];
        final int port = Integer.parseInt(args[2]);

        ExecutorService executor = Executors.newFixedThreadPool(n);

        ArrayList<Callable<Long>> tasks = new ArrayList<Callable<Long>>();
        for (int i = 0; i < n; ++i)
            tasks.add(new Callable<Long>() {
                public Long call() {
                    Date before = new Date();
                    try {
                        Socket socket = new Socket();
                        socket.connect(new InetSocketAddress(ip, port));
                    }

                    catch (Throwable e) {
                        e.printStackTrace();
                    }
                    Date after = new Date();
                    return after.getTime() - before.getTime();
                }
            });
        System.out.println("Invoking");
        List<Future<Long>> results = executor.invokeAll(tasks);
        System.out.println("Invoked");
        for (Future<Long> future : results) {
            System.out.println(future.get());
        }
        executor.shutdown();
    }

    private static void usage() {
        System.out.println("Usage: prog <threads> <url/IP Port>");
        System.out.println("Examples:");
        System.out.println("  prog tcp 10 127.0.0.1 2000");
    }
}
Run Code Online (Sandbox Code Playgroud)

更新 - 如果在运行测试程序之前清除相关的ARP条目,问题将一致地重现.我已经尝试调整TCP重传超时,但这没有帮助.此外,我们将此程序移植到.Net,但问题仍然存在.

更新2 - 3秒是从RFC 1122创建新连接的指定延迟.我仍然不完全理解为什么这里有重传,它应该由MAC层处理.另外,我们使用netcat重现了这个问题,因此它与java无关.

rip*_*234 3

我还没有从这次讨论中找到真正的答案。我想出的最好的理论是:

  1. TCP 层将 SYN 发送到 MAC 层。这是由多个线程发生的。
  2. 第一个线程发现 IP 在 ARP 表中没有匹配项,发送 ARP 请求。
  3. 后续线程发现有一个待处理的 ARP 请求,因此它们完全丢弃该数据包。这种行为可能是在几个操作系统的内核中实现的!
  4. ARP 回复返回,来自第一个线程的原始 SYN 请求离开机器并建立 TCP 连接。
  5. TCP 层等待 3 秒(如 RFC 1122 中所述),然后重试并成功。

我尝试过在 Windows 7 中调整超时,但没有成功。如果有人可以重现该问题并提供解决方法,我将非常有帮助。另外,如果有人有更多关于为什么这种现象只发生在多线程中的详细信息,那么听听会很有趣。

我会尝试接受这个答案,因为我认为任何答案都没有提供真正的解释(请参阅meta 上的讨论)。