javasocket。setTcpNoDelay(true)不工作
我在使用tcpsocket发送数据包时遇到问题。我的程序做的很简单:首先,客户端socket连接到服务器socket。然后服务器socket向客户端发送5个“hello”,客户端将5个“hello”输出到控制台。客户端和服务器都在我的本地计算机上运行,下面是完整代码:
服务器:
public class Server {
private static ServerSocket serverSocket;
public static void main(String[] args) throws IOException, InterruptedException {
serverSocket = new ServerSocket(60009);
serverSocket.setReuseAddress(true);
System.out.println("Server started!");
final Socket socket = serverSocket.accept();
socket.setTcpNoDelay(true);
Thread.sleep(1000);
socket.getOutputStream().write("hello".getBytes());
socket.getOutputStream().write("hello".getBytes());
socket.getOutputStream().write("hello".getBytes());
socket.getOutputStream().write("hello".getBytes());
socket.getOutputStream().write("hello".getBytes());
InputStream is = socket.getInputStream();
is.read(new byte[100]);
}
}
客户端:
public class Client {
static Socket socket;
static byte[] buffer;
public static void main(String[] args) throws IOException {
socket = new Socket();
socket.setTcpNoDelay(true);
socket.connect(new InetSocketAddress("localhost", 60009));
buffer = new byte[100];
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
InputStream is = null;
try {
is = socket.getInputStream();
is.read(buffer);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
String rcvStr = new String(buffer);
System.out.println(rcvStr);
}
}
}).start();
}
}
鉴于上面发布的代码,我的预期输出应该如下所示:
你好
你好
你好
你好
你好
然而,我得到的实际结果是:
你好
你好
我的问题就在这里。结果输出不遵循我在服务器上发送它们的顺序。我要求服务器一个接一个地发送5个“你好”。但根据结果,服务器真正做的似乎是先发送一个“hello”,然后再发送其余四个“hello”
在搜索google之后,我发现很多人将这个问题与所谓的Nagle算法联系起来,该算法可以避免tcpsocket立即发送短数据包,从而提高网络使用效率。要禁用Nagle算法,只需在socket上调用setTcpNoDelay(true)。然后计算机会立即发送您要求它发送的任何内容。但不幸的是,在我禁用了Nagle算法之后,我的客户端仍然输出与上面相同的结果。你们能告诉我我错过了什么或做错了什么吗?非常感谢您的帮助
# 1 楼答案
我可以复制你看到的行为。但是,这可能会让你失望,Nagle算法与这里发生的事情无关
当运行客户端和服务器,并使用
tcpdump
检查网络流量时,可以看到对write
的每次调用都会生成一个带有字符串hello
的TCP数据包。当你调用setTcpNoDelay(true)
和不调用时都会发生这种情况。总之,发送方的工作原理与预期基本相同:你正在向一个无缓冲的OutputStream
写入数据,数据会立即被发送出去因此,一次读取四个数据包的原因是,数据包在接收端得到了缓冲。我觉得你对此无能为力。如果需要区分TCP流中的连续消息,则需要查看各种serialization算法
# 2 楼答案
您应该使用缓冲读写器,用换行符分隔每条消息,并使用读写器阅读每一行:
首先,设置流:
然后通过调用以下函数在服务器上编写消息:
然后在客户机上,阅读以下内容: