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.
The
println()
methods of thePrintWriter
class "commit" the data to the stream only if theautoFlush
attribute is enabled.Look at this quote from the Java docs:
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!
It's more efficient not to flush the data after every single
println
. If you're writing a lot of data, you want to buffer it and send in big chunks, not send each line separately. That's why you need to manually flush the streams if you want to make sure that the data is indeed sent to the other end.Imagine you're writing an email to a friend, and you send each word as its own email vs. sending the whole text in a single email. Which do you think is faster? Sure, your friend will get to read the mail quicker if you send each word as you think of it, but the total time taken will become longer.