14 Replies Latest reply: Oct 1, 2008 9:45 PM by 807589 RSS

    PrintWriter checkError cannot detect connection error immediately

    807589
      Hi,

      I have a server application that accepts a single client connection and sends messages to the client.
      After every call to println(<message>), I call the checkError() method of PrintWriter to check if there are errors in sending the message.
      This is to make sure message sending to client is successful. If message sending is unsuccessful (meaning checkError() returns true),
      my application then buffers the unsent message.

      The problem is, whenever after I shutdown the client application (client connection), the first try to send a message from my server application to the client, the call to checkError() returns false (meaning no errors). It's only in my second call to println(message) then checkErrror() will it return true (meaning error is detected).

      I've been searching the forums, but of no avail. I found a bug reported a couple of years back, yet I'm not sure if this has already been fixed: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4153007

      import java.net.Socket;
      import java.io.PrintWriter;
      /** import java.io.BufferedReader;*/
      import java.io.File;
      import java.io.IOException;
      import java.io.FileInputStream;
      /** import java.io.InputStreamReader;*/
      import java.text.SimpleDateFormat;
      import java.util.Properties;
      import java.util.Date;

      public class AlarmSender
      {
           private Socket _senderSocket = null;
           private PrintWriter _out;
      private ServerSocket _serverSocket;
           
           /**
           * Constructor
           */
           public AlarmSender() throws Exception
           {
      _serverSocket = new ServerSocket(2003);
      senderSocket = serverSocket.accept();
                out = new PrintWriter(senderSocket.getOutputStream(), true);
                _out.println("init");
      }
           
           
      /*After foreign client has shutdown, first call to this method after shutdown throws no exception. Only in the second will the checkError return true thus throwing an exception*/
           public void sendMessage() throws Exception
           {
                String asciiAlarm = new String("Test message");
                          
                LogTrace.debug("ASCII clear alarm: " + asciiAlarm);
                
                _out.println(asciiAlarm);
                _out.flush();
                
      if (_out.checkError())
                {
      throw new Exception("Error occured while sending alarm");
                }
           }
           
           public void close() throws IOException
           {
                _out.close();
                _senderSocket.close();
           }
      }
        • 1. Re: PrintWriter checkError cannot detect connection error immediately
          791266
          I've been searching the forums, but of no avail. I found a bug reported a couple of years back, yet I'm not sure if this has already been fixed: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4153007
          That bug was fixed in JDK 1.4

          Kaj
          • 2. Re: PrintWriter checkError cannot detect connection error immediately
            807589
            I'm currently using JDK 1.6 and still it is occuring. Anybody having the same problem? Help needed.
            • 3. Re: PrintWriter checkError cannot detect connection error immediately
              791266
              Do you use a BufferedWriter? What happens if you call flush after the write?

              Kaj
              • 4. Re: PrintWriter checkError cannot detect connection error immediately
                807589
                I'm using PrintWriter. PrintWriter methods do not throw Exceptions that's why I call the checkError() after every println(String) invocation.

                When I call the flush() method (for the first time after foreign client has shutdown) nothing happens, and checkError() returns false.
                Only the subsequent call to the println() and flush() will the checkError() method return true (meaning error is detected).
                • 5. Re: PrintWriter checkError cannot detect connection error immediately
                  791266
                  paksiw wrote:
                  I'm using PrintWriter. PrintWriter methods do not throw Exceptions that's why I call the checkError() after every println(String) invocation.

                  When I call the flush() method (for the first time after foreign client has shutdown) nothing happens, and checkError() returns false.
                  Only the subsequent call to the println() and flush() will the checkError() method return true (meaning error is detected).
                  Sorry I didn't check your code since it wasn't formatted. I just checked it and you had posted what I asked for.
                  • 6. Re: PrintWriter checkError cannot detect connection error immediately
                    791266
                    paksiw wrote:
                    I'm using PrintWriter. PrintWriter methods do not throw Exceptions that's why I call the checkError() after every println(String) invocation.

                    When I call the flush() method (for the first time after foreign client has shutdown) nothing happens, and checkError() returns false.
                    Only the subsequent call to the println() and flush() will the checkError() method return true (meaning error is detected).
                    It sounds very strange. I checked the code for PrintWriter and I can't see anything that looks odd. The trouble flag should be set if a write fails. (Note that checkError calls flush so you don't need to do that, and you don't need to call new String("....") since "...." already is a string).

                    Kaj
                    • 7. Re: PrintWriter checkError cannot detect connection error immediately
                      807589
                      This erroneous behavior occurs all the time. I used WireShark to see the exchange of messages between the 2 machines.
                      When I shutdown the foreign client application, it sends a [FIN, ACK] to the server application machine. The server application then sends [ACK] to the client application machine.

                      But after this, the first time when I try to send a new message from my server application, [PSH, ACK] attempt is still successful.
                      • 8. Re: PrintWriter checkError cannot detect connection error immediately
                        807589
                        I've created another prototype to test the effect of abnormal client disconnection and normal client disconnection.
                        Now I've noticed that the checkError() method can immediately detect foreign disconnection when connection is killed abnormally.
                        If foreign connection is closed gracefully, then the problem occurs (Where checkError() only returns true after second call to println() after disconnection).

                        Please I need help. Below is the running code.

                        Server Mini Application:
                        import java.io.IOException;
                        import java.io.PrintWriter;
                        import java.net.ServerSocket;
                        import java.net.Socket;
                        
                        public class TestServerSocket {
                        
                             /**
                              * @param args
                              */
                             public static void main(String[] args) 
                             {
                                  try {
                                       ServerSocket ssocket = new ServerSocket(2003);
                                       System.out.println("Waiting for connections");
                                       Socket s = ssocket.accept();
                        //               PrintWriter _out = new PrintWriter(new OutputStreamWriter(s.getOutputStream()), true);
                                       PrintWriter _out = new PrintWriter(s.getOutputStream(), true);
                                       
                                       int i = 0;
                                       while(!_out.checkError())
                                       {
                                            System.out.println("Sending " + i++);
                                            String st = "Message: " + i + "\n";
                                            _out.println(st);
                                            System.out.println("Error state: " + _out.checkError());
                                            
                                            Thread.sleep(10000);
                                       }
                                       
                                       System.out.println("Closing the connection..");
                                       
                                       
                                  } catch (IOException e) {
                                       // TODO Auto-generated catch block
                                       e.printStackTrace();
                                  } catch (InterruptedException e) {
                                       // TODO Auto-generated catch block
                                       e.printStackTrace();
                                  }
                        
                             }
                        
                        }
                        ==============================================

                        Client Mini Application:
                        import java.io.BufferedReader;
                        import java.io.IOException;
                        import java.io.InputStreamReader;
                        import java.net.Socket;
                        import java.net.UnknownHostException;
                        
                        public class TestClientSocket {
                        
                             Socket _s;
                             /**
                              * @param args
                              */
                             public static void main(String[] args) 
                             {
                                  final TestClientSocket test = new TestClientSocket();
                                  
                                        //Comment this part to test for abnormal/ abrupt disconnection start
                                  Runtime.getRuntime().addShutdownHook(new Thread() {
                                        public void run() {
                                          System.out.println("Closing connection..");
                                          test.stopTest();
                                          System.out.println("Connection closed");
                                        }
                                      });
                                        //Comment this part to test for abnormal/ abrupt disconnection end          
                                  
                                  test.startTest();
                                  
                                  
                             }
                             
                             public void startTest()
                             {
                                  try {
                                       _s = new Socket("15.66.89.217", 2003);
                                       System.out.println(_s.getPort());
                                       BufferedReader reader = new BufferedReader(new InputStreamReader(_s.getInputStream()));
                                       for (int i=0; i < 10; i++)
                                       {
                                            System.out.println("Waiting for messages");
                                            String msg = reader.readLine();
                                            System.out.println("Value rcv: " + msg);
                                       }
                                  } catch (UnknownHostException e) {
                                       // TODO Auto-generated catch block
                                       e.printStackTrace();
                                  } catch (IOException e) {
                                       // TODO Auto-generated catch block
                                       e.printStackTrace();
                                  } 
                             }
                             
                             public void stopTest()
                             {
                                  try {
                                       _s.getInputStream().close();
                                       
                                  } catch (IOException e) {
                                       // TODO Auto-generated catch block
                                       e.printStackTrace();
                                  }
                                  
                                  try {
                                       _s.close();
                                  } catch (IOException e) {
                                       // TODO Auto-generated catch block
                                       e.printStackTrace();
                                  }
                                  
                             }
                        
                        }
                        • 9. Re: PrintWriter checkError cannot detect connection error immediately
                          807589
                          hi friend

                          PrintWriter checkError cannot detect connection error immediately because its not PrintWriter 's responsibility to check whether connection is
                          alive or not.

                          checkError checks whether previous write fail or not. first PrintWriter has to write to stream and then in next checkError it will come to know

                          so it will not detect connection error immediately.

                          try some methods of Socket class.
                          • 10. Re: PrintWriter checkError cannot detect connection error immediately
                            EJP
                            Correct except for this:
                            try some methods of Socket class.
                            There are no methods of the Socket class that can tell you about a dropped connection. The only way to detect it is to write to it, and you may have to write a few times before you get an exception.

                            More to the point, you shouldn't really use PrintWriter or PrintStream at all over a network, because they swallow exceptions and you have no way of knowing what the exception actually was. If you want a Writer rather than an OutputStream, use a BufferedWriter.
                            • 11. Re: PrintWriter checkError cannot detect connection error immediately
                              807589
                              Hardik.Mishra wrote:
                              hi friend

                              PrintWriter checkError cannot detect connection error immediately because its not PrintWriter 's responsibility to check whether connection is
                              alive or not.

                              checkError checks whether previous write fail or not. first PrintWriter has to write to stream and then in next checkError it will come to know

                              so it will not detect connection error immediately.

                              try some methods of Socket class.
                              The application did try to write to the stream before invoking checkError. But still, for the first println and checkError invocation after remote socket has been disconnected, no error was detected.
                              • 12. Re: PrintWriter checkError cannot detect connection error immediately
                                807589
                                ejp wrote:
                                The only way to detect it is to write to it, and you may have to write a few times before you get an exception.
                                Is there anyway to know right away if write has failed? Because I am required to buffer messages that are not successfully sent to the remote client. In this case, I will lose a couple of messages if checkError() doesn't detect error immediately. :(

                                Is this a bug in Java Socket io?
                                More to the point, you shouldn't really use PrintWriter or PrintStream at all over a network, because they swallow exceptions and you have no way of knowing what the exception actually was. If you want a Writer rather than an OutputStream, use a BufferedWriter.
                                My application doesn't really require to know what the exceptions are. I just need to know if there was an error in writing to the stream.
                                • 13. Re: PrintWriter checkError cannot detect connection error immediately
                                  EJP
                                  Is there anyway to know right away if write has failed?
                                  No. TCP/IP doesn't know either.
                                  Because I am required to buffer messages that are not successfully sent to the remote client.
                                  TCP/IP buffers too. It's only when TCP/IP detects that a write from its send buffer hasn't been acknowledged that it sets an error condition, and this can take some time after the write that put the data into the send buffer.
                                  In this case, I will lose a couple of messages if checkError() doesn't detect error immediately. :(
                                  Then you have to build ACKs into your application protocol.
                                  Is this a bug in Java Socket io?
                                  No, it's the nature of TCP/IP. Every implementation and every API does the same thing. Java couldn't do anything about it even if it wanted do.
                                  My application doesn't really require to know what the exceptions are. I just need to know if there was an error in writing to the stream.
                                  I disagree completely. You need to know what the exception was so you can log it so you can debug what is happening to your application 18 months down the track when it starts doing mysterious things.
                                  • 14. Re: PrintWriter checkError cannot detect connection error immediately
                                    807589
                                    ejp wrote:
                                    In this case, I will lose a couple of messages if checkError() doesn't detect error immediately. :(
                                    Then you have to build ACKs into your application protocol.
                                    Oh, you mean have client explicitly acknowledge that it has successfuly received the message?
                                    Ok, thanks.

                                    Edited by: paksiw on Oct 1, 2008 8:57 PM