Search code examples
javasocketsserversocketoutputstream

Java ServerSocket OutputStream not flushing


My ServerSocket (java.net.ServerSocket) only flushes the data if I close the OutputStream, but if I close the OutputStream, it closes the connection. Here is my code

Server:

ServerSocket server = new ServerSocket(7788);
Socket client = server.accept();

OutputStream os = client.getOutputStream();

os.write("Hello World".getBytes());
os.flush();
// os.close();

Client:

Socket client = new Socket("localhost", 7788);

byte[] bytes = client.getInputStream().readAllBytes();
String message = new String(bytes);

System.out.println(message);

If I close the OutputStream everything works fine, but I need to send data multiple times for my project. Is there a solution for this?


Solution

  • the problem is not the flush() on the OutputStream (server), but rather the readAllBytes() on the InputStream (client). from the docs (emphasis mine):

    public byte[] readAllBytes() throws IOException

    Reads all remaining bytes from the input stream. This method blocks until all remaining bytes have been read and end of stream is detected, or an exception is thrown.

    end of stream is "sent" only on close(), that is why you are able to read (print) the message only after close().

    a very simple solution to exchange one-line textual data would be to send messages separated by '\n' (new line) character and on the client part, read from the socket line-by-line, for example:

    Server.java

    import java.io.OutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class Server
    {
            public static void main(String[] args) throws Exception
            {
                    ServerSocket server = new ServerSocket(7788);
                    Socket client = server.accept();
    
                    OutputStream os = client.getOutputStream();
                    for (int i = 0; i < 5; i++) {
                            os.write(String.format("message %d\n", i).getBytes());
                            os.flush();
    
                            Thread.sleep(2000);
                    }
    
                    os.close();
            }
    }
    

    Client.java

    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.net.Socket;
    
    public class Client
    {
            public static void main(String[] args) throws Exception
            {
                    Socket client = new Socket("localhost", 7788);
    
                    BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
                    String message = null;
                    while ((message = reader.readLine()) != null)
                            System.out.println(message);
    
                    reader.close();
            }
    }
    

    $ javac Server.java Client.java
    $ java Server
    

    $ java Client
    message 0
    message 1
    message 2
    message 3
    message 4
    $
    

    if you run the above code, you will see that messages gets printed (received) one after the other with a 2 seconds delay and readLine() returns as soon as it read a \n (new line) character.

    if this is not feasible for your use case, I think you will need a more structured protocol.