<p>In our application, we are using RMI for client-server communication in very different ways:</p>

<ol>
<li>Pushing data from the server to the client to be displayed.</li>
<li>Sending control information from the client to the server.</li>
<li>Callbacks from those control messages code paths that reach back from the server to the client (sidebar note - this is a side-effect of some legacy code and is not our long-term intent).</li>
</ol>

<p>What we would like to do is ensure that all of our RMI-related code will use only a known specified inventory of ports.  This includes the registry port (commonly expected to be 1099), the server port and any ports resulting from the callbacks.</p>

<p>Here is what we already know:</p>

<ol>
<li>LocateRegistry.getRegistry(1099) or Locate.createRegistry(1099) will ensure that the registry is listening in on 1099.</li>
<li>Using the UnicastRemoteObject constructor / exportObject static method with a port argument will specify the server port.</li>
</ol>

<p>These points are also covered in this <a href="http://forums.sun.com/thread.jspa?threadID=370039&amp;messageID=1566073" rel="noreferrer">Sun forum post</a>. </p>

<p>What we don't know is: how do we ensure that the client connections back to the server resulting from the callbacks will only connect on a specified port rather than defaulting to an anonymous port?</p>

<p>EDIT: Added a longish answer summarizing my findings and how we solved the problem.  Hopefully, this will help anyone else with similar issues.</p>

<p>SECOND EDIT: It turns out that in my application, there seems to be a race condition in my creation and modification of socket factories.  I had wanted to allow the user to override my default settings in a Beanshell script.  Sadly, it appears that my script is being run significantly after the first socket is created by the factory.  As a result, I'm getting a mix of ports from the set of defaults and the user settings.  More work will be required that's out of the scope of this question but I thought I would point it out as a point of interest for others who might have to tread these waters at some point....</p>

[{'answer_id': 56701, 'author': 'David Webb', 'author_id': 3171, 'author_profile': 'https://Stackoverflow.com/users/3171', 'pm_score': 3, 'selected': True, 'text': '<p>You can do this with a custom RMI Socket Factory.  </p>\n\n<p>The socket factories create the sockets for RMI to use at both the client and server end so if you write your own you\'ve got full control over the ports used.  The client factories are created on the server, Serialized and then sent down to the client which is pretty neat.</p>\n\n<p><a href="http://docs.oracle.com/javase/7/docs/technotes/guides/rmi/socketfactory/" rel="nofollow noreferrer">Here\'s a guide at Sun telling you how to do it.</a></p>\n'}, {'answer_id': 303081, 'author': 'Bob Cross', 'author_id': 5812, 'author_profile': 'https://Stackoverflow.com/users/5812', 'pm_score': 1, 'selected': False, 'text': '<p>Summary of the long answer below: to solve the problem that I had (restricting server and callback ports at either end of the RMI connection), I needed to create two pairs of client and server socket factories.</p>\n\n<p>Longer answer ensues:</p>\n\n<p>Our solution to the callback problem had essentially three parts.  The first was the object wrapping which needed the ability to specify that it was being used for a client to server connection vs. being used for a server to client callback.  Using an extension of <code>UnicastRemoteObject</code> gave us the ability to specify the client and server socket factories that we wanted to use.  However, the best place to lock down the socket factories is in the constructor of the remote object.  </p>\n\n<pre><code>public class RemoteObjectWrapped extends UnicastRemoteObject {\n// ....\nprivate RemoteObjectWrapped(final boolean callback) throws RemoteException {\n  super((callback ? RemoteConnectionParameters.getCallbackPort() : RemoteConnectionParameters.getServerSidePort()),\n        (callback ? CALLBACK_CLIENT_SOCKET_FACTORY : CLIENT_SOCKET_FACTORY),\n        (callback ? CALLBACK_SERVER_SOCKET_FACTORY : SERVER_SOCKET_FACTORY));\n}\n// ....\n}\n</code></pre>\n\n<p>So, the first argument specifies the part on which the object is expecting requests, whereas the second and third specify the socket factories that will be used at either end of the connection driving this remote object.</p>\n\n<p>Since we wanted to restrict the ports used by the connection, we needed to extend the RMI socket factories and lock down the ports.  Here are some sketches of our server and client factories:</p>\n\n<pre><code>public class SpecifiedServerSocketFactory implements RMIServerSocketFactory {\n/** Always use this port when specified. */\nprivate int serverPort;\n/**\n * @param ignoredPort This port is ignored.  \n * @return a {@link ServerSocket} if we managed to create one on the correct port.\n * @throws java.io.IOException\n */\n@Override\npublic ServerSocket createServerSocket(final int ignoredPort) throws IOException {\n    try {\n        final ServerSocket serverSocket = new ServerSocket(this.serverPort);\n        return serverSocket;\n    } catch (IOException ioe) {\n        throw new IOException("Failed to open server socket on port " + serverPort, ioe);\n    }\n}\n// ....\n}\n</code></pre>\n\n<p>Note that the server socket factory above ensures that only the port that you previously specified will ever be used by this factory.  The client socket factory has to be paired with the appropriate socket factory (or you\'ll never connect).</p>\n\n<pre><code>public class SpecifiedClientSocketFactory implements RMIClientSocketFactory, Serializable {\n/** Serialization hint */\npublic static final long serialVersionUID = 1L;\n/** This is the remote port to which we will always connect. */\nprivate int remotePort;\n/** Storing the host just for reference. */\nprivate String remoteHost = "HOST NOT YET SET";\n// ....\n/**\n * @param host The host to which we are trying to connect\n * @param ignoredPort This port is ignored.  \n * @return A new Socket if we managed to create one to the host.\n * @throws java.io.IOException\n */\n@Override\npublic Socket createSocket(final String host, final int ignoredPort) throws IOException {\n    try {\n        final Socket socket = new Socket(host, remotePort);\n        this.remoteHost = host;\n        return socket;\n    } catch (IOException ioe) {\n        throw new IOException("Failed to open a socket back to host " + host + " on port " + remotePort, ioe);\n    }\n}\n// ....\n}\n</code></pre>\n\n<p>So, the only thing remaining to force your two way connection to stay on the same set of ports is some logic to recognize that you are calling back to the client-side.  In that situation, just make sure that your factory method for the remote object calls the RemoteObjectWrapper constructor up top with the callback parameter set to true.</p>\n'}, {'answer_id': 2455094, 'author': 'Iraklis', 'author_id': 172467, 'author_profile': 'https://Stackoverflow.com/users/172467', 'pm_score': 0, 'selected': False, 'text': '<p>I\'ve been having various problems implementing an RMI Server/Client architecture, with Client Callbacks. My scenario is that both Server and Client are behind Firewall/NAT. In the end I got a fully working implementation. Here are the main things that I did:</p>\n\n<h2>Server Side , Local IP: 192.168.1.10. Public (Internet) IP 80.80.80.10</h2>\n\n<p>On the Firewall/Router/Local Server PC open port 6620.\nOn the Firewall/Router/Local Server PC open port 1099.\nOn the Router/NAT redirect incoming connections on port 6620 to 192.168.1.10:6620\nOn the Router/NAT redirect incoming connections on port 1099 to 192.168.1.10:1099</p>\n\n<p>In the actual program:</p>\n\n<pre><code>System.getProperties().put("java.rmi.server.hostname", IP 80.80.80.10);\nMyService rmiserver = new MyService();\nMyService stub = (MyService) UnicastRemoteObject.exportObject(rmiserver, 6620);\nLocateRegistry.createRegistry(1099);\nRegistry registry = LocateRegistry.getRegistry();\nregistry.rebind("FAManagerService", stub);\n</code></pre>\n\n<h2>Client Side, Local IP: 10.0.1.123 Public (Internet) IP 70.70.70.20</h2>\n\n<p>On the Firewall/Router/Local Server PC open port 1999.\nOn the Router/NAT redirect incoming connections on port 1999 to 10.0.1.123:1999</p>\n\n<p>In the actual program:</p>\n\n<pre><code>System.getProperties().put("java.rmi.server.hostname", 70.70.70.20);\nUnicastRemoteObject.exportObject(this, 1999);\nMyService server = (MyService) Naming.lookup("rmi://" + serverIP + "/MyService ");\n</code></pre>\n\n<p>Hope this helps.\nIraklis</p>\n'}, {'answer_id': 37356737, 'author': 'user207421', 'author_id': 207421, 'author_profile': 'https://Stackoverflow.com/users/207421', 'pm_score': 2, 'selected': False, 'text': "<p>You don't need socket factories for this, or even multiple ports. If you're starting the Registry from your server JVM you can use port 1099 for everything, and indeed that is what will happen by default. If you're not starting the registry at all, as in a client callback object, you can provide port 1099 when exporting it.</p>\n\n<p>The part of your question about 'the client connections back to the server resulting from callbacks' doesn't make sense. They are no different from the original client connections to the server, and they will use the same server port(s).</p>\n"}]
['https://Stackoverflow.com/questions/56687', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/5812/']