0

So here is the code I have:

public class TestClass {
    public static void main(String[] args) throws IOException, InterruptedException {
        Thread server = new Thread(new MyServer());
        server.start();
        Thread.sleep(750);
        Thread client = new Thread(new MyClient());
        client.start();
    }
}

The Server:

public class MyServer implements Runnable{

    public static synchronized void go() throws IOException {

        System.out.println("MyServer: Go called...");
        ServerSocket serverSocket = new ServerSocket(5000);
        while(true){
            Socket socket = serverSocket.accept();
            System.out.println(time() + "MyServer: Connection accepted!");
            OutputStream outputStream = socket.getOutputStream();
            System.out.println(time() + "MyServer: socket.getOutputStream");
            PrintWriter printWriter = new PrintWriter(outputStream);
            System.out.println(time() + "MyServer: New PrintWriter object created!");
            printWriter.write("Hello from my socket!");
            System.out.println(time() + "MyServer: printwriter.write method called..");
            printWriter.flush();
            System.out.println(time() + "MyServer: Flushed!");
            printWriter.close();
            System.out.println(time() + "MyServer: printWriter closed...");
        }
    }

    public static String time(){
        return String.valueOf(MyCounterClass.getCounter()) + " ";
    }

    @Override
    public void run() {
        try {
            go();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

The Client:

public class MyClient implements Runnable {

    public static synchronized void go() throws IOException {
        Socket socket = new Socket("localhost",5000);
        System.out.println(time() + "My Client: Connection established...");
        InputStream inputStream = socket.getInputStream();
        System.out.println(time() + "MyClient: socket.getInputStream...");
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        System.out.println(time() + "MyClient: BufferedReader object created...");
        System.out.println(time() + "Bufferedreader readline being called and directly printer: " + bufferedReader.readLine());
        System.out.println(time() + "bufferedReader.readline has just been called...");
    }

    public static String time(){
        return String.valueOf(MyCounterClass.getCounter()) + " ";
    }

    @Override
    public void run() {
        try {
            go();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

And the Counter class:

public class MyCounterClass {
    private static volatile int counter = 0;
    synchronized public static int getCounter(){
        return counter++;
    }
}

And the output will be:

0 My Client: Connection established...
1 MyServer: Connection accepted!
2 MyClient: socket.getInputStream...
3 MyClient: BufferedReader object created...
4 MyServer: socket.getOutputStream
6 MyServer: New PrintWriter object created!
7 MyServer: printwriter.write method called..
8 MyServer: Flushed!
9 MyServer: printWriter closed...
5 Bufferedreader readline being called and directly printer: Hello from my socket!
10 bufferedReader.readline has just been called...

When ordered:

0 My Client: Connection established...
1 MyServer: Connection accepted!
2 MyClient: socket.getInputStream...
3 MyClient: BufferedReader object created...
4 MyServer: socket.getOutputStream
5 Bufferedreader readline being called and directly printer: Hello from my socket!
6 MyServer: New PrintWriter object created!
7 MyServer: printwriter.write method called..
8 MyServer: Flushed!
9 MyServer: printWriter closed...
10 bufferedReader.readline has just been called...

So what is weird to me is line 5 is before 6,7,8... How is this possible?

Koray Tugay
  • 22,894
  • 45
  • 188
  • 319
  • 1
    "Flush" means that the data is assured to have been transmitted, or the method will wait until it is. It can be transmitted sooner. – Hot Licks Jun 28 '14 at 16:09
  • possible duplicate of [Why am I seeing this weird output in Java threads in Socket connections?](http://stackoverflow.com/questions/24468356/why-am-i-seeing-this-weird-output-in-java-threads-in-socket-connections) – alk Jun 28 '14 at 16:33
  • @alk It is not a duplicate. – Koray Tugay Jun 29 '14 at 05:31

2 Answers2

3

There are a number of things happening here

System.out.println(time() + "Bufferedreader readline being called and directly printer: " + bufferedReader.readLine());

First time() is invoked to get a value. Say it returns 5. That value is stored on the stack. Then readLine() is invoked and blocks until it receives something. Once it does, it concatenates the 5 from the stack, the String "Bufferedreader read..." and the String returned from readLine.

So even though the flush() (and writing to the stream) comes later, the value from time() has already been retrieved.

You'd need to synchronized around the whole String concatenation operation.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
1

flush will programatically empty and send the remaining buffer conttent but that does not mean that other automatic flushes won't be performed when the buffers fill completely during transmission over the socket.

That is, flush must be used to make sure the last remains of data in the buffer are sent when you have finished your transmission. However, many iterations of fill-send-flush may have been happened in the mean time.

enter image description here

In this diagram, the explicit flush that you perform within go method is the one responsible for sending the red colored bytes.

It may happen that your buffer is never filled before the call to flush and, in that case the client won't be sent the bytes until that call has finished :

enter image description here

EDIT Although the exposed in this answer is right, it is not full explanation for the problem you are experiencing, Sotirios's answer adds more insight on other problems with your code. Do not forget anyway that flush at the end of go does not imply the complete chunk is sent at that moment, m * sizeof(buffer) may have already been sent before that.