我正在开发一种协议,需要握手,包括在每个方向上来回传递的几条信息,其中几个部分依赖于之前的部分(想像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; 他们没有帮助.]
尝试创建一个简单的服务器:
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 可能有效果,但对我来说,它并不明显。