Qu0ll said:
I understand that RMI doesn't play well with the internet because it can't
work properly when either the client or the server is behind a proxy unless
tunneling is used and that tunneling is slow and prevents callbacks from
being used. So I get it that RMI is probably not the network API for me.
RMI plays perfectly well with the Internet, but not firewalls. I think RMI works
in a very similar way to portmapper. The rmiregistry listens on a well-known
port. A RMI server registers its service with the rmiregistry, and is either
assigned or tells the registry the port that it actually listen on. A RMI
client asks the rmiregistry for the "location" of a particular service, and the
rmiregistry replies telling the client what host/port the server is listening
on.
For the above to work through a firewall the client must be able to connect to
the server both on the rmiregistry port and the port on which the server is
listening. This will normally cause problems with firewalls because they are
not configured to allow this to happen for dynamic ports. It may be possible
for an RMI server to request a specific port and register that, but I'm not
certain (RMISocketFactory.createServerSocket(int port)?). That way it might be
possible to open only the rmiregistry port and the specific RMI server ports in
the firewall.
And I understand that servlets don't have this problem because they
communicate through the standard HTTP port but that servlets don't support
callbacks for non-HTML clients. (Feel free to disagree if appropriate).
Servlets can communicate via any port. The initial connection is made to the
servlet container on whatever port that happens to be listening on. It may be
80, or 8080 or any other port. The socket is passed to the servlet's service
routine and the servlet can send a reply on that already established socket.
There is no requirement for communication to be HTTP unless you extend
HttpServlet. A GenericServlet can use any protocol (layered over TCP/IP).
Servlets can also open any other socket they wish, including initiating callback
to a client. If you do this in the service method you are likely to get
deadlock if the servlet attempts to initiate a new communication channel with
the client whilst the client is waiting for the servlet to respond to its
initial request. You would have to handle this carefully.
You could also start a background thread in the servlet. The background thread
could open a socket to the client and send data when it was ready. The client
would have to be listening to accept the connection and be able to read the
data. But with this method you are at the mercy of the servlet container as it
may decide to unload the servlet if it doesn't received any new service calls.
The simplest method is to use blocking calls. The client makes a service request
to the servlet as normal, but the servlet does not return until there is
something to return. This would presumably require a separate thread in the
client to wait for that service call to return so the main processing of the
client could continue. You would also create one thread per client request in
the servlet, which might also cause problems. However, it requires no
connection from the server back to the client, and maybe your best bet for
getting around the proxy/firewall problem.
Which leads me back to NIO. Does it suffer the same problems as RMI?
Namely, will it play well if the client is behind a proxy? If so, why is it
that RMI can't and NIO can?
I have no experience of proxies so can't help here.