Sen*_*nne 6 java tcp client-server
我试图在一个简单的客户端 - 服务器程序中说明Nagle算法.但我无法弄明白,或者让它清楚地印在我身上.
在我的示例中,客户端只生成从1到1024的int并将它们发送到服务器.服务器只是将这些int转换为十六进制字符串并将它们发送回客户端.
几乎所有我改变的结果都是相同的结果.int的发送和重新发送在256个int的块中.我在两边尝试了setTcpNoDelay(true)来查看更改,但这在我的控制台中给出了相同的结果.(但不是在wireshark中,我看到服务器和客户端之间发送的数据包的数量有很大差异)但我的目标是能够在控制台中看到它,我猜测有一些ObjectOutputStream或类似的缓冲区阻止一切?
当我output = new PrintWriter(client.getOutputStream(), true)改为false (The true或false:autoFlush- 布尔值; if true,the println,printf或者format方法将刷新输出缓冲区)时,我的服务器不再向客户端提供任何输出.
基本上我的目标是只提供服务器和/或客户端的真或假作为参数来设置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");
}
}
}
Run Code Online (Sandbox Code Playgroud)
客户端:
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
您将无法看到差异,因为 readLine() 将等到读取 eol 为止。要查看差异,请使用二进制数据。使输出流写入 64 字节块,间隔 10 毫秒睡眠。使传入流读取 1024 字节的块。当 tcpNoDelay 为 true 时,每次读取操作时将读取传入流约 64 个字节。当 tcpNoDelay 为 false 时,传入流将读取更多字节。您可以记录每次读取操作中读取的平均字节数,因此差异很明显。并且始终使用两台机器进行测试,因为操作系统可以优化环回流。