Java和Nagle插图

Java和Nagle插图,java,tcp,client-server,Java,Tcp,Client Server,我试图在一个简单的客户机-服务器程序中演示Nagle算法。但我不能完全弄清楚,也不能把它清楚地印出来 在我的示例中,客户机只生成从1到1024的int并将其发送到服务器。服务器只是将这些int转换为十六进制字符串,并将它们发送回客户端 几乎所有我改变的结果都是一样的。整数以256整数的块发送和重新发送。。 我尝试在两侧设置setCpnodelay(true)以查看更改,但这在我的控制台中给出了相同的结果。(但不是在wireshark中,我看到服务器和客户端之间发送的数据包数量有很大差异) 但我的

我试图在一个简单的客户机-服务器程序中演示Nagle算法。但我不能完全弄清楚,也不能把它清楚地印出来

在我的示例中,客户机只生成从1到1024的int并将其发送到服务器。服务器只是将这些int转换为十六进制字符串,并将它们发送回客户端

几乎所有我改变的结果都是一样的。整数以256整数的块发送和重新发送。。 我尝试在两侧设置setCpnodelay(true)以查看更改,但这在我的控制台中给出了相同的结果。(但不是在wireshark中,我看到服务器和客户端之间发送的数据包数量有很大差异) 但我的目标是能够在控制台中看到它,我猜有ObjectOutputStream或类似的缓冲区来支撑一切

当我将
output=new PrintWriter(client.getOutputStream(),true)
更改为
false
true
false
autoFlush
-布尔值;如果
true
,则
println
printf
format
方法将刷新输出缓冲区)我的服务器不再向客户端返回任何输出

基本上,我的目标是将server和/或client作为参数设置为true或false,以便在启动TcpNoDelay时清楚地看到控制台中输入/输出的差异。我不确定所使用的所有东西,所以欢迎任何帮助来清除这个问题

服务器:

package Networks.Nagle;

import java.io.*;
import java.net.*;
import java.util.*;

public class NagleDemoServer
{
    private static ServerSocket serverSocket;
    private static final int PORT = 1234;

    public static void main(String[] args) throws IOException
    {
        int received = 0;
        String returned; 
        ObjectInputStream input = null;
        PrintWriter output = null;
        Socket client;

        try
        {
            serverSocket = new ServerSocket(PORT);
            System.out.println("\nServer started...");
        }
        catch (IOException ioEx)
        {
            System.out.println("\nUnable to set up port!");
            System.exit(1);
        }

        while(true)
        {
            client = serverSocket.accept();
            client.setTcpNoDelay(true);

            System.out.println("\nNew client accepted.\n");

            try
            {
                input = new ObjectInputStream(client.getInputStream());
                output = new PrintWriter(client.getOutputStream(), true);

                while( true )
                {
                    received = input.readInt();
                    returned = Integer.toHexString(received);
                    System.out.print(" " + received);
                    output.println(returned.toUpperCase());

                }
            }
            catch(EOFException eofEx)
            {
                output.flush();
                System.out.println("\nEnd of client data.\n");
            }
            catch(SocketException sEx)
            {
                System.out.println("\nAbnormal end of client data.\n");
            }
            catch(IOException ioEx)
            {
                ioEx.printStackTrace();
            }

            input.close();
            output.close();
            client.close();
            System.out.println("\nClient closed.\n");
        }
    }
}
客户:

package Networks.Nagle;

import java.io.*;
import java.net.*;
import java.util.*;

public class NagleDemoClient
{
    private static InetAddress host;
    private static final int PORT = 1234;

    public static void main(String[] args)
    {
        Socket socket = null;

        try
        {
            host = InetAddress.getByName("localhost");

            socket = new Socket(host, PORT);

            socket.setTcpNoDelay(true);
            socket.setSendBufferSize(64);

            System.out.println("Send Buffer: " + socket.getSendBufferSize());
            System.out.println("Timeout: " + socket.getSoTimeout());
            System.out.println("Nagle deactivated: " + socket.getTcpNoDelay());

        }
        catch(UnknownHostException uhEx)
        {
            System.out.println("\nHost ID not found!\n");
            System.exit(1);
        }
        catch(SocketException sEx)
        {
            sEx.printStackTrace();
        }
        catch(IOException ioEx)
        {
            ioEx.printStackTrace();
        }

        NagleClientThread client = new NagleClientThread(socket);
        NagleReceiverThread receiver = new NagleReceiverThread(socket);

        client.start();
        receiver.start();

        try
        {
            client.join();
            receiver.join();

            socket.close();
        }
        catch(InterruptedException iEx)
        {
            iEx.printStackTrace();
        } 
        catch(IOException ioEx)
        {
            ioEx.printStackTrace();
        }

        System.out.println("\nClient finished.");
    }
}


