Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4493377

Initial write to socket closed by other end does not fail

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Not an Issue
    • Icon: P4 P4
    • None
    • 1.3.0, 1.4.0
    • core-libs
    • x86
    • windows_nt, windows_2000



      Name: nt126004 Date: 08/17/2001


      C:\Mis documentos\pruebasockets>c:\jdk\jdk1.2.2\bin\java -version
      java version "1.2.2"
      Classic VM (build JDK-1.2.2-001, native threads, symcjit)

      I have an application wich is intended to write data in string format via a
      socket. There is a moment when i want that one of the peers close the
      connection. This closing should cause that the other peer gets an exception
      wich prevents it from continuing sending data to the socket.
      When the peer wich did not close the socket tries to write on the closed
      socket, it gets an exception, but only the second and later times it tries to.
      Thus, the first message sent does not get an exception though there in nobody
      to get the message.
      I have get this problem both in windowsNT 4.0 and in Windows95 platforms, and
      both in java 1.2.2 and java 1.3 jdk's
      I have read the bug 4213824, which is similar to this, but there are two
      differences in this report:
      i do not have problems to obtain an exception when READING from the closed
      socket.
      I abide that the closed socket causes a exception when writing, but only the
      second and later times.
      Next i attach the code of a program which illustrates the problem:
      This program shows two windows, one for controlling a server side and one for
      controlling the client side.
      1. Click on the "Accept" button on the window for the server
      2. Click on the "Connect" button on the window for the client
      At this point the client and the server should be connected
      3. (Optional) Click on the receive button on the client. This will launch a
      thread that will cause that all messages sent from the server appear on the
      panel in the client
      4. (Optional) Click on the "send" button on the server to send messages to the
      client. The message will be the text of the text box included in the server.
      Steps 3 and 4 are oprionals, but they are interesting to ensure that the
      comunication is correct
      5. Click on the "close" button on the client. This will close the socket
      (and its associated writer)
      6. Click on the "send" button on the server. Here is where the problem can be
      seen. The program is triying to write on a closed socket and should get an
      exception because of that, but it succeeds on the write operation instead!.
      7. Click on the "send" button again. Now the program gets an exception when
      writing to the socket.

      Some preliminary explanations to the attached code:
      1. The program has been developed with JBuilder3.0, (but i have compiledrun it
      with JDK1.2.2 get from a Sun page), so the code to construct the windows and
      its components is generated by JBuilder and is not intended to be clear. In
      fact, i recommend not to read the jbInit methods not the class "Lanzador". The
      only reason i include these sources is to allow the program to be run directly.
      2. The program uses the ip direction "127.0.0.1" to connect the socket, wich is
      supposed to be the direction of the local host. If the program is not going to
      run on the same machine this direction should be changed accordingly.
      3. The program uses a bufferedReader and a bufferedWriter to read and write
      from an to the socket. These objects are closed prior to close the socket,
      following the advice from bug 4213824. I have tried to write to the socket
      using the PrintWriter class and have get the same result.
      4. The program relies on the buffered writer and reader to close the
      outputStream of the socket when they are closed, but i have tried to close the
      Stream directly and get the same result.
      5. The program forces the actual writing of the messages by calling the flush
      method of the writer

      And here cames the code:

      /* This is a class generated by JBuilder to launch the program. It is necesary
         to excecute the program but is is not necesary to understand the problem,
         so you need not to read it */

      import javax.swing.UIManager;
      import java.awt.*;

      public class Lanzador
      {
       boolean packFrame = false;

       //Construct the application
        public Lanzador()
       {
        TfrmPrincipal frame = new TfrmPrincipal();
        TfrmSecundaria sec = new TfrmSecundaria();
        //Validate frames that have preset sizes
        //Pack frames that have useful preferred size info, e.g. from their layout
        if (packFrame)
         frame.pack();
        else
         frame.validate();
        //Center the window
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        Dimension frameSize = frame.getSize();
        if (frameSize.height > screenSize.height)
         frameSize.height = screenSize.height;
        if (frameSize.width > screenSize.width)
         frameSize.width = screenSize.width;
        frame.setLocation((screenSize.width - frameSize.width) / 2,
      (screenSize.height - frameSize.height) / 2);
        frame.setVisible(true);
       }

       //Main method
        public static void main(String[] args)
       {
        try
        {
         UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        }
        catch(Exception e)
        {
        }
        new Lanzador();

       }
      }



      /* Here comes the class for the server. You need not read the jbInit method */
      import java.awt.*;
      import java.awt.event.*;
      import javax.swing.*;

      import java.net.*;
      import java.io.*;

      public class TfrmPrincipal extends JFrame implements Runnable
      {
       BorderLayout borderLayout1 = new BorderLayout();
       Button cmdAccept = new Button();
       Button cmdClose = new Button();
       TextField edt = new TextField();
       TextArea txa = new TextArea();
       Button cmdSend = new Button();

       ServerSocket ssk;
       Socket sck;
       OutputStreamWriter osw;
       BufferedWriter bw;

       //Construct the frame
        public TfrmPrincipal()
       {
        enableEvents(AWTEvent.WINDOW_EVENT_MASK);
        try
        {
           jbInit();
           ssk = new ServerSocket(5000);
        }
        catch(Exception e)
        {
         e.printStackTrace();
        }
       }

       //Component initialization
       /* You need not to read this method to understand the problem */
        private void jbInit() throws Exception
       {
        cmdAccept.setLabel("Accept");
        cmdAccept.addActionListener(new java.awt.event.ActionListener()
        {

         public void actionPerformed(ActionEvent e)
         {
          cmdAccept_actionPerformed(e);
         }
        });
        this.getContentPane().setLayout(borderLayout1);
        this.setSize(new Dimension(400, 300));
        this.setTitle("sockets trial");
        cmdClose.setLabel("Close");
        cmdClose.addActionListener(new java.awt.event.ActionListener()
        {

         public void actionPerformed(ActionEvent e)
         {
          cmdClose_actionPerformed(e);
         }
        });
        edt.setText("Some text");
        txa.setText("");
        cmdSend.setLabel("send");
        cmdSend.addActionListener(new java.awt.event.ActionListener()
        {

         public void actionPerformed(ActionEvent e)
         {
          cmdSend_actionPerformed(e);
         }
        });
        this.getContentPane().add(cmdAccept, BorderLayout.WEST);
        this.getContentPane().add(edt, BorderLayout.SOUTH);
        this.getContentPane().add(txa, BorderLayout.CENTER);
        this.getContentPane().add(cmdSend, BorderLayout.NORTH);
        this.getContentPane().add(cmdClose, BorderLayout.EAST);
       }

       //Overridden so we can exit on System Close
        protected void processWindowEvent(WindowEvent e)
       {
        super.processWindowEvent(e);
        if(e.getID() == WindowEvent.WINDOW_CLOSING)
        {
         System.exit(0);
        }
       }

       void cmdAccept_actionPerformed(ActionEvent e)
       {
          Thread hiloConexion = new Thread(this);
          hiloConexion.start();
       }

       void cmdClose_actionPerformed(ActionEvent e)
       {
          try
          {
             sck.getOutputStream().close();
             osw.close();
             bw.close();

             sck.setSoLinger(true, 0);
             sck.close();
             txa.append("closed\n");
          }
          catch(Exception ex)
          {
             txa.append(ex.getMessage() + "\n");
             ex.printStackTrace();
          }
       }

       void cmdSend_actionPerformed(ActionEvent e)
       {
          if (sck != null)
          try
          {
             bw.write(edt.getText());
      // bw.flush();
             bw.newLine();
             bw.flush();

             txa.append("String '" + edt.getText() + "' sent\n");
          }
          catch(Exception ex)
          {
             ex.printStackTrace();
          }
       }

         public void run()
         {
            try
            {
               sck = ssk.accept();
               txa.append("concected\n");
               osw = new OutputStreamWriter(sck.getOutputStream());
               bw = new BufferedWriter(osw);
            }
            catch(Exception ex)
            {
               txa.append(ex.getMessage() + "\n");
               ex.printStackTrace();
            }
         }
      }





      /* And here comes the class for the client. You need not read the jbInit method
      */

      import java.awt.*;
      import javax.swing.*;
      import java.awt.event.*;

      import java.net.*;
      import java.io.*;

      public class TfrmSecundaria extends JFrame implements Runnable
      {
       Panel panel1 = new Panel();
       Button cmdConnect = new Button();
       BorderLayout borderLayout1 = new BorderLayout();
       Button cmdReceive = new Button();
       JTextField edt = new JTextField();

       InputStreamReader isr;
       BufferedReader br;
         Socket sck;
       TextArea txa = new TextArea();
       Button cmdClose = new Button();

         public TfrmSecundaria()
         {
            try
            {
             jbInit();
             setSize(400, 400);
             setVisible(true);
            }
            catch(Exception e)
            {
             e.printStackTrace();
            }
         }


       private void jbInit() throws Exception
       {
        cmdConnect.setLabel("Connect");
        cmdConnect.addActionListener(new java.awt.event.ActionListener()
        {

         public void actionPerformed(ActionEvent e)
         {
          cmdConnect_actionPerformed(e);
         }
        });
        panel1.setLayout(borderLayout1);
        cmdReceive.setLabel("Receive");
        cmdReceive.addActionListener(new java.awt.event.ActionListener()
        {

         public void actionPerformed(ActionEvent e)
         {
          cmdReceive_actionPerformed(e);
         }
        });
        edt.setText("some thing");
        txa.setText("");
        cmdClose.setLabel("close");
        cmdClose.addActionListener(new java.awt.event.ActionListener()
        {

         public void actionPerformed(ActionEvent e)
         {
          cmdClose_actionPerformed(e);
         }
        });
        this.getContentPane().add(panel1, BorderLayout.CENTER);
        panel1.add(cmdConnect, BorderLayout.WEST);
        panel1.add(cmdReceive, BorderLayout.EAST);
        panel1.add(edt, BorderLayout.NORTH);
        panel1.add(cmdClose, BorderLayout.SOUTH);
        panel1.add(txa, BorderLayout.CENTER);
       }

       void cmdConnect_actionPerformed(ActionEvent e)
       {
             try
             {
                sck = new Socket("127.0.0.1", 5000);
                txa.append("coneected\n");
             }
             catch(Exception ex)
             {
                txa.append(ex.getMessage() + "\n");
                ex.printStackTrace();
             }
       }

       void cmdReceive_actionPerformed(ActionEvent e)
       {
          Thread hiloConexion = new Thread(this);
          hiloConexion.start();
       }

          public void run()
          {
             String sCadena = "";
             try
             {
                if (sck != null)
                {
                   isr = new InputStreamReader( sck.getInputStream());
                   br = new BufferedReader(isr);
                   while(sCadena != null)
                   {
                      sCadena = br.readLine();
                      txa.append(sCadena + "\n");

                   }
                   txa.append("finished\n");
                   sck.close();
                }
             }
             catch(Exception ex)
             {
                txa.append(ex.getMessage() + "\n");
                ex.printStackTrace();
             }
          }

       void cmdClose_actionPerformed(ActionEvent e)
       {
          try
          {
             sck.setSoLinger(true, 50);
             sck.close();
             txa.append("closed\n");
          }
          catch(Exception ex)
          {
             txa.append(ex.getMessage() + "\n");
             ex.printStackTrace();
          }
       }
      }
      (Review ID: 130207)
      ======================================================================

      Name: nt126004 Date: 08/20/2001


      java version "1.3.0"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
      Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)

      1- Start a server listening for incoming socket connections.
      2- Start a client connecting to the above server.
      3- The client writes to the socket, the server reads from the socket.
      4- At some point, the server closes the socket.
      5- The first client write + flush after server socket closing does not report
      any failure. Most of the time (but some times we have to wait for the third
      write + flush) the second write throws an exception: "java.net.SocketException:
      Connection aborted by peer: socket write error", which we think should be
      reported by the first write + flush operation.

      Here is the source code we wrote to simply reproduce the problem:


      import java.io.*;
      import java.net.*;

      public class TestSocket
      {
          /**
           * The main routine.
           */
          
          public static void main(String strArguments[]) throws Exception
          {
              //
              // Create the server
              //
              
              ServerSocket server = new ServerSocket(25000);
              
              //
              // Create and start the client thread.
              //
              
              Thread thread = new ClientThread();
              thread.start();

              //
              // Read info coming from the client.
              //
              
              Socket socket = server.accept();
              InputStream in = socket.getInputStream();
              
              for (int i = 1; i <= 5; i++)
              {
                  System.out.println("Read attempt " + i + ": " + in.read());
              }
              
              //
              // Close everything.
              //
              
              in.close();
              socket.shutdownInput();
              socket.shutdownOutput();
              socket.close();
              server.close();
              System.out.println("Socket closed on server side");
              
              //
              // Wait for client thread to end.
              //
              
              thread.join();
              System.out.println("Exiting...");
          }
          
          /**
           * The client thread.
           */
          
          private static class ClientThread extends Thread
          {
              public void run()
              {
                  try
                  {
                      Socket socket = new Socket("localhost", 25000);
                      OutputStream out = socket.getOutputStream();

                      for (int i = 1; i <= 1000; i++)
                      {
                          System.out.println("Write attempt " + i);
                          out.write(0);
                          out.flush();
                          Thread.sleep(5000);
                      }
                      
                      out.close();
                      socket.close();
                  }
                  catch (Exception exception)
                  {
                      exception.printStackTrace();
                  }
              }
          }
      }


      The output of this program is the following:

      Write attempt 1
      Read attempt 1: 0
      Write attempt 2
      Read attempt 2: 0
      Write attempt 3
      Read attempt 3: 0
      Write attempt 4
      Read attempt 4: 0
      Write attempt 5
      Read attempt 5: 0
      Socket closed on server side
      Write attempt 6
      Write attempt 7
      java.net.SocketException: Connection aborted by peer: socket write error
              at java.net.SocketOutputStream.socketWrite(Native Method)
              at java.net.SocketOutputStream.write(SocketOutputStream.java:62)
              at com.temenos.icc.ifc.net.TestInterruptableSocket$ClientThread.run
      (TestInterruptableSocket.java:80)
      Exiting...
      (Review ID: 130300)
      ======================================================================

            michaelm Michael McMahon
            nthompsosunw Nathanael Thompson (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: