Should I close sockets from both ends? - java

I have the following problem. My client program monitor for availability of server in the local network (using Bonjour, but it does not rally mater). As soon as a server is "noticed" by the client application, the client tries to create a socket: Socket(serverIP,serverPort);.
At some point the client can loose the server (Bonjour says that server is not visible in the network anymore). So, the client decide to close the socket, because it is not valid anymore.
At some moment the server appears again. So, the client tries to create a new socket associated with this server. But! The server can refuse to create this socket since it (server) has already a socket associated with the client IP and client port. It happens because the socket was closed by the client, not by the server. Can it happen? And if it is the case, how this problem can be solved?
Well, I understand that it is unlikely that the client will try to connect to the server from the same port (client port), since client selects its ports randomly. But it still can happen (just by chance). Right?

Yes, close the socket, as soon as you detect a failure.
The socket will be "stuck" in "close_wait" if not closed properly.
Even if the socket is closed, it's state will be in time_wait for a short period.
However, if You design the application to use a different local port for each new connection, there is no need to wait for the old socket to be closed.
(As you are then creating a completly different socket, since a socket is identified by the remote-ip, remote port, local ip and local port.)

A quick/ dirty illustration of why this can't happen (note the client forcibly uses the same local port in its connection):
public class Server{
public static void main(String[] args) throws Exception {
new Thread(){
java.net.ServerSocket server = new java.net.ServerSocket(12345);
java.util.ArrayList<java.net.Socket> l = new java.util.ArrayList<java.net.Socket>();
public void run() {
try{
while(true){
java.net.Socket client = server.accept();
System.out.println("Connection Accepted: S: "+client.getLocalPort()+", C: "+client.getPort());
l.add(client);
}
}catch(Exception e){e.printStackTrace();}
}
}.start();
}
and a client (replace server address with something valid):
import java.net.InetAddress;
import java.net.Socket;
public class SocketTest {
public static void main(String[] args) throws Exception {
InetAddress server = InetAddress.getByName("192.168.0.256");
InetAddress localhost = InetAddress.getLocalHost();
Socket s = new Socket(server, 12345, localhost, 54321);
System.out.println("Client created socket");
s.close();
s = null;
System.gc();
System.gc();
Thread.sleep(1000);
s = new Socket(server, 12345, localhost, 54321);
System.out.println("Client created second socket");
s.close();
System.exit(55);
}
}
If you start the server and then try to run the client the first connection will succeed, but the second will fail with a "java.net.BindException: Address already in use: connect"

Short answer: yes, you should close socket on both ends.
Although the answer is simple, in reality it may be very hard to detect that the peer has stopped responding if you don't build some ACK/NACK scheme into your client-server protocol.
Even with your protocol ACKs your processing thread may be hanging waiting for ACKs that will never come from the client or vice versa.
If you use Blocking I/O, I would start by setting read timeouts on a socket. Unfortunately, if the peer becomes unresponsive, there is no corresponding time-out for the writes.
One blunt instrument that I found has value in our environment is to create blocking Sockets through java.nio methods and then interrupt the processing thread at configurable intervals.
Interrupting processing thread will close socket, but if you pick the timeout large enough you will know that there is a trouble. We chose this approach because application was written initially with blocking I/O and a cost to transition it to non-blocking was very high.
With the non-blocking I/O, though, you may check at a finer-grained interval the status of your connection and react more intelligently to the slow/unresponsive connections.
Though non-blocking I/O requires a higher upfront investment, I think it will pay better dividends in terms of reliability and better throughput later on.

the client operating system will not allocate the same port to a new socket so soon. there are several mechanism that prevents it. one of which is the TIME_WAIT state that reserves the port for some time after the connection is closed.
I wouldn't worry about it.
if you really need to detect disconnection you will have to implement ping/pong protocol, initiated by both the client and the server.

It sounds like your client is detecting loss of connectivity to the server (using Bonjour), but you don't have the corresponding capability in the other direction.
You're certainly going to want some kind of timeout for inactive connections on the server side as well, otherwise dead connections will hang around forever. Beyond the problem of potential IP address/port # collisions you mention, there's also the fact that the dead connections are consuming OS and application resources (such as open file descriptors)
Conversely, you might also want to consider not being too aggressive in closing a connection from the client side when Bonjour says the service is no longer visible. If you're in a wireless scenario, a transient loss of connectivity isn't that uncommon, and it's possible for a TCP connection to remain open and valid after connectivity is restored (assuming the client still has the same IP address). The optimum strategy depends on what kind of connection you're talking about. If it's a relatively stateless connection where the cost of discarding the connection and retrying is low (like HTTP), then it makes sense to toss the connection at the first sign of trouble. But if it's a long-lived connection with significant user state (like an SSH login session), it makes sense to try harder to keep the connection alive.

If you close server socket only in case of blocking socket then client socket will be closed but not vice versa.
otherwise it would be better socket in both end. Because socket is a heavy weigt for you system. It will use a local port and a remote port of your system forever.
Thanks
Sunil Kumar Sahoo

Related

Android socket connection issues

I am creating a chat application, which runs as a service. I connect to the chat server using a socket, and I declared a timeout using setSoTimeout.
When a connection is idle, (for example when I am at home and connected to WiFi) I never face issues. When I go outside, and my WiFi connection is lost, my phone switches to 3G. The problem is that the socket stays connected without receiving any data. (So the timeout exception isn't called.) < sometimes it connects after 30 mins, but this need to be reduced to at least a few seconds.
I also tried to add a CONNECTIVITY_CHANGE broadcast detector in my AndroidManifest.xml, this also didn't work.
See my socket connection below:
socket = new Socket(proxy);
SocketAddress socketAddress = new InetSocketAddress(HOST,
PORT);
socket.connect(socketAddress);
if (socket.isConnected()) {
socket.setSoTimeout(1020000); //Even when setting to 10000 makes no sense
return true;
} else {
Log.w("WARNING", "Failed to connect to the server");
return false;
}
In the background there are also some loops running which checks the server for chatmessages, these loops triggers a reconnect when no data is received, but this didn't work too. (During reconnect, I set the socket to socket.close() and socket = null before connecting again.)
So are there any ideas, maybe I need to use a different socket? Or some other code to resolve this problem? Thanks.
In such unexpected(as per application's perspective) network disconnection, the socket won't know it was disconnected. If this situation occurs, the only way is to try writing some data to the socket. When the socket is disconnected, writing data would throw IOExcpetion with message like Connection reset.
You'd better implement a heartbeat method to detect the disconnection. A packet sent to server every 5~10 seconds would detect network disconnection speedy enough.

How do i find if (java) socket is still valid? [duplicate]

This question already has answers here:
Java socket API: How to tell if a connection has been closed?
(9 answers)
Closed 5 years ago.
When I'm using e.g. PuTTY and my connection gets lost (or when I do a manual ipconfig /release on Windows), it responds directly and notifies my connection was lost.
I want to create a Java program which monitors my Internet connection (to some reliable server), to log the date/times when my internet fails.
I tried use the Socket.isConnected() method but that will just forever return "true". How can I do this in Java?
Well, the best way to tell if your connection is interrupted is to try to read/write from the socket. If the operation fails, then you have lost your connection sometime.
So, all you need to do is to try reading at some interval, and if the read fails try reconnecting.
The important events for you will be when a read fails - you lost connection, and when a new socket is connected - you regained connection.
That way you can keep track of up time and down time.
Even though TCP/IP is "connection oriented" protocol, normally no data is sent over an idle connection. You can have a socket open for a year without a single bit sent over it by the IP stack. In order to notice that a connection is lost, you have to send some data on the application level.(*) You can try this out by unplugging the phone cable from your ADSL modem. All connections in your PC should stay up, unless the applications have some kind of application level keepalive mechanism.
So the only way to notice lost connection is to open TCP connection to some server and read some data from it. Maybe the most simple way could be to connect to some FTP server and fetch a small file - or directory listing - once in a while. I have never seen a generic server which was really meant to be used for this case, and owners of the FTP server may not like clients doing this.
(*) There is also a mechanism called TCP keepalive but in many OS's you have to activate it for all applications, and it is not really practical to use if you want to notice loss of connection quickly
If the client disconnects properly, a read() will return -1, readLine() returns null, readXXX() for any other X throws EOFException. The only reliable way to detect a lost TCP connection is to write to it. Eventually this will throw an IOException 'connection reset', but it takes at least two writes due to buffering.
Why not use the isReachable() method of the java.net.InetAddress class?
How this works is JVM implementation specific but:
A typical implementation will use ICMP ECHO REQUESTs if the privilege can be obtained, otherwise it will try to establish a TCP connection on port 7 (Echo) of the destination host.
If you want to keep a connection open continually so you can see when that fails you could connect to server running the ECHO protocol yourself rather than having isReachable() do it for you and read and write data and wait for it to fail.
You might want to try looking at the socket timeout interval. With a short timeout (I believe the default is 'infinite timeout') then you might be able to trap an exception or something when the host becomes unreachable.
Okay so I finally got it working with
try
{
Socket s = new Socket("stackoverflow.com",80);
DataOutputStream os = new DataOutputStream(s.getOutputStream());
DataInputStream is = new DataInputStream(s.getInputStream());
while (true)
{
os.writeBytes("GET /index.html HTTP/1.0\n\n");
is.available();
Thread.sleep(1000);
}
}
catch (IOException e)
{
System.out.println("connection probably lost");
e.printStackTrace();
}
Not as clean as I hoped but it's not working if I leave out the os.writeBytes().
You could ping a machine every number of seconds, and this would be pretty accurate. Be careful that you don't DOS it.
Another alternative would be run a small server on a remote machine and keep a connection to it.
Its probably simpler to connect to yahoo/google or somewhere like this.
URL yahoo = new URL("http://www.yahoo.com/");
URLConnection yc = yahoo.openConnection();
int dataLen = yc.getContentLength() ;
Neil
The isConnected()method inside Socket.java class is a little misleading. It does not tell you if the socket is currently connected to a remote host (like if it is unclosed). Instead, it tells you whether the socket has ever been connected to a remote host. If the socket was able to connect to the remote host at all, this method returns true, even after that socket has been closed. To tell if a socket is currently open, you need to check that isConnected() returns true and isClosed() returns false.
For example:
boolean connected = socket.isConnected() && !socket.isClosed();

Handling Multiple TCP Connections In Java (Server-side)

I'm in the process of writing a messaging program, and I'm running into a spot where I'm having trouble understanding how to pass a socket over to a new thread for handling outbound messages via TCP. I'm currently using UDP packets for messages coming from a client, to the server, which, being UDP, doesn't require very much processing, as it's simply listening for incoming packets, before it de-serializes the objects, and processes them as needed in a separate thread. My problem now is, I'm setting up a client initiated TCP socket for reverse traffic, from the server to the assorted clients that connect. I've done a bit of research, and I already understood that each client should have their own thread for handling outgoing messages, along with another thread simply for accepting the incoming connections. I'm unsure of how to actually achieve this, and I've done some research into the topic.
I've found this: http://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html
The resource above basically verified my original suspicion that this would have to be handled by threads dedicated to the client. They included psuedo code here, which is representing my listener thread.
while (true) {
accept a connection;
create a thread to deal with the client;
}
I'm a bit of a visual learner, and I have been searching for some type of an example where this is done. I'm unsure of what variable I'd be passing over to the thread that keeps the original connection open, and pushes data back to clients. I'm also having a little bit of trouble grasping whether it even keeps the same socket open, or if a new one needs to be established, which then, makes me believe a firewall could interfere, but I know that won't be the case.
Can somebody explain this for me in detail? If possible, an example would be greatly appreciated!
I'll be likely replying and commenting on responses in about 15-30 minutes from the time this is posted.
What you are doing sounds correct. I typically implement a server like this (simplified version with no tracking of the clients and so on):
#Override
public void run() {
//start listening on the port
try {
serverSocket = new ServerSocket(port);
logger.info("Listening for connections on port " + port);
} catch (IOException e) {
logger.error("Cannot start SocketListener on port " + port + ". Stopping.", e);
return;
}
while (!stopped) {
try {
//wait for connection
Socket newSocket = serverSocket.accept();
ClientThread client = new ClientThread(newSocket);
Thread clientThread = new Thread(client, MEANINGFUL_THREAD_ID);
clientThread.start();
} catch ...
}
}
where serverSocket is a ServerSocket instance variable and stopped is a flag I use to stop the listener thread.
So to answer your questions in the comment, you normally pass the Socket object to each client thread so that that thread can work with the input and output stream and handle closing of the socket and so on. Once you "accept" a socket connection, you do not need to recreate the ServerSocket, you simply call .accept() again to start waiting for a new connection.
In most cases, you will need to keep track of all client threads in your server so that you can stop the server gracefully or do broadcasts for example.

How can I force the server socket to re-accept a request from a client?

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:
If Bonjour does not see the server it does not necessarily means that client cannot see the server.
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:
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.
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.
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).
The situation you describe is impossible. You can't get a new connect request from the same remote IP:port as an existing connection. The client will not permit it to occur.
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.)

Java detect lost connection [duplicate]

This question already has answers here:
Java socket API: How to tell if a connection has been closed?
(9 answers)
Closed 5 years ago.
When I'm using e.g. PuTTY and my connection gets lost (or when I do a manual ipconfig /release on Windows), it responds directly and notifies my connection was lost.
I want to create a Java program which monitors my Internet connection (to some reliable server), to log the date/times when my internet fails.
I tried use the Socket.isConnected() method but that will just forever return "true". How can I do this in Java?
Well, the best way to tell if your connection is interrupted is to try to read/write from the socket. If the operation fails, then you have lost your connection sometime.
So, all you need to do is to try reading at some interval, and if the read fails try reconnecting.
The important events for you will be when a read fails - you lost connection, and when a new socket is connected - you regained connection.
That way you can keep track of up time and down time.
Even though TCP/IP is "connection oriented" protocol, normally no data is sent over an idle connection. You can have a socket open for a year without a single bit sent over it by the IP stack. In order to notice that a connection is lost, you have to send some data on the application level.(*) You can try this out by unplugging the phone cable from your ADSL modem. All connections in your PC should stay up, unless the applications have some kind of application level keepalive mechanism.
So the only way to notice lost connection is to open TCP connection to some server and read some data from it. Maybe the most simple way could be to connect to some FTP server and fetch a small file - or directory listing - once in a while. I have never seen a generic server which was really meant to be used for this case, and owners of the FTP server may not like clients doing this.
(*) There is also a mechanism called TCP keepalive but in many OS's you have to activate it for all applications, and it is not really practical to use if you want to notice loss of connection quickly
If the client disconnects properly, a read() will return -1, readLine() returns null, readXXX() for any other X throws EOFException. The only reliable way to detect a lost TCP connection is to write to it. Eventually this will throw an IOException 'connection reset', but it takes at least two writes due to buffering.
Why not use the isReachable() method of the java.net.InetAddress class?
How this works is JVM implementation specific but:
A typical implementation will use ICMP ECHO REQUESTs if the privilege can be obtained, otherwise it will try to establish a TCP connection on port 7 (Echo) of the destination host.
If you want to keep a connection open continually so you can see when that fails you could connect to server running the ECHO protocol yourself rather than having isReachable() do it for you and read and write data and wait for it to fail.
You might want to try looking at the socket timeout interval. With a short timeout (I believe the default is 'infinite timeout') then you might be able to trap an exception or something when the host becomes unreachable.
Okay so I finally got it working with
try
{
Socket s = new Socket("stackoverflow.com",80);
DataOutputStream os = new DataOutputStream(s.getOutputStream());
DataInputStream is = new DataInputStream(s.getInputStream());
while (true)
{
os.writeBytes("GET /index.html HTTP/1.0\n\n");
is.available();
Thread.sleep(1000);
}
}
catch (IOException e)
{
System.out.println("connection probably lost");
e.printStackTrace();
}
Not as clean as I hoped but it's not working if I leave out the os.writeBytes().
You could ping a machine every number of seconds, and this would be pretty accurate. Be careful that you don't DOS it.
Another alternative would be run a small server on a remote machine and keep a connection to it.
Its probably simpler to connect to yahoo/google or somewhere like this.
URL yahoo = new URL("http://www.yahoo.com/");
URLConnection yc = yahoo.openConnection();
int dataLen = yc.getContentLength() ;
Neil
The isConnected()method inside Socket.java class is a little misleading. It does not tell you if the socket is currently connected to a remote host (like if it is unclosed). Instead, it tells you whether the socket has ever been connected to a remote host. If the socket was able to connect to the remote host at all, this method returns true, even after that socket has been closed. To tell if a socket is currently open, you need to check that isConnected() returns true and isClosed() returns false.
For example:
boolean connected = socket.isConnected() && !socket.isClosed();

Categories