In my app if user do not have internet connection I need to show "NO internet connection" message.
To use Reachability like that:
Reachability *netReach = [Reachability reachabilityWithHostName:#"host.name"];
is bad idea, because internet could be available but host is not, right ?
So how to check internet connection without host ? Thanks...
Reachability *internetReachable = [Reachability reachabilityForInternetConnection];
[internetReachable startNotifier];
if(internetReachable.isReachable)
NSLog(#"True");
You are absolutely right. Reachability only checks whether a certain host is reachable or not. The problem is, that without sending a request to a host there is no way (that I can think of) how to determine whether you are connected to the internet or not.
So what you can do (and what Apple is doing in its Reachability example): Choose a host where you can be 99.99% sure that the host is available. Like for example google.com or apple.com
I think the fact that apple is relying on a certain host to be available to check internet connection (and the fact that they haven't come up with something else, without dependency on a certain host) is a pretty good sign that checking internet connection in this manner is not such a bad idea.
EDIT
Of course the best way (as described in the answer to the question that Petesh is pointing to) would be to simply make the request you want to make and then handle errors accordingly if they occur. In other words: 1. Make your request 2. If it fails use Reachability to see if a missing internet connection might be the problem
Related
What I want to do is call some code when the internet connection is established or restored.
I know there are solutions out there that let me test whether an internet connection is active or not, but I am wondering if there is a way for a function to be triggered by the internet connection becoming active.
If not, what is the best workaround? Checking for a connection every x seconds? Thanks.
The SCNetworkReachability APIs can be configured to generate notifications when the reachability status of an IP address or hostname changes. Create a SCNetworkReachabilityRef, then set a callback, and it will be called when a network change is detected.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
I have used AFNetworking and Reachability now and then but it has always been for checking internet connection. How do I tell if the iOS device is connected to a WLAN that has no internet connection?
I have to be able to know reachability status in real time.
*Just a clarification:
I do not want to check if internet is reachable.
I want to check if the device is connected to the WLAN.
*Changed LAN to WLAN to clarify
Reachability deals with connections to 2 types of network connections, WWans(cell connection) and WiFi. I am guessing you are talking about being connected via WiFi.
Try something like this:
-(BOOL)isWifiRouterConnected
{
BOOL returnValue = NO;
//test for a wifi connection
Reachability *wifiReachability = [Reachability reachabilityForLocalWiFi];
BOOL wifiReachable = [wifiReachability isReachableViaWiFi];
//test for connection to google
if( wifiReachable )
{
returnValue = [Reachability reachabilityWithHostname:#"google.com"];
}
return returnValue;
}
The standard Reachability class that everyone uses is very deceptive. It attempts to determine if a host is reachable only by guessing. For example, if you want to know if you are currently able to reach www.google.com, and you call [Reachability reachabilityWithHostname:#"www.google.com"]; the app never actually "touches" the server to ensure it is turned on, connected, or responding.
What Reachability actually does roughly looks like this:
Look up the IP address using current DNS configuration. If DNS cannot be resolved, the host is unreachable.
Look at the current state of all known network connections. If they are all down, the host is unreachable.
For each network adapter, determine if the destination IP is on the local subnet. If it is, report it as reachable.
For each network adapter, determine if a routing path exists to the destination IP. Generally this only looks at the default gateway. If there is a path to the destination IP, report it as reachable.
If everything has failed, the host is not reachable.
The problem you are encountering is if you are on WiFi, but the user has not yet agreed to the terms and conditions, as is common at Starbucks, the destination will still be reported as reachable.
The only real way to test network connectivity is to download something. For example, I frequently see Ping/Pong functions and heartbeat files on servers that are for this sole purpose. In this manor you can test not only your Internet, but if the server is functioning as expected.
Take a look at Network Apps for iPhone OS, Part 1 and Part 2.
Do not use Reachability to preflight your connection and just fire your request.
If you insist on using Reachability to test your connection befor you fire a request, use the method described by Jonah and test with your, only internal reachable, hostname.
For example:
// ...
if (wifiReachable) {
returnValue = [Reachability reachabilityWithHostname:#"internalserver.example.com"];
}
return returnValue;
}
Our web service has a "ping" function which is great for testing if the web service is available or not (I don't really care if the internet connection is available, right?) and I know how to test this condition, but how do I go about implementing this in my application? As in where do I test?
If there is no connection, the app doesn't crash of course, it just returns an empty table view or set of views. Should I put the ping before each request and generate an exception or error message when the ping fails? The web service request + response itself can take longer than the transmission of the actual data (latency I guess it would be) so I worry that implementing a Ping before each request might almost double the time it takes to perform each request. Or, should I be continually ping-ing and making sure there is a connection? What is the best practice?
Or should I even worry about it at all?
I was able to use the Reachability library as seen in the answer to How to check for an active Internet connection on iOS or OSX? . You can extend the library to include not only hostReachable but wsReachable with a little bit of work that is probably obvious to all.
iOS can provide you with callbacks once the network connectivity changes (e.g. from airplane mode to cell only to wifi and back). So you get notified whenever the network state changes and you don't need to keep pinging the server and can display proper online/offline messages.
Have a look at the SCNetworkReachabilitySetCallback method in the NetworkReachability.h header.
I've looked at Reachability sample from apple and another sample from "Iphone developer's cook book"
Here are steps to test ip/port reachability
construct sockaddr_in variable with given ip/port.
call SCNetworkReachabilityCreateWithAddress with the address
call SCNetworkReachabilityGetFlags and see if kSCNetworkFlagsReachable is set.
I find that whatever valid(valid-range) ip/port I put to test, my code says it's reachable even though they are not actually reachable when i ping or telnet test.
(I have seen other SO posts where reachability test to specific ip always succeed)
Reachability reachabilityWithAddress does not work
is SCNetworkReachability.. call only checks the validity of argument(ip address or hostname)? ie, do they actually send a packet(or do connect) to the given address to test reachability?
I can implement the async connect with timeout myself, but it's subtle matter how long the timeout should be not to be rejected by apple reviewers.(I am worried if it takes too long, apple reviewers might think my app is not handling network reachability at all)
Thank you
To answer your question based on the comments above, according to the SCNetworkReachability Reference
A remote host is considered reachable
when a data packet, sent by an
application into the network stack,
can leave the local device.
Reachability does not guarantee that
the data packet will actually be
received by the host.
This will not be able to check the status of your server but just make sure it can get a data packet out.
Apple wants for your app to elegantly fail if there are any network related issue, checking to see if internet is available using Reachability is the first step. If Reachability fails you can assume that you wont be able a server and alert the user immediately. The next steps are to properly handle errors returned by your server such as a 400 bad request, 404 file not found, setting a reasonable timeout, and not blocking the UI during long downloads while showing some sort of status indicator.
I am trying to access 61616 in my iPhone app and the SCReachability code indicates that I have a valid network, but I time out trying to write to 61616. Does anyone know:
A. If the iPhone EDGE/3G network has a limited port range or isn't allowed to connect to this port?
B. How I can check explicitly for access to this port. Here is my "is the network reachable" code (borrowed from Apple's examples), which checks for "foo.bar.com" but doesn't show how to check for "foo.bar.com:61616".
Any help is appreciated!
- (BOOL)isDataSourceAvailable{
static BOOL checkNetwork = YES;
BOOL _isDataSourceAvailable = NO;
if (checkNetwork) { // Since checking the reachability of a host can be expensive, cache the result and perform the reachability check once.
checkNetwork = NO;
Boolean success;
const char *host_name = "foo.bar.com";
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, host_name);
SCNetworkReachabilityFlags flags;
success = SCNetworkReachabilityGetFlags(reachability, &flags);
_isDataSourceAvailable = success && (flags & kSCNetworkFlagsReachable) && !(flags & kSCNetworkFlagsConnectionRequired);
CFRelease(reachability);
}
return _isDataSourceAvailable;
}
The SCNetworkReachability API only checks whether the address can be routed to. Quoting the documentation:
"Reachability" reflects whether a data
packet, sent by an application into
the network stack, can leave the local
computer. Note that reachability does
not guarantee that the data packet
will actually be received by the host.
This has nothing to do with NAT or port restrictions. Routing is based on addresses - not on ports. So all you can find out (via SCNetworkReachability API) is whether you could (in theory) reach the machine's interface. It does not try to establish a connection on a certain port.
So in order to find out whether that service is reachable you will have to try and test yourself. Preferably when the SCNetworkReachability API tells you that a connection can be established. Just try to connect to the server on port 61616 and see whether you get a connection or a timeout. Proper timeout values and handling is crucial here.
This is something that varies a lot from not just carrier to carrier but from contract to contract. For example, here in the UK O2 restrict internet access only to web addresses (presumably ports 80 and 443 but I didn't check) for pay-as-you-go customers but allow more-or-less free access for people on a contract. (I would hope that it's a little more open for iPhone PAYG customers.)
I think the practical upshot of this is that you can't assume access to high ports everywhere in the world.
I'm not sure that there's a simple way to check that a particular port is open, probably your best option is to use a "reasonable" timeout. Of course, there are a number of reasons you might get the timeout so your error would have to be suitable vague.
If your iPhone is connected over EDGE/Mobile, it might be behind a NAT gateway thus you being unable to contact it. At least that's the case with T-Mobile Germany. The iPhone gets an RFC IP address by T-Mobile (172.16.x.x).
I would test it with the iPhone connected to your local WiFi net and -- if possible -- generally design the app in a way that the iPhone contacts a server and then the server can communicate with the phone.
Are you trying to contact your iPhone from an external machine?
That likely does not work. Usually the GPRS/EDGE/UMTS infrastructure blocks incoming connections. Otherwise a mobile subscriber could be billed for unwanted traffic he did not request. (Imagine someone pinging your iPhone once per second for the next six weeks. You would pay for that...)
Solution is to establish a connection from the mobile device to the remote machine and then let the remote machine use that for traffic.