Search code examples
javaiostreamprintwriter

Java - Understanding PrintWriter and need for flush


Ok, firstly I apologise for all the code but I feel like too much code is better than not enough. I'm making a simple chat client and printwriter in particular i'm struggling with. With the code the way it is the now it will interact with the server class and perfectly fine and print what im wanting to print. However, when I remove 'writer.flush();' it will stop printing. With my understanding -which is evidently wrong- 'writer.println(outgoing.getText());' should be enough as this would send the text im trying to send to the server. I understand flush forces all the information to write but why is this required when i've already written what I want to write?

public class SimpleChatClientA {

    JTextArea incoming;
    JTextField outgoing;
    BufferedReader reader;
    PrintWriter writer;
    Socket sock;

    public void go(){

        JFrame frame = new JFrame("Ludicrously Simple Chat Client");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel mainPanel = new JPanel();

        incoming = new JTextArea(15,50);
        incoming.setLineWrap(true);
        incoming.setWrapStyleWord(true);
        incoming.setEditable(false);

        JScrollPane qScroller = new JScrollPane(incoming);
        qScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        qScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

        outgoing = new JTextField(20);

        JButton sendButton = new JButton("Send");
        sendButton.addActionListener(new SendButtonListener());

        mainPanel.add(qScroller);
        mainPanel.add(outgoing);
        mainPanel.add(sendButton);
        setUpNetworking();

        Thread readerThread = new Thread(new IncomingReader());
        readerThread.start();

        frame.getContentPane().add(BorderLayout.CENTER, mainPanel);
        frame.setSize(400, 500);
        frame.setVisible(true);


    }//close go

    public void setUpNetworking(){
        try{

            sock = new Socket("127.0.0.1", 5000);

            InputStreamReader streamReader = new InputStreamReader(sock.getInputStream());

            reader = new BufferedReader(streamReader);
            writer = new PrintWriter(sock.getOutputStream());
            System.out.println("network established");
        }catch(Exception e){
            e.printStackTrace();
        }
    }//close setupnetworking

    public class SendButtonListener implements ActionListener{

        @Override
        public void actionPerformed(ActionEvent e) {

            try{
                writer.println(outgoing.getText());
                writer.flush();
            }catch(Exception ex){
                ex.printStackTrace();
            }
            outgoing.setText("");
            outgoing.requestFocus();
        }

    }//close sendbuttonlistener inner class


    public class IncomingReader implements Runnable{

        public void run(){
            String message;
            try{

                while((message = reader.readLine()) != null){
                    System.out.println("read " + message);
                    incoming.append(message + "\n");
                }

            }catch(Exception e){
                e.printStackTrace();
            }
        }

    }//close inner class incomingreader


    public static void main(String[] args){
        new SimpleChatClientA().go();
    }


}

Thanks in advance, if there is anymore information I can give please let me know first time i've properly posted to stackoverflow.


Solution

  • The println() methods of the PrintWriter class "commit" the data to the stream only if the autoFlush attribute is enabled.

    Look at this quote from the Java docs:

    if automatic flushing is enabled it will be done only when one of the println, printf, or format methods is invoked

    Link to Java docs here: https://docs.oracle.com/javase/7/docs/api/java/io/PrintWriter.html#PrintWriter(java.io.OutputStream,%20boolean)

    If you need to send the message over to the server, then create the PrintWriter object with the autoflush option turned on.

    So, where you're creating the writer object, just do this:

    writer = new PrintWriter(sock.getOutputStream(), true);

    That should do it. Hope it helps!