有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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算法之后,我的客户端仍然输出与上面相同的结果。你们能告诉我我错过了什么或做错了什么吗?非常感谢您的帮助


共 (2) 个答案

  1. # 1 楼答案

    我可以复制你看到的行为。但是,这可能会让你失望,Nagle算法与这里发生的事情无关

    当运行客户端和服务器,并使用tcpdump检查网络流量时,可以看到对write的每次调用都会生成一个带有字符串hello的TCP数据包。当你调用setTcpNoDelay(true)和不调用时都会发生这种情况。总之,发送方的工作原理与预期基本相同:你正在向一个无缓冲的OutputStream写入数据,数据会立即被发送出去

    Traffic dump

    因此,一次读取四个数据包的原因是,数据包在接收端得到了缓冲。我觉得你对此无能为力。如果需要区分TCP流中的连续消息,则需要查看各种serialization算法

  2. # 2 楼答案

    您应该使用缓冲读写器,用换行符分隔每条消息,并使用读写器阅读每一行:

    首先,设置流:

    bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
    bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    bufferedWriter.flush();
    

    然后通过调用以下函数在服务器上编写消息:

    private void rawSend(final String rawText) throws IOException {
        bufferedWriter.write(rawText);
        bufferedWriter.newLine();
        bufferedWriter.flush();
    }
    

    然后在客户机上,阅读以下内容:

    final String rawPacket = bufferedReader.readLine();