简体   繁体   中英

Forcing a TCP socket to flush in Java

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.]

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM