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

An RMII call can hang forever

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P4 P4
    • None
    • 1.3.0
    • core-libs
    • sparc
    • solaris_2.5.1



      Name: md23716 Date: 11/29/2000

      A similar problem was discussed in the SUN's rmi-users forum under
      the thread " "RMI methods that don't return".
      The solutions proposed are:
      1. Having separate threads for RMI calls and monitor them - This is
            not feasible as it involves lots of overhead.
      2. Have the client implement a timeout/watchdog mechanism -Also not
            feasible since the code is too complex to implement and there are
            TOO MANY places to take care of.
      3. Work around is to have control over the ports used by RMI stuff
            - Also not feasible with the customer.
      The customer has suggested to implement a time out at the low level
      code, where the handshaking occurs. The timeout can be a Java property
      that, if not set, people will see the default no timeout behavior. If
      the property is set, the customers will be responsible for what they
      do.

      // To test what'd happen to a remote reference if the object on the remote
      // site is taken down.
      //
      // What we will test is (1) the remote port is unused now, and (2) the
      // remote port is not being served by someone else.
      //
      // We will use an existing remote reference after the remote object is gone,
      // and deserialization a remote reference after the remoteobject is gone.
      import java.rmi.registry.*;
      import java.rmi.*;
      import java.rmi.server.*;

      public class testServer extends UnicastRemoteObject
                              implements Service
      {
        public testServer() throws RemoteException
        {
        }

        public static void main(String[] args)
        {
          try
          {
            // Bind ourselves as service in a remote RMI registry
            Registry remoteRegistry = LocateRegistry.getRegistry(args[0], 14000);

            if ((args.length > 0) && (args[0].equals("-unbind")))
            {
              remoteRegistry.unbind("Test");
              System.out.println("Server unbound....");
              System.exit(0);
            }
            else
            {
              remoteRegistry.rebind("Test", new testServer());
              System.out.println("Server started....");
            }
          }
          catch (Exception e)
          {
            System.out.println(e);
            e.printStackTrace();
          }
        }

        public String service() throws RemoteException
        {
          return "There you go....";
        }
      }

      interface Service extends Remote
      {
        public String service() throws RemoteException;
      }

      1. Compile the code (do 'javac *.java'). Then run 'rmic testServer'. Make sure
         . is in the CLASSPATH.

      2. Start the rmiregistry at port 14000. The port # is hard coded.

      3. start the test server: java testServer <your_host>. For example,
         'java testServer dcertp70'. It should say 'Server started....'.

      4. In a different shell, start the test client: java testClient <your_host>. For
         example, 'java testClient dcertp70'. You should see the following output:

           Remote object 1: testServer_Stub[RemoteStub [ref: [endpoint:[dcertp70:44115](remote),objID:[6008fab:dcb278bb57:-8000, 0]]]]
           Remote object 2: testServer_Stub[RemoteStub [ref: [endpoint:[dcertp70:44115](remote),objID:[6008fab:dcb278bb57:-8000, 0]]]]
           Remote object 3: testServer_Stub[RemoteStub [ref: [endpoint:[dcertp70:44115](remote),objID:[6008fab:dcb278bb57:-8000, 0]]]]
           Remote object 4: testServer_Stub[RemoteStub [ref: [endpoint:[dcertp70:44115](remote),objID:[6008fab:dcb278bb57:-8000, 0]]]]
           Calling the remote1.service() method...
           There you go....
           Calling the remote2.service() method...
           There you go....
           Calling the remote3.service() method...
           There you go....
           Calling the remote4.service() method...
           There you go....
           Saving serialized remote2..
           Saving serialized remote4..
           Remove the Server object now. And hit <ENTER>

         Note the port number, which we will use later. In the above output, it is
         44115.

      5. Kill the server.

      6. Hit <ENTER> on the client, you should see

           Test if the previously obtained remote reference
           is still functioning
           Remote object 1: testServer_Stub[RemoteStub [ref: [endpoint:[dcertp70:44115](remote),objID:[6008fab:dcb278bb57:-8000, 0]]]]
           Calling the remote1.service() method again
           java.rmi.ConnectException: Connection refused to host: [dcertp70:44115]; nested exception is:
                   java.net.ConnectException: A remote host refused an attempted connect operation.
                   at sun.rmi.transport.tcp.TCPChannel.openSocket(TCPChannel.java:264)
                   at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:132)
                   at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:73)
                   at testServer_Stub.service(testServer_Stub.java:27)
                   at testClient.main(testClient.java:74)
           Test if the previously serialized obtained remote
           reference is still functioning
           Reading serialized remote2
           Remote object 2: testServer_Stub[RemoteStub [ref: [endpoint:[dcertp70:44115](remote),objID:[6008fab:dcb278bb57:-8000, 0]]]]Calling the remote2.service() method again
           java.rmi.ConnectException: Connection refused to host: [dcertp70:44115]; nested exception is:
                   java.net.ConnectException: A remote host refused an attempted connect operation.
                   at sun.rmi.transport.tcp.TCPChannel.openSocket(TCPChannel.java:264)
                   at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:132)
                   at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:73)
                   at testServer_Stub.service(testServer_Stub.java:27)
                   at testClient.main(testClient.java:95)
           Run bogusSocket now and give the port # as parameter. And then hit <ENTER>

         We got exception because the server is gone (and nobody listening on port
         44115).

      7. Start the bogusSocket by doing 'java bogusSocket <port_number>'. In the above
         example, we should type in 'java bogusServer 44115'. This bogus server only
         reads from the socket but never responds. I want to demonstrate the problem
         of the RMI calls if the remote reference isn't responding. Now for the
         client, hit the ENTER. You will see

           Test if the previously obtained remote reference
           is still functioning
           Remote object 3: testServer_Stub[RemoteStub [ref: [endpoint:[dcertp70:44565](remote),objID:[6008fab:dcb2802a0c:-8000, 0]]]]
           Calling the remote3.service() method again

         And the client is hung (stuck in getting responses from the Server).


      8. Kill the Client. And start the testBogusSocket
         'java testBogusSocket <your_host> <port_number>'. For example,
         'java testBogusSocket dcertp70 44115'. The testBogusSocket will hang (in
         reading results from bogusSocket).

      9. Kill the testBogusSocket. Then restart it with one additional parameter
          'true'. For example, 'java testBogusSocket dcertp70 44115 true'. This will
          set a time out on socket read() for 5 sec. Wait for 5 seconds, you will see
          the InterruptedException with message saying

            "Read Time out"
            java.io.InterruptedIOException: Read timed out
                   at java.net.SocketInputStream.read(SocketInputStream.java:92)
                   at java.net.SocketInputStream.read(SocketInputStream.java:75)
                   at testBogusSocket.main(testBogusSocket.java:33)

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

      public class testBogusSocket
      {
        public static void main(String[] args)
        {
          boolean timeout = false;
          try
          {
            Socket connection = new Socket(args[0], Integer.parseInt(args[1]));

            if (args.length > 2)
              timeout = new Boolean(args[2]).booleanValue();
          
            // now read in a huge file and send it over to the TServer
            OutputStream out = connection.getOutputStream();

            // we don't count the above two overhead
            long startTime = System.currentTimeMillis();
            byte[] buffer = new byte[] {'x', 'y', 'z'};
            int bytesRead;
            
            out.write(buffer);

            // now the server won't respond. So let's set a timeout to make sure
            // we get a response in a timely fashion. Timeout in ms. Let's wait
            // for at most 5 sec. We should get a InterruptedException.
            if (timeout)
              connection.setSoTimeout(5000);

            InputStream in = connection.getInputStream();
            in.read(buffer);
          }
          catch (Exception e)
          {
            e.printStackTrace();
          }
        }
      }

      // Let's have two references for the
      import java.rmi.registry.*;
      import java.rmi.*;
      import java.rmi.server.*;
      import java.io.*;

      public class testClient
      {
        public static void main(String[] args)
        {
        String urlremote2;
          Remote remote1 = null,
                 remote2 = null,
                 remote3 = null,
                 remote4 = null;

          String file1 = "file1", file2 = "file2";
          try
          {
            String url = "rmi://" + args[0] + ":14000/Test";
            // Now we want to see whether we can get this service via Remote RMI
            // registry
            remote1 = Naming.lookup(url);
            remote2 = Naming.lookup(url);
            urlremote2 = "rmi://" + args[0] + ":14000/"+remote2;
            Naming.bind(urlremote2,remote2);
            remote3 = Naming.lookup(url);
            remote4 = Naming.lookup(url);
            
            System.out.println("Remote object 1: " + remote1);
            System.out.println("Remote object 2: " + remote2);
            System.out.println("Remote object 3: " + remote3);
            System.out.println("Remote object 4: " + remote4);
            
            System.out.println("Calling the remote1.service() method...");
            System.out.println(((Service)remote1).service());
            System.out.println("Calling the remote2.service() method...");
            System.out.println(((Service)remote2).service());
            System.out.println("Calling the remote3.service() method...");
            System.out.println(((Service)remote3).service());
            System.out.println("Calling the remote4.service() method...");
            System.out.println(((Service)remote4).service());
            
            // serializing remote2...
            System.out.println("Saving serialized remote2..");
            FileOutputStream fos = new FileOutputStream(file1);
            ObjectOutputStream out = new ObjectOutputStream(fos);
            out.writeObject(remote2);
            out.flush();
            out.close();

            // serializing remote4...
            System.out.println("Saving serialized remote4..");
            fos = new FileOutputStream(file2);
            out = new ObjectOutputStream(fos);
            out.writeObject(remote4);
            out.flush();
            out.close();

            System.out.println("Remove the Server object now. And hit <ENTER>");

            LineNumberReader in = new LineNumberReader(new InputStreamReader(System.in));

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

          try
          {
            System.out.println("Test if the previously obtained remote reference");
            System.out.println("is still functioning");
            System.out.println("Remote object 1: " + remote1);
            System.out.println("Calling the remote1.service() method again");
            System.out.println(((Service)remote1).service());
          }
          catch (Exception e)
          {
            e.printStackTrace();
          }

          try
          {
            System.out.println("Test if the previously serialized obtained remote");
            System.out.println("reference is still functioning");

            // deseriablizing....
            System.out.println("Reading serialized remote2");
            FileInputStream fis = new FileInputStream(file1);
            ObjectInputStream oi = new ObjectInputStream(fis);
            remote2 = (Remote)oi.readObject();
            oi.close();

            urlremote2 = "rmi://" + args[0] + ":14000/"+remote2;
            remote2 = Naming.lookup(urlremote2);
            System.out.println("Remote object 2: " + remote2);
            System.out.println("Calling the remote2.service() method again");
            System.out.println(((Service)remote2).service());
          }
          catch (Exception e1)
          {
            e1.printStackTrace();
          }

          try
          {
            System.out.println("Run bogusSocket now and give the port # as parameter. And then hit <ENTER>");
            
            LineNumberReader in = new LineNumberReader(new InputStreamReader(System.in));
            
            in.readLine();

            System.out.println("Test if the previously obtained remote reference");
            System.out.println("is still functioning");
            System.out.println("Remote object 3: " + remote3);
            System.out.println("Calling the remote3.service() method again");
            System.out.println(((Service)remote3).service());
          }
          catch (Exception e2)
          {
            e2.printStackTrace();
          }

          try
          {
            System.out.println("Test if the previously serialized obtained remote");
            System.out.println("reference is still functioning");

            // deseriablizing....
            System.out.println("Reading serialized remote4");
            FileInputStream fis = new FileInputStream(file2);
            ObjectInputStream oi = new ObjectInputStream(fis);
            remote4 = (Remote)oi.readObject();
            oi.close();

            System.out.println("Remote object 4: " + remote4);
            System.out.println("Calling the remote4.service() method again");
            System.out.println(((Service)remote4).service());
          }
          catch (Exception e3)
          {
            e3.printStackTrace();
          }

        }
      }

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

      public class bogusSocket
      {
        public static void main(String[] args)
        {
          try
          {
            ServerSocket server = new ServerSocket(Integer.parseInt(args[0]));
            
            while (true)
            {
              Socket connection = server.accept();
              
              // now let's get the Socket InputStream.
              InputStream in = connection.getInputStream();
              byte[] buffer = new byte[2000];
              int bytesRead;
              
              while ((bytesRead = in.read(buffer)) >= 0)
              {
                System.out.print(new String(buffer));
              }
            }
          }
          catch (Exception e)
          {
            e.printStackTrace();
          }
        }
      }


      4. Targeted FCS Release

      Merlin

      5. Suggested Fix:

      6.1 Suggested Fix
      If an earlier socket is used by some non RMI code, then there
              should be some mechanism to notify the clients about this so
              that the clients doesn't hang.
      ======================================================================

            Unassigned Unassigned
            mdevereuorcl Michelle Devereux (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: