Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Forcing a TCP socket to flush in Java

Tags:

java

tcp

sockets

I'm developing a protocol that requires a handshake that consists of several pieces of information going back and forth in each direction, with several pieces dependent on the previous pieces (think like SSL/TLS handshake). I'm trying to implement it in Java.

A lot of my packets are only 20-30 bytes, whereas my computer seems to think it needs to buffer hundreds of bytes before it sends anything; even if I wait 5-10 seconds (with Thread.sleep), it still won't actually send it until I close the socket.

How can I get Java/my computer to send what's in its buffer?

On other forums (and SO), a lot of people have been using arguments like "that's not how TCP works", "you shouldn't actually need that." If I need to send 10 packets each way, each one depends on the last, each one waits for 300ms in the TCP stack, I'm looking at 6s for my handshake, which is completely unusable. (Mind you, I can't get it to send at all, no matter how much I call flush on the socket; I can't get it sent at all until I close the socket).

I have considered just sending a packet plus enough useless padding to force the TCP implementation to force it, that seems like a bad solution.

(Simplified, extracted) Code:

Socket sock = new Socket("localhost", 1234);
OutputStream output = sock.getOutputStream();
output.write(new byte[] {(byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef});
output.flush();
Thread.sleep(5000);

[I've tried with PrintWriter, OutputStreamWriter; they don't help.]

like image 491
Ethan White Avatar asked Sep 07 '15 20:09

Ethan White


People also ask

Can you flush a socket?

You cant really flush a socket.

How do I flush TCP buffer?

The only way to "flush" the receive buffer is to read from it. After the first read, keep reading from the socket, throwing that data away, until there is no more data available to read. Use select() with a timeout to detect when the socket is still receiving data.

Does java sockets use TCP?

Yes, Socket and ServerSocket use TCP/IP. The package overview for the java.net package is explicit about this, but it's easy to overlook. UDP is handled by the DatagramSocket class.

What is TCP socket in java?

A socket is one endpoint of a two-way communication link between two programs running on the network. A socket is bound to a port number so that the TCP layer can identify the application that data is destined to be sent to. An endpoint is a combination of an IP address and a port number.


1 Answers

Try this create a simple server :

public static void main(String[] args) throws IOException {
    ServerSocket svr = new ServerSocket(1234);
    Socket s = svr.accept();
    byte b4[] = new byte[4];
    new DataInputStream(s.getInputStream()).readFully(b4);
    s.getOutputStream().write(b4);
}

Run your client code, but measure the time:

public static void main(String[] args) throws IOException {
    Socket sock = new Socket("localhost", 1234);
    OutputStream output = sock.getOutputStream();
    long t1 = System.currentTimeMillis();
    output.write(new byte[]{(byte) 0xde, (byte) 0xad, (byte) 0xbe, (byte) 0xef});
    byte b4[] = new byte[4];
    new DataInputStream(sock.getInputStream()).readFully(b4);
    long t2 = System.currentTimeMillis();
    System.out.println("t2-t1="+(t2-t1));
}

When I did this I got an output of 15 milliseconds. This is round trip including both read and write. If you run this and get something dramatically different, then you probably need to fix something in your network configuration. If this gives you about 15 milliseconds you need to look at the difference between this code and your code.The setTcpNoDelay might have an effect but for for me it wasn't noticeable.

like image 86
WillShackleford Avatar answered Sep 22 '22 15:09

WillShackleford