In my Android app, I do poll a device (Wallbox) every 5 seconds using the Volley library. For one customer, I get
java.net.NoRouteToHostException: Address not available
after several hours. Usually, using the exactly same type of device and at my place, this polling works for days, but not at (at least) this customer.
The device address is on the local LAN.
I have not found any description about "address not available" that might apply to my case, or at least I did not see the point.
The call is always the same:
http://192.168.160.152/api/status
As this is live data, I set ".setShouldCache(false)" for the request.
Meanwhile, other HTTP requests (in this case, a query to a WWW address, also polled continuously), even using Volley, continue to work:
https://backend.powerfox.energy/api/2.0/my/***********/current
The connection works again after rebooting the device (and at the same original IP address), so I guess it has nothing to do with the wallbox or the router.
And if the wallbox would be not available, I assue I would get "unreachable" error or such.
Is there someone who can help me, what could cause that exception ("address not available"), and what can I do about it?
Related
I am having an Android app which needs continuous network monitoring and I require to be notified when I have internet and when not. I have tried Android connectivity manager, which only tells if the internet wifi is connected or not, but doesn't tell if there is reachability. So I used the following ping method to check the reachability.
private fun isOnline(): Boolean {
return try {
val timeoutMs = 1500
val sock = Socket()
val socketAddress = InetSocketAddress("8.8.8.8", 53)
sock.connect(socketAddress, timeoutMs)
sock.close()
true
} catch (e: IOException) {
Logger.e(TAG, e.toString())
false
}
}
Now to keep checking this every 1 minute I am using a fixedRateTimer which will call this method every 1 minute and notify accordingly.
Now the problem I am facing is, this works fine for few hours and I get proper connection status. But after few hours the ping starts timing out. I get a timeout exception every alternate ping.
I want to understand few things,
First thing, is it okay to ping for every 1 minute to check the network?
Can the client be blocked by Google for frequent pings?
Or is it anything related to the ISP?
Is there a better approach in android to achieve what I want?
Any advice would be appreciated. Thanks in advance!
PS : I have also tried onCapabilitiesChanged and the callbacks are not immediate for every connection and disconnection, though the google documentation says callbacks will be immediate.
but doesn't tell if there is reachability. So I used the following ping method to check the reachability
First, that is not a ping. That is opening and closing a socket.
Second, it can only tell you if you can open a socket connection to that IP address. It does not tell you if you can access anything else. So, this is subject to false positives (you can reach 8.8.8.8 but not your real server) and false negatives (8.8.8.8 is blocked by network management, but your real server is not).
Now to keep checking this every 1 minute I am using a fixedRateTimer which will call this method every 1 minute and notify accordingly.
That will only work so long as your process is running, and only until you lose Internet access due to Doze mode/app standby/manufacturer-specific power management solutions.
First thing, is it okay to ping for every 1 minute to check the network?
It has flaws. "Okay" is a subjective measure; only you can decide whether it is "okay" for you.
Can the client be blocked by Google for frequent pings?
This is not a ping. It is certainly within Google's power to take action for buggy clients like this.
Or is it anything related to the ISP?
There are lots of pieces involved in an Android device reaching 8.8.8.8:
The network management for whatever WiFi network the phone is using for connectivity (where relevant)
The mobile carrier or ISP
The various other ISPs between you and Google
Google's own network management
Any of them could take steps, if they so chose.
Is there a better approach in android to achieve what I want?
I would aim to eliminate the "need" entirely, as Android and device manufacturers will be fighting you every step of the way.
At minimum:
Do a valid expected operation, such as an actual ping; and
Do it against a relevant server
IIRC, 8.8.8.8 is a DNS server. If your app is a DNS client, you are welcome perform a valid, useful DNS operation against 8.8.8.8. If your app is not a DNS client, quit messing with somebody else's server. Run your own server and test reaching it. For example, you could run a Web server and test whether you can retrieve your robots.txt file.
Most of the question has been answered, but I want to pick up on the most important one.
First thing, is it okay to ping for every 1 minute to check the network?
No. It is not OK.
It is wasteful
You are consuming Google's resources. Resources that you are not paying for. If everyone did what you are doing it would cost Google a lot of money ... to run a much larger fleet of DNS servers, etc to cope with bazillions of vacuous connections.
You are also consuming resources in the along the route from the user's app to Google with the (unnecessary) network traffic.
This would also apply if you were doing real (ICMP) pings, though not to the same extent.
And bear in mind, this is also consuming electricity. And that means more fossil fuel is burned.
It may be incurring costs for the user
Depending on the what their mobile phone plan is, this may be costing the user of your app network charges. Each of those connections your App is making probably being metered. If they are not aware of this ... or they can't turn this (mis-)feature off, they could get rather annoyed about this. (I would be!)
It doesn't actually work
What you are doing doesn't actually test if the internet is available. What you are actually doing is seeing if your App can connect to the Google DNS services. But the fact that the DNS server is accepting connections doesn't mean that the real services that the user wants to use will be accessible and working. (And vice versa!)
As you noted, connections will occasionally fail for reasons that are probably due to transient problems that resolve themselves. There is nothing you can do about that. That could be a false negative for the internet being "up".
Even if there was a reliable way to find out if the internet is "working", your "pinging" is only giving you a single sample. The internet could go "down" (or come back "up") any time in the up to 60 seconds between your pings. More false negatives and positives.
And as noted, Google DNS is not the same as "the internet", and "the internet" is not the same as the service that the user of you App is really interested in.
Your app doesn't REALLY need this information
The user does not need to know minute by minute that the internet is available.
Most of the time a typical user is doing something else.
They only actually need to know if they are actively using some service. And even then, knowing that the internet was up 60 seconds ago is probably no help to them.
Unfortunately, the only way that the user can tell if the service they are talking to is available right now ... is to actually try to use it.
So what is the real solution?
IMO, there are two approaches:
Forget it. In most cases, the user really doesn't need to know. It is not actually going to materially effect the user if your App does not distinguish "service down" from "internet down".
If you can't forget it.
Implement an end-point on your service that you can ping ... and pay the bills!
If you are trying to implement this in an App where you are talking to someone else's services, stop free-loading on Google. If you want an "internet is up/down" feature in your App, implement your own service for doing this ... and pay the bills.
Note that you will still have false positives and false negatives to deal with. There is no solution to that. It is a fundamental property of the internet.
I've been experimenting with the new Android Nearby Connections v2.0 API. Most of my devices can now talk to each other most of the time, but I also get a lot of error codes back when trying to connect. Checking status.getStatusCode() inside my program, I can see the following return codes:
STATUS_ALREADY_CONNECTED_TO_ENDPOINT (8003)
STATUS_BLUETOOTH_ERROR (8007)
STATUS_ENDPOINT_IO_ERROR (8012)
STATUS_ERROR (13)
I'm having a hard time making sense of these. The first error code seems self-explanatory, except that I see it in cases when I haven't hit the onConnectionResult callback with a "SUCCESS" return code on either side of the alleged connection. My current code is full of trace statements, and I'd see logging entries if those callbacks had been reached. So maybe the devices are connected at some lower level, but if so, the higher-level code doesn't always hear about it.
I'm guessing that STATUS_BLUETOOTH_ERROR indicates a Bluetooth error on the side that logs it, while STATUS_ENDPOINT_IO_ERROR indicates an error (probably involving Bluetooth) on the other end? Is it possible to get any more details?
The STATUS_ERROR (13) status that I see once in a while sounds like the sort of error code a programmer would use for those "WTF, we should never get here" moments, but without access to the source code, I can only guess.
Note that I see these errors between devices that talk to each other beautifully at other times, using the same code. Sometimes if the code retries enough times, it eventually gets a stable connection. Sometimes it connects and gets instantly disconnected from the other end. Sometimes I just get an endless stream of repeated error messages (STATUS_BLUETOOTH_ERROR and/or STATUS_ENDPOINT_IO_ERROR).
I'm using Nearby Connections with the connection strategy P2P_CLUSTER. These problems seem to happen most often when both sides do both advertising and discovery. However, I wrote two smaller programs that specialize in either advertising or discovery, and they sometimes get these errors too (but less often).
In the trace messages, I've also noticed lots of warning messages from Nearby Connections that look like this:
09-04 22:54:40.070 3866-3924/? W/NearbyConnections: Cannot deserialize BluetoothDeviceName: expecting min 16 raw bytes, got 6
I'm guessing that this is because Nearby Connections uses its own short tokens (like ZGbx) instead of the device Bluetooth name? I'm not at all sure about that, though. And anyway, if these are Nearby Connections' own special tokens, then why would it be issuing warning messages about it?
[Disclaimer: I work on Nearby Connections] I can try and help out.
STATUS_ALREADY_CONNECTED_TO_ENDPOINT: This occurs if you call 'requestConnection' while you have any pending (onConnectionInitiated) or established (onConnectionResult) connections to the given endpoint. Move your log statements earlier, to onConnectionInitiated, and you should see why we throw this error.
STATUS_BLUETOOTH_ERROR: Something went wrong with Bluetooth. The phone is probably in a bad state. This (hopefully) shouldn't happen too often. But if you really want a fix, stop advertising & discovery before reattempting requestConnection. Nearby Connections will toggle Bluetooth when it detects this error, but only if nothing else is going on.
STATUS_ENDPOINT_IO_ERROR: We lost connection to the other device. This can happen for a variety of reasons (they could have walked too far away, Bluetooth was flaky, the device stopped responding, etc). If you're discovering while you have connections, avoid that. Discovery can be hard on the phone and reduces bandwidth at best, causes dropped connections at worst.
STATUS_ERROR: Something went wrong that didn't fit well in the other error codes. It's a catch-all. This is most-often returned in onConnectionResult(FAILED), to notify you that something went wrong in between onConnectionInitiated and waiting for both sides to accept the connection.
We've also lowered the log severity of "Cannot deserialize BluetoothDeviceName" in an upcoming release, since it's not really a warning. It's like you said; expected behavior when we see non-Nearby Connections devices while discovering.
If you continue to see problems, let us know what devices you're using and we'll be sure to add them to our test suite.
I just want to add that it may be necessary to have a short client name string when calling the API.
E.g., Nearby.Connections.requestConnection(googleApiClient, shortNameHere,....)
I had been generating my own client name with UUID.randomUUID().toString() and that seemed to cause the STATUS_BLUETOOTH_ERROR.
All I did was change the code sample to use a UUID name and to use P2P_CLUSTER and I got that error.
This was the solution for me regarding the STATUS_BLUETOOTH_ERROR.
I have 2 android phones phones, both connected to the same wifi, both with bluetooth.
I want some method that syncs somehow the phones and starts a function on the same time on both phones.
For example playing a song at the same time.
I already tried with bluetooth but its with lag, sometimes 0.5 secs. I want something in +- 0.01sec if possible.
Someone suggesting playing it in the future with 2-3 seconds, sending the time-stamp, but how do you sync the internal clocks of the devices then ?
Before calling that particular method, try to measure the latency between the two devices:
1.First device says Hi(store the current time)
2.Second device receives the Hi.
3.Second device says back Hi !!
4.First device receives the Hi.((storedTime - currentTime) / 2 )
Now you have the latency, send your request to second device to start your particular method and start it on first one after the latency.
Try to measure the latency 5 to 10 times to be more accurate.
you have a way to transfer data between the devices right ?
if so you can send a time-stamp which is in the future,
ex: if the present time stamp is 1421242326 you send 1421242329 or something and start the function at that time on both devices.
Basically use #Dula's suggestion (device 1 sends command to device 2 and gives a "start time" which lies in the future). Both devices then start the action at the same time (in the future).
To make sure that the devices are synchronized, you can use a server-based time sync (assuming that both devices have Internet access). To do this, each device contacts the same server (using NTP, or HTTP-based NTP, or contacts a known HTTP server, like www.google.com and uses the value in the "Date" header of the HTTP response). The "server-date" is compared to the system clock on the device, and the difference is the "time-offset from server-time". The time-offsets can be used to synchronize on the "server-time", which is then used as the time base for the actual action (playing the media, etc.).
If your WiFi router allows clients to talk to each other (many public hotspots disable this), you could implement a simple socket listener on one (or each) device and have the initiating device broadcast a message.
For more complicated things and network flexibility, I've had good success with connected sessions using AllJoin. There is a bit of a learning curve to do interesting things, but the simple stuff is pretty easy once you understand the architecture.
Use a server to provide a synchronous event to just the two clients who have decclared their mutual affinity (random as a parm and pair serializer Partner-1 or Partner-2 which they share prior to their respectve calls for the sync event).
Assume both clients on same subnet (packets from 2 events serialized on the server , arrive across the network at the 2 clients simultaneously client-side) This provides synchronous PLays by 2 , bound clients.
The event delivered by server is either a confirm to play queued selected track OR a broadcast( decoupled, more formal)
The only tricky thing is the server side algorythm implementing this:
Queue a pair of requests or error
Part1, part2 with same Random value constitute valid pair if both received before either times out.
On a valid pair schedule both to the same future event in their respective , committed responses.
OnSchedule do the actual IO for 2 paired requests. Respective packets will arrive back at respective clients at same time, each response having been subject to equal network latency
Ng if two diff carrier 4G or lte networks involved. (Oops)
This thing is possible via socket, you will send a event via socket then the other device receive that event. For learn socket io chat
maybe it's not the answer you are looking for but i think that due to the high precision you are wanting , you should look for a push technology, i advice you to take look at SignalR. It's real time technology which gives you abstraction of sending methods , it have a built-in methods like Clients.All.Broadcast that fit your needs.
You can try to use some MQTT framework to send message between two device, or into a set with more number of devices.
I tried connecting to an IP address (e.g. http://222.222.222.222:8080) and a URL (e.g. http://www.website.com) while my wiFi is disabled. I noticed that if I don't have a wiFi and I tried connecting to an IP address, it gives me a ConnectException error. On the other hand, if I don't have a wiFi and I tried connecting to a URL, it gives me an IOException error. Why am I receiving different Exception for the 2 cases when the only difference is I supplied an IP address for the first one and a URL for the other? Can someone enlighten me on this one? I am asking this for clarification.
Thank you!
You're getting different errors because different steps are failing.
When you're trying to connect to port 80 of an IP address, it is a connect(2) system call that is failing. There are many different reasons why connect(2) could fail; you'll need to inspect the message from the exception to provide a good error message to the user.
When you're trying to connect to port 80 of a textual address, the libraries will first try to resolve the hostname into an IP address using getaddrinfo(3). The name resolution may or may not fail based on having network access -- if you were trying to connect to localhost, for example, no network access is usually required, as the nameservice lookup can be handled entirely on the local device. Because the nameservice failure happens because you cannot contact a nameserver, it makes sense to give a different error message (and exception), even if the underlying cause is the same for a given set of tests. You might not be able to contact the nameservers for any variety of reasons. Again, you'll need to inspect the message from the exception to give a good error message to the user.
I perform some large downloads. I start a download being connected to 3G, all is fine. Then, I switch to WiFi connection, but the request returns a timeout exception. I have used HttpClient library. I have implemented a retry mechanism, so, when the request returns an exception, it sleeps for 0.5 seconds and tries to execute again and again. I would expect that, after connecting to a WiFi, the Http request could execute. But it seems that the Http execute method returns a null response, all the time after that. Very strange, if I commute again to 3G, the execute method returns again a good response. Can anyone help me please :) ?
First, it seems that it may be more convenient to use DownloadManager for large files - it handles retry and everything.
As for HttpClient - it's known to have some issues, but i'm not sure if you bumped into one of them or just overlooked something. It's been deprecated as of Gingerbread, you may want to try HttpUrlConnection instead, it's said to have less problems than HttpClient.
Also, when switching between WIFI and cell connections, HttpClient may need to be reinitialized completely, there's http range header to tell server which byte you want to continue downloading from. But again, I suggest you give DownloadManager a try, it may save you a lot of time.
This might be a routing problem:
when switching between different network types usually the local ip address and, more important, the local routing table changes, due to a different gateway being used. This means that packages that traveled fine between client and server wont reach any destination after a network change, if they are send the same route. Most likely your client implementation has to be notified of the change or even restartet completely, so that the routing strategy is reinitilized.
If the documentation of the implementation components you use dont reveal anything you could try to track this down using a package sniffer like wireshark. Typically packages running into nirwhana show up easily there.