iOS Network Connectivity - kgleong/software-engineering GitHub Wiki
Network Connectivity
Checking for Connectivity
NOTE: The following code is a useful learning reference, but should never be used to perform a pre-check for network availability. According to the Apple Developer documents:
The Reachability APIs (see SCNetworkReachability Reference) are intended for diagnostic purposes after identifying a connectivity issue.
Many apps incorrectly use these APIs to proactively check for an Internet connection by calling the SCNetworkReachabilityCreateWithAddress method and passing it an IPv4 address of 0.0.0.0, which indicates that there is a router on the network.
However, the presence of a router doesn’t guarantee that an Internet connection exists. In general, avoid preflighting network reachability. Just try to make a connection and gracefully handle failures. If you must check for network availability, avoid calling the SCNetworkReachabilityCreateWithAddress method. Call the SCNetworkReachabilityCreateWithName method and pass it a hostname instead.
Some apps also pass the SCNetworkReachabilityCreateWithAddress method an IPv4 address of 169.254.0.0, a self-assigned link-local address, to check for an active Wi-Fi connection. To check for Wi-Fi or cellular connectivity, look for the network reachability flag kSCNetworkReachabilityFlagsIsWWAN instead.
Term | Description |
---|---|
socket | A connection endpoint in that allows communication between two processes. The processes can be on the same or different machines. |
sockaddr_in |
Socket address in. Local or remote address used to connect a socket to receive or send data |
sin |
Abbreviation for socket address in |
import SystemConfiguration
public class NetworkUtility {
class func isConnected() -> Bool {
/*
Initializes a sockaddr_in struct with all 0s.
A sockaddr_in struct contains the following fields:
AF_NET is the internetwork address family. Usually used for
internet requests using the UDP, TCP protocols.
struct sockaddr_in {
short int sin_family; // address family. Usually AF_NET
unsigned short int sin_port; // port
struct in_addr sin_addr; // 32-bit network address
unsigned char sin_zero[8]; // not used
};
*/
var zeroAddress = sockaddr_in()
// set the length and address family of the socket address
zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
/*
SCNetworkReachabilityCreateWithAddress expects a sockaddr.
Casts zeroAddress, which is a sockaddr_in to a sockaddr.
0.0.0.0 is the default route, hence the variable name:
defaultRouteReachability.
*/
guard let defaultRouteReachability: SCNetworkReachability =
// Creates a pointer to zeroAddress and passes the pointer to the
// supplied closure.
withUnsafePointer(
to: &zeroAddress,
{
(zeroAddressPointer: UnsafePointer<sockaddr_in>)
in
// Casts the pointer to type sockaddr.
// capacity is the number of elements.
zeroAddressPointer.withMemoryRebound(to: sockaddr.self, capacity: 1) {
zeroSockAddress in
// Pass nil for the default allocator.
SCNetworkReachabilityCreateWithAddress(nil, zeroSockAddress)
}
}
) else {
// SCNetworkReachabilityCreateWithAddress returned nil, so
// a network issue exists.
return false
}
/*
SCNetworkReachabilityFlags contains reachability data for a given
network address.
Populate the flags with the reachability results for 0.0.0.0.
*/
var flags = SCNetworkReachabilityFlags()
if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
return false
}
// address can be reached with the current network configuration
let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
// address can be reached but a network connection is still required to
// successfully connect.
let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
return (isReachable && !needsConnection)
}
}
NetworkUtility.isConnected()