Neatoro
Neatoro

Reputation: 173

Java OutputStream only flushes data on close

Socket socket = new Socket("192.168.178.47", 82);

OutputStream out = socket.getOutputStream();
out.write("{ \"phone\": \"23456789\" }".getBytes());
out.flush();

//Server

InputStream in = client.getInputStream();
ByteArrayOutputStream bOut = new ByteArrayOutputStream();

int i = 0;
while((i = in.read()) >= 0) {
    bOut.write(i);
}

String complete = new String(bOut.toByteArray(), "UTF-8");

I had tried to send data via OutputStream to a socket but the data is not flushing. If I add an out.close(); to the end then it works perfectly, but the socket is closed and I cannot accept the response. Does anybody know why? The server is not giving any type of error. I had used Java 1.7!

Upvotes: 8

Views: 7958

Answers (5)

MadConan
MadConan

Reputation: 3767

I'm not sure of the labelling "//Server" in your question, but I'm assuming the following code is the server code:

InputStream in = client.getInputStream();
ByteArrayOutputStream bOut = new ByteArrayOutputStream();

int i = 0;
while((i = in.read()) >= 0) {
    bOut.write(i);
}

String complete = new String(bOut.toByteArray(), "UTF-8");

This will continue to read, blocking each time, until it gets a value from read() less than zero. That only happens if the stream is closed.

It really looks like you need to establish your own protocol. So instead of looking for "<=0" look for some constant value that signals the end of the message.

Here's a quick demonstration of what I mean (I didn't have time yesterday). I have 3 classes, Message,MyClient (which also is the main class), and MyServer. Notice there isn't anything about sending or receiving a newline. Nothing is setting tcpNoDelay. But it works fine. Some other notes:

  • This code only sends and receives a single request and response.
  • It doesn't support sending multiple Message instances. That would require checking for the start of a Message as well as the end.

Message class:

public class Message {
    public static final String MSG_START = "<message>";
    public static final String MSG_END = "</message>";

    private final String content;

    public Message(String string){
        content = string;
    }

    @Override
    public String toString(){
        return MSG_START + content + MSG_END;
    }
}

MyServer class

public class MyServer implements Runnable{
    public static final int PORT = 55555;

    @Override
    public void run(){
        try {
            ServerSocket serverSocket = new ServerSocket(PORT);
            Socket socket = serverSocket.accept();
            String message = getMessage(socket);
            System.out.println("Server got the message:  " + message);
            sendResponse(socket);
        }catch (IOException e){
            throw new IllegalStateException(e);
        }
    }

    private void sendResponse(Socket socket) throws IOException{
        Message message = new Message("Ack");
        System.out.println("Server now sending a response to the client: " + message);
        OutputStream out = socket.getOutputStream();
        out.write(message.toString().getBytes("UTF-8"));
    }

    private String getMessage(Socket socket) throws IOException{

        BufferedInputStream in = new BufferedInputStream(socket.getInputStream());
        StringBuilder sb = new StringBuilder(100);
        byte[] bytes = new byte[1024<<8];
        while(sb.lastIndexOf(Message.MSG_END) == -1){
            int bytesRead = in.read(bytes);
            sb.append(new String(bytes,0,bytesRead,"UTF-8"));
        }

        return sb.toString();
    }
}

MyClient class

public class MyClient {

    public static void main(String[] args){
        MyClient client = new MyClient();

        Thread server = new Thread(new MyServer());
        server.start();

        client.performCall();
    }

    public void performCall(){
        try {
            Socket socket = new Socket("127.0.0.1",MyServer.PORT);
            sendMessage(socket, "Why hello there!");
            System.out.println("Client got a response from the server: " + getResponse(socket));
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
    }

    public String getResponse(Socket socket) throws IOException{
        String response;

        StringBuilder sb = new StringBuilder(100);
        InputStream in = socket.getInputStream();
        byte[] bytes = new byte[1024];
        while(sb.lastIndexOf(Message.MSG_END) == -1){
            int bytesRead = in.read(bytes);
            sb.append(new String(bytes,0,bytesRead,"UTF-8"));
        }
        response = sb.toString();

        return response;
    }

    public void sendMessage(Socket socket, String message) throws IOException{
        Message msg = new Message(message);
        System.out.println("Client now sending message to server: " + msg);
        OutputStream out = socket.getOutputStream();
        out.write(msg.toString().getBytes("UTF-8"));
    }
}

The output

Client now sending message to server: Why hello there!
Server got the message:  Why hello there!
Server now sending a response to the client: Ack
Client got a response from the server: Ack

Process finished with exit code 0

Upvotes: 4

jarnbjo
jarnbjo

Reputation: 34313

The problem is not that you are not flushing properly, but that the reading code waits for the socket to disconnect before handling the data:

while((i = in.read()) >= 0)

Will loop as long as something can be read from in (the socket's InputStream). The condition will not fail until the other peer disconnects.

Upvotes: 1

Dan
Dan

Reputation: 1018

Looking at your code it seems ok. However you are sending less than the MTU Nagle's algothrim could be holding it back until enough data is present for a full packet or you close the socket.

So - try this:

socket.setTCPNoDelay(true);

http://en.wikipedia.org/wiki/Nagle%27s_algorithm https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html#setTcpNoDelay-boolean-

Upvotes: -1

Mike
Mike

Reputation: 3311

Try using

socket.setTcpNoDelay(true);

There is buffering that occurs for performance reasons (read up on Nagle's algorithm).

Upvotes: 0

Evgeniy Dorofeev
Evgeniy Dorofeev

Reputation: 136002

It is possible that the server is waiting for the end of line. If this is the case add "\n" to the text

Upvotes: 7

Related Questions