Most apps rely heavily on the network, and an App with a good user experience must consider the changes in the network state.

In order to better user experience, we will display local or cached content when there is no network, and give users appropriate prompts. For network state detection, Apple provides Reachability, from which various frameworks have been derived. Compare the tonymillion/have a lot of famous Reachability and the AFNetworkReachabilityManager AFNetworking module, Their implementation principles are basically the encapsulation of Apple’s SCNetworkReachability API.

1, SCNetworkReachability (SystemConfiguration framework)

Get network status:

@property (nonatomic, strong) dispatch_source_t timer; @property (nonatomic, assign) SCNetworkReachabilityRef reachability; @property (nonatomic, strong) dispatch_queue_t serialQueue; -(void)dealloc { if (_reachability ! = NULL) { CFRelease(_reachability); _reachability = NULL; } } - (void)viewDidLoad { [super viewDidLoad]; Struct sockaddr_in zeroAddress; // Do any additional setup after loading the view. bzero(&zeroAddress, sizeof(zeroAddress)); zeroAddress.sin_len = sizeof(zeroAddress); zeroAddress.sin_family = AF_INET; _reachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress); _serialQueue = dispatch_queue_create("com.xmy.serialQueue", DISPATCH_QUEUE_SERIAL); __weak __typeof(self) weakSelf = self; _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue()); Dispatch_source_set_timer (_timer, DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC, 0.0 * NSEC_PER_SEC); dispatch_source_set_event_handler(_timer, ^{ __strong __typeof(weakSelf) strongSelf = weakSelf; NSLog(@" Connection status: %d", [strongSelf isConnectionAvailable]); }); dispatch_resume(_timer); [self startMonitor]; } - (BOOL)isConnectionAvailable { SCNetworkReachabilityFlags flags; / / get connection symbol BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags (_reachability, & flags); // If (! didRetrieveFlags) { NSLog(@"Error. Could not recover network reachability flags"); return NO; BOOL isReachable = ((flags & kSCNetworkFlagsReachable)! = 0); BOOL needConnection = ((flags & kSCNetworkFlagsConnectionRequired) ! = 0); return (isReachable && ! needConnection) ? YES : NO; } - (void)startMonitor { SCNetworkReachabilityContext context = {0, (__bridge void *)self, NULL, NULL, NULL}; if (SCNetworkReachabilitySetCallback(_reachability, ReachabilityCallback, &context)) { // Schedules the given target with the given run loop and mode. // SCNetworkReachabilityScheduleWithRunLoop(_reachability, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); // Schedule or unschedule callbacks for the given target on the given dispatch queue. SCNetworkReachabilitySetDispatchQueue(_reachability, _serialQueue); } } - (void)stopMonitor { SCNetworkReachabilitySetCallback(_reachability, NULL, NULL); // Unschedules the given target from the given run loop and mode. // SCNetworkReachabilityUnscheduleFromRunLoop(_reachability, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); SCNetworkReachabilitySetDispatchQueue(_reachability, NULL); } static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) { NSLog(@"%@, %d, %@", target, flags, info); }Copy the code

Advantages:

  • Simple to use, only one class, official Demo, easy to use
  • High sensitivity, basic network changes, basic immediately can be determined

Disadvantages:

  • Now popular public wifi, requires web authentication, authentication can not access the Internet, but the local connection has been established
  • A local network connection exists, but the signal is poor and the server cannot be connected
  • Whether to connect to a specified server, such as a server outside the domestic access wall

Apple’s Reachability has the following description to tell us that its capabilities are limited by this: The SCNetworkReachability programming interface allows an application to determine the status of a system’s current network configuration and the reachability of a target host. 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. When packets sent by an application to the network stack can leave the local device, the remote host is considered accessible and there is no guarantee that the host will actually receive the packets.

2, SimplePing

Ping is a common command used in Windows, Unix, Linux, and macOS. You can use the ping command to test whether packets can reach a specific host through the IP protocol and receive a response from the host. In this way, you can check whether the network connection is normal and the network connection speed, helping you analyze and determine network faults.

SimplePing is a ping function packaged by Apple. It uses resolve Host, CREATE socket(Send&Recv Data), ICMP packet resolution and checksum to perform ping. IPv4 and iPv6 are supported.

The ping function uses the Internet Control Message Protocol (ICMP), which defines a set of error messages. If a router or host fails to process an IP packet, it can send the error Message back to the source host:

ICMP USES: Error notification, information query, redirection, etc

[1] Error notification to sender; [2] Sender information query.

[1] is used when an error occurs during the processing of an IP packet by the other party’s computer. Send not only the fact that an error occurred, but also the reason for the error.

[2] is used when the sender’s computer asks the receiver’s computer for information. They were asked about a variety of things, such as basic confirmation of the existence of the machine with the target IP address, investigating the subnet mask of their own network, obtaining the time information of the other machine, etc.

Ping:

Ping timeout cause:

  • The target server does not exist
  • The time spent on packet communication is too long. Ping indicates timeout
  • The target server does not answer the ping command

SimplePing implementation:

Initialization of SimplePing:

let hostName = "www.baidu.com"
var pinger: SimplePing?
var sendTimer: NSTimer?
 
/// Called by the table view selection delegate callback to start the ping.
func start(forceIPv4 forceIPv4: Bool.forceIPv6: Bool) {
    let pinger = SimplePing(hostName: self.hostName)
    self.pinger = pinger
 
    // By default we use the first IP address we get back from host resolution (.Any)
    // but these flags let the user override that.
    if (forceIPv4 && !forceIPv6) {
        pinger.addressStyle = .ICMPv4
    } else if (forceIPv6 && !forceIPv4) {
        pinger.addressStyle = .ICMPv6
    }
 
    pinger.delegate = self
    pinger.start()
}
 
/// Called by the table view selection delegate callback to stop the ping.
func stop(a) {
    self.pinger?.stop()
    self.pinger = nil
 
    self.sendTimer?.invalidate()
    self.sendTimer = nil
     
    self.pingerDidStop()
}
 
/// Sends a ping.
/// Called to send a ping, both directly (as soon as the SimplePing object starts up) and
/// via a timer (to continue sending pings periodically).
func sendPing(a) {
    self.pinger!.sendPingWithData(nil)}Copy the code

Proxy method:

/// pinger.start() resolves the HostName callback after getting the IP address
func simplePing(pinger: SimplePing.didStartWithAddress address: NSData) {
    NSLog("pinging %@".MainViewController.displayAddressForAddress(address))
     
    // Send the first ping straight away.
    self.sendPing()
 
    // And start a timer to send the subsequent pings.
    assert(self.sendTimer = = nil)
    self.sendTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(MainViewController.sendPing), userInfo: nil, repeats: true)}/// The pinger.start() function fails to start the callback
