I used the Java Knock Knock tutorial for creating a client-server connection but I cant figure out how to check if the socket is still open.
Simplified code:
try {
while ((clientMessage = inFromClient.readLine()) != null) {
//do stuff
} catch (IOException e) {
//client disconnected
e.printStackTrace();
}
}
This works great, however I noticed that when the client is Linux based the exception isn't thrown if client gets forcefully closed. I tried some suggestions posted by others but can't get any working. I tried to implement a loop that checks how long its been since last message was received but it didn't work, the loop had to be inside the loop in the above code, and the loop is only executed when a new message is received from the client. I'm very confused but I don't understand how to implement any methods of checking.
If I put the method to check for inactivity outside the above loop then it's never called because the socket loop is indefinite (unless socket is closed).
Just set a read timeout with Socket.setSoTimeout(). Set it to higher than the expected request interval, say double that. If it expires, you will get a SocketTimeoutException: close the socket.
Contrary to some of the comments, isConnected(), isBound(), isClosed(), etc. are no use for this. They tell you whether you connected, bound, closed, etc. the Socket. Not about the state of the connection.
Related
I am running into some issues with the Java socket API. I am trying to display the number of players currently connected to my game. It is easy to determine when a player has connected. However, it seems unnecessarily difficult to determine when a player has disconnected using the socket API.
Calling isConnected() on a socket that has been disconnected remotely always seems to return true. Similarly, calling isClosed() on a socket that has been closed remotely always seems to return false. I have read that to actually determine whether or not a socket has been closed, data must be written to the output stream and an exception must be caught. This seems like a really unclean way to handle this situation. We would just constantly have to spam a garbage message over the network to ever know when a socket had closed.
Is there any other solution?
There is no TCP API that will tell you the current state of the connection. isConnected() and isClosed() tell you the current state of your socket. Not the same thing.
isConnected() tells you whether you have connected this socket. You have, so it returns true.
isClosed() tells you whether you have closed this socket. Until you have, it returns false.
If the peer has closed the connection in an orderly way
read() returns -1
readLine() returns null
readXXX() throws EOFException for any other XXX.
A write will throw an IOException: 'connection reset by peer', eventually, subject to buffering delays.
If the connection has dropped for any other reason, a write will throw an IOException, eventually, as above, and a read may do the same thing.
If the peer is still connected but not using the connection, a read timeout can be used.
Contrary to what you may read elsewhere, ClosedChannelException doesn't tell you this. [Neither does SocketException: socket closed.] It only tells you that you closed the channel, and then continued to use it. In other words, a programming error on your part. It does not indicate a closed connection.
As a result of some experiments with Java 7 on Windows XP it also appears that if:
you're selecting on OP_READ
select() returns a value of greater than zero
the associated SelectionKey is already invalid (key.isValid() == false)
it means the peer has reset the connection. However this may be peculiar to either the JRE version or platform.
It is general practice in various messaging protocols to keep heartbeating each other (keep sending ping packets) the packet does not need to be very large. The probing mechanism will allow you to detect the disconnected client even before TCP figures it out in general (TCP timeout is far higher) Send a probe and wait for say 5 seconds for a reply, if you do not see reply for say 2-3 subsequent probes, your player is disconnected.
Also, related question
I see the other answer just posted, but I think you are interactive with clients playing your game, so I may pose another approach (while BufferedReader is definitely valid in some cases).
If you wanted to... you could delegate the "registration" responsibility to the client. I.e. you would have a collection of connected users with a timestamp on the last message received from each... if a client times out, you would force a re-registration of the client, but that leads to the quote and idea below.
I have read that to actually determine whether or not a socket has
been closed data must be written to the output stream and an exception
must be caught. This seems like a really unclean way to handle this
situation.
If your Java code did not close/disconnect the Socket, then how else would you be notified that the remote host closed your connection? Ultimately, your try/catch is doing roughly the same thing that a poller listening for events on the ACTUAL socket would be doing. Consider the following:
your local system could close your socket without notifying you... that is just the implementation of Socket (i.e. it doesn't poll the hardware/driver/firmware/whatever for state change).
new Socket(Proxy p)... there are multiple parties (6 endpoints really) that could be closing the connection on you...
I think one of the features of the abstracted languages is that you are abstracted from the minutia. Think of the using keyword in C# (try/finally) for SqlConnection s or whatever... it's just the cost of doing business... I think that try/catch/finally is the accepted and necesary pattern for Socket use.
I faced similar problem. In my case client must send data periodically. I hope you have same requirement. Then I set SO_TIMEOUT socket.setSoTimeout(1000 * 60 * 5); which is throw java.net.SocketTimeoutException when specified time is expired. Then I can detect dead client easily.
I think this is nature of tcp connections, in that standards it takes about 6 minutes of silence in transmission before we conclude that out connection is gone!
So I don`t think you can find an exact solution for this problem. Maybe the better way is to write some handy code to guess when server should suppose a user connection is closed.
As #user207421 say there is no way to know the current state of the connection because of the TCP/IP Protocol Architecture Model. So the server has to notice you before closing the connection or you check it by yourself.
This is a simple example that shows how to know the socket is closed by the server:
sockAdr = new InetSocketAddress(SERVER_HOSTNAME, SERVER_PORT);
socket = new Socket();
timeout = 5000;
socket.connect(sockAdr, timeout);
reader = new BufferedReader(new InputStreamReader(socket.getInputStream());
while ((data = reader.readLine())!=null)
log.e(TAG, "received -> " + data);
log.e(TAG, "Socket closed !");
Here you are another general solution for any data type.
int offset = 0;
byte[] buffer = new byte[8192];
try {
do {
int b = inputStream.read();
if (b == -1)
break;
buffer[offset++] = (byte) b;
//check offset with buffer length and reallocate array if needed
} while (inputStream.available() > 0);
} catch (SocketException e) {
//connection was lost
}
//process buffer
Thats how I handle it
while(true) {
if((receiveMessage = receiveRead.readLine()) != null ) {
System.out.println("first message same :"+receiveMessage);
System.out.println(receiveMessage);
}
else if(receiveRead.readLine()==null)
{
System.out.println("Client has disconected: "+sock.isClosed());
System.exit(1);
} }
if the result.code == null
On Linux when write()ing into a socket which the other side, unknown to you, closed will provoke a SIGPIPE signal/exception however you want to call it. However if you don't want to be caught out by the SIGPIPE you can use send() with the flag MSG_NOSIGNAL. The send() call will return with -1 and in this case you can check errno which will tell you that you tried to write a broken pipe (in this case a socket) with the value EPIPE which according to errno.h is equivalent to 32. As a reaction to the EPIPE you could double back and try to reopen the socket and try to send your information again.
I'm new to working with Socket and have perhaps painted myself into a corner with a spurious design. I think I'd like to find a way to purge or flush the contents of a line decorating a Socket's InputStream. But maybe I've set things up incorrectly?
The Socket is tasked with repeatedly running the following cycle, on demand, on a background thread. A Runnable is instantiated that does the following tasks, then completes:
Send a message to server
Listen for an "ACK"
Wait for response from server
Read and "log" response
Send "ACK"
The runnable holds a class variable that is responsible for reading messages from the ServerSocket. inLine is instantiated in a separate method which is used to establish the connection.
inLine = new BufferedReader(new InputStreamReader(socket.getInputStream()));
My issue is that I am trying to figure out how to handle a test case scenario where the SocketServer sends an "extraneous" message during the interval when the client is dormant. On the next iteration of the cycle, this "extra" message is in the cue ahead of the expected "ACK" in step 2.
I was thinking I would remove any pending messages from the inLine variable prior to launching the runnable. But I don't see any means to do this. There are no flush or clear methods on BufferedReader or InputStreamReader. Nor are there any methods that I can find which allow one to inspect if there are any messages in the queue, along the lines of an iterator's hasNext() method.
Is there something I am missing?
Should I just declare and instantiate the inLine anew with each cycle? I was hesitating to do this because I don't know how expensive it is to continually repeat this operation. (As I said, I'm new to working with Socket-based communications.)
Would something like the following at the top of the cycle be considered ugly, or reasonable?
// clear out any messages sent during dormant time
socket.setSoTimeout(10); // arbitrary, very short timeout
while (true) {
try {
in.readLine();
} catch (SocketTimeoutException ex) {
break;
}
}
EDIT: There are wonderful folks at StackOverflow who I know are doing their best to keep questions in conformance with site standards. If you have a suggestion to help me improve the question, it would be appreciated. Should a question like this perhaps be better posted at "Code Review" now that I have added a plausible routine for clearing the input line?
I am running into some issues with the Java socket API. I am trying to display the number of players currently connected to my game. It is easy to determine when a player has connected. However, it seems unnecessarily difficult to determine when a player has disconnected using the socket API.
Calling isConnected() on a socket that has been disconnected remotely always seems to return true. Similarly, calling isClosed() on a socket that has been closed remotely always seems to return false. I have read that to actually determine whether or not a socket has been closed, data must be written to the output stream and an exception must be caught. This seems like a really unclean way to handle this situation. We would just constantly have to spam a garbage message over the network to ever know when a socket had closed.
Is there any other solution?
There is no TCP API that will tell you the current state of the connection. isConnected() and isClosed() tell you the current state of your socket. Not the same thing.
isConnected() tells you whether you have connected this socket. You have, so it returns true.
isClosed() tells you whether you have closed this socket. Until you have, it returns false.
If the peer has closed the connection in an orderly way
read() returns -1
readLine() returns null
readXXX() throws EOFException for any other XXX.
A write will throw an IOException: 'connection reset by peer', eventually, subject to buffering delays.
If the connection has dropped for any other reason, a write will throw an IOException, eventually, as above, and a read may do the same thing.
If the peer is still connected but not using the connection, a read timeout can be used.
Contrary to what you may read elsewhere, ClosedChannelException doesn't tell you this. [Neither does SocketException: socket closed.] It only tells you that you closed the channel, and then continued to use it. In other words, a programming error on your part. It does not indicate a closed connection.
As a result of some experiments with Java 7 on Windows XP it also appears that if:
you're selecting on OP_READ
select() returns a value of greater than zero
the associated SelectionKey is already invalid (key.isValid() == false)
it means the peer has reset the connection. However this may be peculiar to either the JRE version or platform.
It is general practice in various messaging protocols to keep heartbeating each other (keep sending ping packets) the packet does not need to be very large. The probing mechanism will allow you to detect the disconnected client even before TCP figures it out in general (TCP timeout is far higher) Send a probe and wait for say 5 seconds for a reply, if you do not see reply for say 2-3 subsequent probes, your player is disconnected.
Also, related question
I see the other answer just posted, but I think you are interactive with clients playing your game, so I may pose another approach (while BufferedReader is definitely valid in some cases).
If you wanted to... you could delegate the "registration" responsibility to the client. I.e. you would have a collection of connected users with a timestamp on the last message received from each... if a client times out, you would force a re-registration of the client, but that leads to the quote and idea below.
I have read that to actually determine whether or not a socket has
been closed data must be written to the output stream and an exception
must be caught. This seems like a really unclean way to handle this
situation.
If your Java code did not close/disconnect the Socket, then how else would you be notified that the remote host closed your connection? Ultimately, your try/catch is doing roughly the same thing that a poller listening for events on the ACTUAL socket would be doing. Consider the following:
your local system could close your socket without notifying you... that is just the implementation of Socket (i.e. it doesn't poll the hardware/driver/firmware/whatever for state change).
new Socket(Proxy p)... there are multiple parties (6 endpoints really) that could be closing the connection on you...
I think one of the features of the abstracted languages is that you are abstracted from the minutia. Think of the using keyword in C# (try/finally) for SqlConnection s or whatever... it's just the cost of doing business... I think that try/catch/finally is the accepted and necesary pattern for Socket use.
I faced similar problem. In my case client must send data periodically. I hope you have same requirement. Then I set SO_TIMEOUT socket.setSoTimeout(1000 * 60 * 5); which is throw java.net.SocketTimeoutException when specified time is expired. Then I can detect dead client easily.
I think this is nature of tcp connections, in that standards it takes about 6 minutes of silence in transmission before we conclude that out connection is gone!
So I don`t think you can find an exact solution for this problem. Maybe the better way is to write some handy code to guess when server should suppose a user connection is closed.
As #user207421 say there is no way to know the current state of the connection because of the TCP/IP Protocol Architecture Model. So the server has to notice you before closing the connection or you check it by yourself.
This is a simple example that shows how to know the socket is closed by the server:
sockAdr = new InetSocketAddress(SERVER_HOSTNAME, SERVER_PORT);
socket = new Socket();
timeout = 5000;
socket.connect(sockAdr, timeout);
reader = new BufferedReader(new InputStreamReader(socket.getInputStream());
while ((data = reader.readLine())!=null)
log.e(TAG, "received -> " + data);
log.e(TAG, "Socket closed !");
Here you are another general solution for any data type.
int offset = 0;
byte[] buffer = new byte[8192];
try {
do {
int b = inputStream.read();
if (b == -1)
break;
buffer[offset++] = (byte) b;
//check offset with buffer length and reallocate array if needed
} while (inputStream.available() > 0);
} catch (SocketException e) {
//connection was lost
}
//process buffer
Thats how I handle it
while(true) {
if((receiveMessage = receiveRead.readLine()) != null ) {
System.out.println("first message same :"+receiveMessage);
System.out.println(receiveMessage);
}
else if(receiveRead.readLine()==null)
{
System.out.println("Client has disconected: "+sock.isClosed());
System.exit(1);
} }
if the result.code == null
On Linux when write()ing into a socket which the other side, unknown to you, closed will provoke a SIGPIPE signal/exception however you want to call it. However if you don't want to be caught out by the SIGPIPE you can use send() with the flag MSG_NOSIGNAL. The send() call will return with -1 and in this case you can check errno which will tell you that you tried to write a broken pipe (in this case a socket) with the value EPIPE which according to errno.h is equivalent to 32. As a reaction to the EPIPE you could double back and try to reopen the socket and try to send your information again.
I have made a client-server application which can connect over the internet. I have hard coded in my client the server's IP which is fixed.
My question is that I want a way that will not take a lot of processing and memory.
I want my client to check if internet is available and then try to connect to the server if its up and running. If not then to wait and try again.
Keeping in mind that the app is supposed to always run on your computer 24/7 and connect when possible just like skype does, in the sense that its always on and when you have the internet available and server reachable , it connects.
My client's code that connects to the server:
private void connectToServer() throws Exception {
showMessage("Attempting Connection... \n");
try{
connection = new Socket(InetAddress.getByName(serverIP), 6789);
showMessage("Ok dude you are Connected to:" + connection.getInetAddress().getHostName());}
catch(IOException e){
int x = 0;
while (true){
try {
showMessage("Sorry Your IP was not found, \nAutomatic detection:");
showMessage("Now trying again");
connection = new Socket(InetAddress.getByName(serverIP),6789);
break;
} catch (UnknownHostException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
showMessage("\nConnection not established, trying again\n");
}
/*x++;
if(x>10) break;*/
}
//throw new Exception();
}
}
This does work but takes a lot of processing and memory !
I know that by adding thread.sleep(5000), I am going to add them eventually etc...
But this doesn't solve the memory problem. My program would be running for a long time and this doesn't stop the inevitable.
Is there a better way?
THANKS
P.S : showMessage() is just my function that displays the output on my GUI
The way I checked memory was using Window's Task Manager !
(the memory increases drastically)
As you've noted in your question already, you should add a call to Thread.sleep() within the loop. As your code stands right now, it runs a tight endless loop that will be very taxing on the CPU.
As for memory usage, are you sure that the memory used is actually growing? The JVM may be allocating a large chunk of memory off the bat even for a simple program -- you should check to make sure that the usage is actually growing. If it is indeed a problem, it may just be because you're making a new Socket in each cycle of a tight loop, in which case adding the sleep() call would solve the issue by allowing the GC to take care of old Socket objects in time.
By the way, have you noticed that your code performs the exact same check again if the first one fails? Why not start the loop immediately and just perform the check once within the loop? This would allow you to significantly reduce your code's complexity. Look into the software guideline often referred to as "Don't Repeat Yourself" to learn more.
It seems you are having two problems
How to check internet is available - please refer
Preferred Java way to ping an HTTP URL for availability
Detect internet Connection using Java
How to check if internet connection is present in java?
Memory leak
You need to clean up the socket object if the connection fails.
My client/server application currently keeps opening and closing new connections every time it wants to send/receive data. I'm trying to change it so it will have one persistent connection.
The problem I'm having is the socket's DataInputStream on the server keeps throwing EOFException's when I just want it to block until it receives the next batch of data.
I thought about just simply writing the server like this...
while socket is open {
while at socket's DataInputStream's EOF {
wait a second
}
//If we're here, then we have some data
do stuff
}
... but this is extremely ugly and not the proper way to block until some data is received.
Is there a cleaner way to tell the socket to block until there's some data to read? I've tried read() and readFully(), but neither work.
If you are getting EOFException, it means the connection is gone. You cannot wait on a connection that's closed. Keep working on your client code so that it doesn't close the connection. On the server side, any of the read methods will block until data is available without further effort from you.