When OkHttp3 calls the onFailure callback, it passes an IOException. Is there a specific subclass of IOException that will indicate that the target device has disappeared from the WiFi network? Is there another way to detect this?
IOException has several sub-classes; while it may be save to assume that something went offline - because when the own network connection is still alive, it has to be the other side of the connection. when it throws an IOException, that's an IOExcpetion; casting it won't add any more information.
the state of the own network connection can be detected, but not with OkHttp3. here's an example for that on my GitHub; see class ConnectivityListener and class ConnectivityReceiver.
How would you detect the state of another host's network connection?
this can be tested, by switching off the WiFi network of either device; both situations would cause an IOException.
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.
Maybe I miss something, but How can I change the timeout of BluetoothSocket.connect() ?
Thanks you
Anthony
You can't change timeout of BluetoothSocket.connect(). As documentation:
This method will block until a connection is made or the connection
fails. If this method returns without an exception then this socket is
now connected.
A workaround.
Ex: timeout 5s.
Using CountDownTimer to check if connect is complete(success or fail). After 5s, if connection is incomplete then use BluetoothSocket.close() to cancel.
As BluetoothSocket documentation:
close() can be used to abort this call from another thread.
In my application two devices are connected via bluetooth. In the background runs an own thread for the bluetooth connection. (Just like the example )
When one device wants to connect to another device i want a request dialog to be displayed on the second device.
So I guess that i have to modify the AcceptThread. The AcceptThread has to inform my mainThread (for example with a Handler).
In the AcceptThread I find this code:
// This is a blocking call and will only return on a
// successful connection or an exception
socket = mmServerSocket.accept();
Now here is my problem: this "blocking call" runs the whole time. How and when shall I inform my mainThread that another device wants to connect?
Definitely afterwards.
What you want is the result of the blocking call - of the .accept().
That is socket in your code.
Here is a quote from the Android BluetoothServerSocket documentation:
Then call accept() to listen for incoming connection requests. This
call will block until a connection is established, at which point, it
will return a BluetoothSocket to manage the connection. Once the
BluetoothSocket is acquired, it's a good idea to call close() on the
BluetoothServerSocket when it's no longer needed for accepting
connections. Closing the BluetoothServerSocket will not close the
returned BluetoothSocket.
So don't forget to do:
mmServerSocket.close()
After you receive a socket correctly - a BluetoothSocket actually -, you can choose what to do with it following the user's choice:
Should he go ahead, you just create the AsyncTask that reads from the socket until the AsyncTask is cancelled or an Exception occurs(on Bluetooth disconnect probably).
Should he decline, just cancel the socket
If you receive an Exception during the blocking call I would return to the main menu only a toast, saying something failed. But you can do a dialog (like retry?)
Hi
I'm trying to implement a bluetooth library and in it I want to connect an rfcomm socket once and then reuse it on all calls.
I want to know if it's connected or not in order to know if I should call the connect method.
I can't find anything in the source code for Bluetooth sockets since it's all native calls and there's no isConnected method defined in the API...
Does anyone have any experience with this?
I answered a similar question here. Starting from API Level 14 there is a isConnected method in the BluetoothSocket class available. For lower API levels, you may open a socket, do your work and close it again. However there are some thing you might have to consider, more in the linked answer.
I think you would have a member variable maintain the state of your connection. on successful connection set it to true, start a thread that loops always reading bytes from the sockets inputstream and if you get an IOException on that thread, set your flag to false.
isConnected() never works for me.
Try something like this:
try {
mSocket.connect()
} catch (IOException e) {
// Create a new socket
// mSocket.connect();
}