强制TCP套接字在Java中刷新

Eth*_*ite 6 java sockets tcp

我正在开发一种协议,需要握手,包括在每个方向上来回传递的几条信息,其中几个部分依赖于之前的部分(想像SSL/TLS握手).我正在尝试用Java实现它.

我的很多数据包只有20-30个字节,而我的计算机似乎认为它需要在发送任何内容之前缓冲数百个字节; 即使我等待5-10秒(使用Thread.sleep),它仍然不会实际发送它,直到我关闭套接字.

如何让Java /我的计算机发送缓冲区中的内容?

在其他论坛(和SO)上,很多人一直在使用诸如"那不是TCP的工作方式"这样的论点,"你实际上并不需要这样做." 如果我需要每个方向发送10个数据包,每个都依赖于最后一个,每个在TCP堆栈中等待300毫秒,我正在寻找6s用于我的握手,这是完全无法使用的.(请注意,我无论如何都无法发送它,无论我在套接字上调用多少刷新;在关闭套接字之前我根本无法发送它).

我考虑过只发送一个数据包加上足够无用的填充来强制TCP实现强制它,这似乎是一个糟糕的解决方案.

(简化,摘录)代码:

Socket sock = new Socket("localhost", 1234);
OutputStream output = sock.getOutputStream();
output.write(new byte[] {(byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef});
output.flush();
Thread.sleep(5000);
Run Code Online (Sandbox Code Playgroud)

[我尝试过使用PrintWriter,OutputStreamWriter; 他们没有帮助.]

Wil*_*ord 1

尝试创建一个简单的服务器:

public static void main(String[] args) throws IOException {
    ServerSocket svr = new ServerSocket(1234);
    Socket s = svr.accept();
    byte b4[] = new byte[4];
    new DataInputStream(s.getInputStream()).readFully(b4);
    s.getOutputStream().write(b4);
}
Run Code Online (Sandbox Code Playgroud)

运行您的客户端代码,但测量时间:

public static void main(String[] args) throws IOException {
    Socket sock = new Socket("localhost", 1234);
    OutputStream output = sock.getOutputStream();
    long t1 = System.currentTimeMillis();
    output.write(new byte[]{(byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef});
    byte b4[] = new byte[4];
    new DataInputStream(sock.getInputStream()).readFully(b4);
    long t2 = System.currentTimeMillis();
    System.out.println("t2-t1="+(t2-t1));
}
Run Code Online (Sandbox Code Playgroud)

当我这样做时,我得到了 15 毫秒的输出。这是一个往返,包括读和写。如果您运行此命令并得到明显不同的结果,那么您可能需要修复网络配置中的某些内容。如果这给你大约 15 毫秒,你需要看看这段代码和你的代码之间的差异。setTcpNoDelay 可能有效果,但对我来说,它并不明显。