views:

145

answers:

2

For those who do not want to read a long question here is a short version:

A server has an opened socket for a client. The server gets a request to open a socket from the same client-IP and client-port. I want to fore the server not to refuse such a request but to close the old socket and open a new one. How can I do ti?


And here is a long (original) question:

I have the following situation. There is an established connection between a server and client. Then an external software (Bonjour) says to my client the it does not see the server in the local network. Well, client does nothing about that because of the following reasons:

  1. If Bonjour does not see the server it does not necessarily means that client cannot see the server.

  2. Even if the client trusts the Bonjour and close the socket it does not improve the situation ("to have no open socket" is worser that "to have a potentially bad socket").

So, client do nothing if server becomes invisible to Bonjour. But than the server re-appears in the Bonjour and Bonjour notify the client about that. In this situation the following situations are possible:

  1. The server reappears on a new IP address. So, the client needs to open a new socket to be able to communicate with the server.

  2. The server reappears on the old IP address. In this case we have two subcases:

2.1. The server was restarted (switched off and then switched on). So, it does not remember the old socket (which is still used by the client). So, client needs to close the old socket and open a new one (on the same server-IP address and the same server-port).

2.2. We had a temporal network problem and the server was running the whole time. So, the old socket is still available for the use. In this case the client does not really need to close the old socket and reopen a new one.

But to simplify my life I decide to close and reopen the socket on the client side in any case (in spite on the fact that it is not really needed in the last described situation).

But I can have problems with that solution. If I close the socket on the client side and than try to reopen a socket from the same client-IP and client-port, server will not accept the call for a new socket. The server will think that such a socket already exists.

Can I write the server in such a way, that it does not refuse such calls. For example, if it (the server) sees that a client send a request for a socket from the same client-IP and client-port, it (server) close the available socket, associated with this client-IP and client-port and than it reopens a new socket.

A: 

You can't "reopen" a socket on your server. If the socket already exists and the client is trying to reconnect then you should get an BindException (see your previous question). The scenario that may be possible:

  • Client Shuts down socket
  • Server OS "notices" socket is dead on client side and shuts its side down
  • Client reconnects on the same port, but with a "new" socket

In this case you may consider it be the "same" socket, but it really isn't. That said a strategy you may wish to adopt is to have some sort of map (hash of client IP/port) to whatever mechanism you are using to service the socket or some kind of persistent state data, so that it can simulate a continuation of a previous socket (in the same vein as http sessioning). Something along the lines of:

HashMap<Client, State> sessions = ...;

public void server(){
  ...
  while(true){
    Socket socket = server.accept();
    Client client = new Client(socket);
    State s = sessions.get(client);
    if(s == null){
      s = new State();
      sessions.put(client, s);
    }
    client.setState(s);
    service(client);
  }
  ...
}

and you can adjust the map lookup to define what a "session" means within your application (same client IP, same client IP & client port, some sessionid sent over the wire, etc).

If you are just trying to make it possible for the client to reconnect and force the server to "notice" the client is disconnected, the only real way in Java is to try and read/write data, and if it has been shutdown then it should throw an exception. Therefore as was mentioned in your other question you could add some kind of ack/nak feature to your protocol and add some type of check if you believe the client is disconnected (for example if you haven't read any data in the last N milliseconds, send a message the client must echo within M milliseconds, otherwise it is assumed to be disconnected). You can also try isConnected, isInputShutdown, isOutputShutdown, but I have found those to be unreliable in my own code to indicate the socket state, unless you have closed the socket (i.e. the one you are testing on the server).

M. Jessup
A: 

Based on the comments:

You cannot write the server in a way that it will close a socket it still thinks is connected and automatically accept the new connection, as application code does not have that kind of control over the TCP stack, nor is there a way to reopen a connection.

The chance of the port numbers being the same between your client restarts is very small.

But still, if that happens, the server will note that that you're trying to set up an already connected socket, and refuse your new connection. There's not much else your client can do in this case besides close your socket, create a new one and try to connect again - and another random port will be selected.

additional note, your server should take some form of action to detect and close dead sockets, if all your server does is read incoming data, the "dead" sockets will never be closed as they will never be detected as dead.(enabling tcp keepalive is one cheap measure to take against dead sockets staying up for months, though it will take a couple of hours to detect them as such by default.)

nos
Why these dead socket will stay for months? With my test applications I found out that if client close a socket, the server will "notice" that in less than one minute. I do not know how it works (what exactly close the server socket) but as a matter of fact, in less than one minute server forgets about such a socket.
Roman
Depends on what your server do, e.g. if it has some timeouts, if it sends heartbeats, or sends something to the sockets every now and then - it will likely detect the client is gone. If all you do is read from the client and, say, you unplug a network cable somewhere inbetween the client and server, and reboot the client - how is the server ever going to know that socket is dead ?
nos