class NagleClientThread extends Thread
{
    private Socket socket;

    public NagleClientThread(Socket s)
    {
        socket = s;

    }

    public void run() 
    {
        try
        {
            ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());

            for( int i = 1; i < 1025; i++)
            {
                output.writeInt(i);
                sleep(10);
            } 

            output.flush();
            sleep(1000);
            output.close();
        }
        catch(IOException ioEx)
        {
            ioEx.printStackTrace();
        }
        catch(InterruptedException iEx)
        {
            iEx.printStackTrace();
        }
    }
}


class NagleReceiverThread extends Thread
{
    private Socket socket;

    public NagleReceiverThread(Socket s)
    {
        socket = s;
    }

    public void run()
    {
        String response = null;
        BufferedReader input = null;

        try
        {
            input = new BufferedReader(
                        new InputStreamReader(socket.getInputStream()));

            try
            {
                while( true ) 
                {
                    response = input.readLine(); 
                    System.out.print(response + " ");
                } 
            }
            catch(Exception e)
            {
                System.out.println("\nEnd of server data.\n");
            }    

            input.close();

        }
        catch(IOException ioEx)
        {
            ioEx.printStackTrace();
        }
    }
}
packagenetworks.Nagle;
导入java.io.*;
导入java.net。*;
导入java.util.*;
公共类NagleDemoClient
{
专用静态地址主机;
专用静态最终int端口=1234;
公共静态void main(字符串[]args)
{
套接字=空;
尝试
{
host=InetAddress.getByName(“localhost”);
套接字=新套接字(主机、端口);
socket.setTcpNoDelay(true);
插座。setSendBufferSize(64);
System.out.println(“发送缓冲区:+socket.getSendBufferSize());
System.out.println(“超时:+socket.getSoTimeout());
System.out.println(“Nagle停用:+socket.getTcpNoDelay());
}
捕获(未知后异常uhEx)
{
System.out.println(“\n找不到主机ID!\n”);
系统出口(1);
}
捕获(袜子例外性别)
{
sEx.printStackTrace();
}
捕获(IOException ioEx)
{
ioEx.printStackTrace();
}
NagleClientThread客户端=新的NagleClientThread(套接字);
NagleReceiverThread接收器=新的NagleReceiverThread(套接字);
client.start();
receiver.start();
尝试
{
client.join();
receiver.join();
socket.close();
}
捕获(中断异常iEx)
{
iEx.printStackTrace();
} 
捕获(IOException ioEx)
{
ioEx.printStackTrace();
}
System.out.println(“\n客户端完成”);
}
}
类NagleClientThread扩展了线程
{
专用插座;
公共NagleClient线程(套接字s)
{
插座=s;
}
公开募捐
{
尝试
{
ObjectOutputStream输出=新的ObjectOutputStream(socket.getOutputStream());
对于(int i=1;i<1025;i++)
{
输出.写入(i);
睡眠(10);
} 
output.flush();
睡眠(1000);
output.close();
}
捕获(IOException ioEx)
{
ioEx.printStackTrace();
}
捕获(中断异常iEx)
{
iEx.printStackTrace();
}
}
}
类NagleReceiverThread扩展线程
{
专用插座;
公共NagleReceiver线程(套接字s)
{
插座=s;
}
公开募捐
{
字符串响应=null;
BufferedReader输入=null;
尝试
{
输入=新的BufferedReader(
新的InputStreamReader(socket.getInputStream());
尝试
{
while(true)
{
response=input.readLine();
系统输出打印(响应+“”);
} 
}
捕获(例外e)
{
System.out.println(“\n服务器数据的数量。\n”);
}    
input.close();
}
捕获(IOException ioEx)
{
ioEx.printStackTrace();
}
}
}

您将无法看到差异,因为readLine()将等待读取eol。要查看差异,请使用二进制数据。使64字节的传出流写入块以10ms的间隔休眠。使传入流读取1024字节的块。当tcpNoDelay为true时,每次读取操作将读取大约64字节的传入流。当tcpNoDelay为false时,传入流将读取更多字节。您可以记录每次读取操作中读取的平均字节数,因此差异非常明显。另外,还要始终使用两台机器进行测试,因为操作系统可以优化环回流。

您可以使用一台对等机进行测试,一台对等机只是发送,另一台只是接收和记录。但根据您的示例,我知道您希望进行服务器测试以达到基准测试的目的。在这种情况下,让带有tcpnode的服务器始终处于打开状态,并让它读取4096字节的块,然后立即用它刚刚读取的字节数进行应答。只需在客户端上更改tcpNoDelay,您就会看到不同之处。