socket.setTcpNoDelay(true)不起作用

时间:2016-12-08 20:48:40

标签: java sockets tcp

我在使用tcp socket发送数据包时遇到问题。我的程序做的非常简单:首先,客户端套接字连接到服务器套接字。然后服务器套接字发送5"你好"回到客户端,客户端输出5"你好"到控制台。客户端和服务器都在我的本地计算机上运行,​​下面是完整的代码:

服务器

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();
}

}

鉴于上面发布的代码,我的预期输出应该是这样的:

您好

您好

您好

您好

您好

但是,我得到的实际结果是:

您好

hellohellohellohello

我的问题就在这里。结果输出不遵循我在服务器上发送的顺序。我要求服务器发送5"你好"逐一。但根据结果,似乎服务器真正做的是发送一个"你好"起初然后发送剩余的四个"你好"一起来。

搜索谷歌后,我发现很多人将这个问题与所谓的Nagle算法联系起来,这将避免tcp套接字立即发送短数据包以提高网络使用效率。要禁用Nagle算法,只需要在socket上调用setTcpNoDelay(true)。然后,计算机将立即发送您要求发送的任何内容。但不幸的是,在我禁用Nagle算法后,我的客户端仍然输出与上面相同的结果。你能告诉我我错过了什么或做错了吗?非常感谢任何帮助!

2 个答案:

答案 0 :(得分:1)

我可以重现你所看到的行为。但是,这可能会令你失望,Nagle算法与此处发生的事情毫无关系。

当您运行客户端和服务器,并使用struct top_level_module: private module0, private module1 { using module0::a; using module0::b; using module0::c; using module1::d; using module1::e; }; 检查网络流量时,您可以看到每次调用tcpdump都会生成一个包含字符串write的TCP数据包。当您拨打hello和不拨打电话时,会发生这种情况。总而言之,发件人的工作方式与预期完全相同:您正在写入无缓冲的setTcpNoDelay(true),并且数据会立即发送出去。

Traffic dump

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

答案 1 :(得分:0)

您应该使用缓冲的读取器和写入器,用newLine分隔每条消息,并使用读取器读取每一行:

首先,设置您的流:

std::string

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

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();
}