美文网首页
iOS 的 Reachability 你使用的对吗?

iOS 的 Reachability 你使用的对吗?

作者: brownfeng | 来源:发表于2021-04-19 13:02 被阅读0次

iOS 的 Reachability 你使用的对吗?

问题背景: 在使用Reachability监听网络时, 在初次启动以后多次回调!

最近在开发一个项目时, 使用iOS的官方DemoReachability, 几乎没有思考就直接使用原来项目中的代码:

  // 监听 remote host name
  // Change the host name here to change the server you want to monitor.
  NSString *remoteHostName = @"www.baidu.com";
    // 创建一个 host 链接检测器 -> 首先进行DNS解析!!!
    self.hostReachability = [Reachability reachabilityWithHostName:remoteHostName];
    [self.hostReachability startNotifier]; // 启动监听

但是最近在ceshi-wifi(only-v6)情况下, 网络状态的callback回调总是展示NotReachable !!!

在仔细研究了Apple的Demo Reachability 以后, 有了答案, 具体关键信息如下:

Note: Reachability cannot tell your application if you can connect to a particular host, only that an interface is available that might allow a connection, and whether that interface is the WWAN. To understand when and how to use Reachability

简单点说, Reachability能做的就是:

  1. 可以告诉你哪个网口可以与给定的Host建立连接.
  2. 可以建立的网口究竟是WIFI还是WWAN, 如果是WWAN, 那么具体是3g, 4g or 5g!

然后针对Demo中的两个核心API, Demo也拥有如下解释:

- reachabilityWithHostName and SCNetworkReachabilityCreateWithName:  Internally, this API works be resolving the host name to a set of IP addresses (this can be any combination of IPv4 and IPv6 addresses) and establishing separate monitors on all available addresses.

- reachabilityWithAddress and SCNetworkReachabilityCreateWithAddress:  To monitor an IPv6 address, simply pass in an IPv6 `sockaddr_in6 struct` instead of the IPv4 `sockaddr_in struct`.

- reachabilityForInternetConnection:  This monitors the address 0.0.0.0, which reachability treats as a special token that causes it to actually monitor the general routing status of the device, both IPv4 and IPv6.

简单解释:

  1. reachabilityWithHostName, 调用这个API以后, 操作系统首先会使用LocalDNS解析Host对应的IP List(可能有多个IP, 并且可能IPv4&IPv6都有), 然后底层会针对各个IP, 去建立多个监听器去针对all available addresses!!!

    1. 这里availabel addresses 值得研究! 举个例子, 我们在上面在ipv6-only的wifi中, 监听www.baidu.com , baidu的只有ipv4-only的ip, 因此是not available 的!!!
    2. 方案会使用LocalDNS服务去解析Host! 这里很有可能因为DNS解析缓慢, 从而导致我们在callback回调中收到多次信息, 在DNS解析还没有成功时, 收到Not Reachable, 在DNS解析成功, 获取IP并建立监听以后, 监听到Reachable!!!
  2. reachabilityForInternetConnection 方案使用0.0.0.0这个特殊的IP, 是让操作系统帮我们监听是否在本地网络连接中有出口路由, 或者说是否有本地网关gateway, 并且会同时监听Ipv4Ipv6的出口gateway

另外Apple 在Demo中提示:


By default, the application uses www.apple.com for its remote host. You can change the host it uses in APLViewController.m by modifying the value of the remoteHostName variable in -viewDidLoad.
 
IMPORTANT: Reachability must use DNS to resolve the host name before it can determine the Reachability of that host, and this may take time on certain network connections.  Because of this, the API will return NotReachable until name resolution has completed.  This delay may be visible in the interface on some networks.
 
The Reachability sample demonstrates the asynchronous use of the SCNetworkReachability API. You can use the API synchronously, but do not issue a synchronous check by hostName on the main thread. If the device cannot reach a DNS server or is on a slow network, a synchronous call to the SCNetworkReachabilityGetFlags function can block for up to 30 seconds trying to resolve the hostName. If this happens on the main thread, the application watchdog will kill the application after 20 seconds of inactivity.
 
SCNetworkReachability API's do not currently provide a means to detect support for device level peer-to-peer networking, including Multipeer Connectivity, GameKit, Game Center, or peer-to-peer NSNetService.

关键信息如下:

  1. 由于reachabilityWithHostName会使用DNS, 而DNS耗时不定, the API will return NotReachable until name resolution has completed!
  2. 注意使用reachabilityWithHostName时, 由于DNS解析时间不定, 也有可能会解析失败从而导致超时, 超时时间长达20+s. 因此Apple 建议我们不要使用同步API, 而是添加到Runloop中, 使用异步方式调用API. 具体异步的方式参考demo.

另外Apple也告知了, 我们针对Reachability的最佳实践Reachability最佳实践, 简单总结一下:

如果是用户操作触发的网络请求:

  1. 如果网络连接失败了, 可以创建SCNetworkReachability 去检测具体失败的原因

    1. 如果是因为传输过程失败, 那么重新连接
    2. 如果是因为host unreachable!!! 最好等待我们注册的Reachability callback 回调, 等待 Host Reachable 以后, 重新连接!
  2. 不要在每个网络请求之前调用SCNetworkReachability 去检测Host的reachable!!!!

  3. 并且即使我们通过SCNetworkReachability 检测到指定的 Host 是使用WWAN也并不表名, 请求并不一定会从WWAN发出!!

最终我们的总结如下:

  1. 如果我们需要监听本地的网络连接状态!!! 使用reachabilityForInternetConnection ,一般而言我们对APP进行全局监听的时, 基本用这个就行!!!
  2. 如果我们需要针对某一个Host监听它的状态(监听的是DNS解析后的Ipv4/Ipv6), 使用reachabilityWithHostName
  3. 注意SCNetworkReachability返回Reachable并不保证指定的Host可以访问到!!! 只是数据会从设备终端发出!!! 能不能被对端的Host接受是另外一码事, 如果需要知道是能否对对端Host接受到, 请使用PING/PING6, 或者第三方的 RealReachability

reachabilityWithHostName 监听的Host一定是在项目中关注的某个接口的Host, 而不是我们随便设置的一个Host

相关文章

网友评论

      本文标题:iOS 的 Reachability 你使用的对吗?

      本文链接:https://www.haomeiwen.com/subject/iisilltx.html