func simplePing(pinger: SimplePing.didFailWithError error: NSError) {
    NSLog("failed: %@".MainViewController.shortErrorFromError(error))
     
    self.stop()
}
 
/// sendPingWithData Succeeded in sending data
func simplePing(pinger: SimplePing.didSendPacket packet: NSData.sequenceNumber: UInt16) {
    NSLog("#%u sent", sequenceNumber)
}
 
/// sendPingWithData failed to send data and returned an error message
func simplePing(pinger: SimplePing.didFailToSendPacket packet: NSData.sequenceNumber: UInt16.error: NSError) {
    NSLog("#%u send failed: %@", sequenceNumber, MainViewController.shortErrorFromError(error))
}
 
/// Ping receives a response after being sent
func simplePing(pinger: SimplePing.didReceivePingResponsePacket packet: NSData.sequenceNumber: UInt16) {
    NSLog("#%u received, size=%zu", sequenceNumber, packet.length)
}
 
/// Ping failed to receive the response packet
func simplePing(pinger: SimplePing.didReceiveUnexpectedPacket packet: NSData) {
    NSLog("unexpected packet, size=%zu", packet.length)
}
Copy the code

As shown in the code, ping hosts at regular intervals to see if they are running properly. Therefore, it is impossible for ping to determine network changes in time and there will be a certain delay. Reachability is used to check whether the current device is connected to the network, and SimplePing is used to check whether the server is connected.

3,RealReachability (Star: 3k)

4. Extension: Traceroute

The ping command may not determine whether the peer exists. To check the routing path between the host and the destination host, run the traceroute command. It is one of the typical implementations of ICMP, along with ping.

Traceroute does this by increasing the TTL value. Each time an ICMP packet passes through a router, the TTL value decreases by 1. When the TTL reaches 0, the router cancels the packet sending and sends an ICMP TTL timeout packet to the originator.

Command line test:

test1: > Traceroute -i baidu.comtraceroute: Warning: baidu.com has multiple addresses; using 220.18138.148.
traceroute to baidu.com (220.18138.148.), 64 hops max, 72 byte packets
 1  172.2562.254. (172.2562.254.)  2.198 ms  1.690 ms  1.437 ms
 2  172.25100.17. (172.25100.17.)  2.175 ms  1.795 ms  1.769 ms
 3  * * *
 4  * * *
 5  * * *
 6  * * *
 7  * * *
 8  * * *
 9  * * *
10  * * *
11  * * *
12  * * *
13  * * *
14  * * *
15  * * *
16  220.18138.148. (220.18138.148.)  29.700 ms  29.135 ms  29.127Ms test2: > Traceroute -i baidu.comtraceroute: Warning: baidu.com has multiple addresses; using 39.15669.79.
traceroute to baidu.com (39.15669.79.), 64 hops max, 72 byte packets
 1  172.2562.254. (172.2562.254.)  3.339 ms  1.993 ms  4.845 ms
 2  172.25100.17. (172.25100.17.)  2.146 ms  1.792 ms  1.971 ms
 3  * * *
 4  * * *
 5  * * *
 6  * * *
 7  * * *
 8  * * *
 9  * * *
10  * * *
11  * * *
12  * * *
13  * * *
14  * * *
15  * * *
16  * * *
17  * * *
18  39.15669.79. (39.15669.79.)  29.015 ms  27.569 ms  28.232 ms
Copy the code

Net-diagnosis (Star: 0.3K) With Net-Diagnosis, you can easily implement network diagnosis functions on iOS, such as ping, traceroute, mobile public network information, and port scanning.

Reference:

  1. Fully understand ICMP
  2. Ping and traceroute are implemented on iOS
  3. The principle and implementation of Traceroute