【问题标题】:Network connection check crashing on IPv6 networks in SwiftSwift 中 IPv6 网络上的网络连接检查崩溃
【发布时间】:2016-07-22 01:47:34
【问题描述】:

我最近因为与 IPv6 不兼容而遭到拒绝。调用以下代码时,应用程序导致崩溃。我怀疑崩溃是因为它使用了SCNetworkReachabilityCreateWithAddress,而 Apple 建议不要再使用它。

谁能帮我把下面的代码与 IPv6 和 IPv4 兼容?

代码

import Foundation
import SystemConfiguration

public class Reachability {

    class func isConnectedToNetwork() -> Bool {

        var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
        zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
        zeroAddress.sin_family = sa_family_t(AF_INET)

        let defaultRouteReachability = withUnsafePointer(&zeroAddress) {
            SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0)).takeRetainedValue()
        }

        var flags: SCNetworkReachabilityFlags = 0
        if SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) == 0 {
            return false
        }

        let isReachable = (flags & UInt32(kSCNetworkFlagsReachable)) != 0
        let needsConnection = (flags & UInt32(kSCNetworkFlagsConnectionRequired)) != 0

        return isReachable && !needsConnection
    }

}

代码来源:

Check for internet connection availability in Swift

确实加载了视图代码调用:

if Reachability.isConnectedToNetwork() == false
{
      // internet is down
      let error = NSError(domain: "", code: 3, userInfo: nil)           let alertView = createDefaultAlertError(error.code)
      let tryAgainAction = UIAlertAction(title: ClassGeneralMessages().userMessageTryAgain, style: UIAlertActionStyle.Default) { (UIAlertAction) in                
}
else
{
     // internet is ok
     // run more code here
}

【问题讨论】:

  • 请在调用该函数时显示您的代码。
  • @Christian Abella,代码已添加。
  • 我面临同样的拒绝问题。你能解决这个问题吗?如何解决?请提出建议。

标签: ios swift ipv6


【解决方案1】:

来自Apple's documentation on supporting IPv6-only networks

无需预检即可连接

可达性 API(请参阅 SCNetworkReachability Reference)用于在识别连接问题后进行诊断。许多应用程序错误地使用这些 API 来主动检查 Internet 连接,方法是调用 SCNetworkReachabilityCreateWithAddress 方法并向其传递 IPv4 地址 0.0.0.0,这表明网络上有路由器。但是,存在路由器并不能保证存在 Internet 连接。一般来说,避免预检网络可达性。只需尝试建立连接并优雅地处理故障。如果您必须检查网络可用性,请避免调用SCNetworkReachabilityCreateWithAddress 方法。调用 SCNetworkReachabilityCreateWithName 方法并改为传递一个主机名。

您的应用似乎在做它不建议做的两件事:

  1. 使用可达性 API 执行预检,而不是仅在出现连接问题时。
  2. 将 IPv4 文字而不是主机名传递给可达性 API。

为了解决这个问题,我建议不要预先检查网络连接,而是处理网络代码中的错误。

【讨论】:

  • 我对这个问题做了一些更新。该应用程序再次被拒绝。我正在关注 Apple 的文档。此外,不预先检查连接。正如您所说,所有网络错误都由 CloudKit 操作处理。我正在使用 xCode 7.3.1 为 iOs9 构建。完全迷失在这一场比赛中。
  • 你不只是做了一些小的更新,you completely changed the question
  • 它被恢复到对你的回答更有意义的那个@bdash
【解决方案2】:

您遇到了崩溃,因为您在应该在主 UI 线程中运行的代码中显示了一个警报。将您的 UI 代码放入主 UI 线程的 dispatch_async 中,它应该可以解决问题。

dispatch_async(dispatch_get_main_queue(),
{
   let error = NSError(domain: "", code: 3, userInfo: nil)           let alertView = createDefaultAlertError(error.code)
      let tryAgainAction = UIAlertAction(title: ClassGeneralMessages().userMessageTryAgain, style: UIAlertActionStyle.Default) { (UIAlertAction) in }
})

【讨论】:

  • 如果在 IPv4 上出现错误,则会弹出警报视图,但不会崩溃。这让我认为它与 UI 无关似乎调用检查 IPv6 网络时“isConnectedToNetwork”正在崩溃这就是我认为 Apple 正在考虑的问题:确保您没有将 IPv4 地址文字以点表示法传递给 API,例如 getaddrinfo和 SCNetworkReachabilityCreateWithName。相反,使用高级网络框架和与地址无关的 API 版本,例如 getaddrinfo 和 getnameinfo,并向它们传递主机名或完全限定域名 (FQDN)。请参阅 getaddrinfo(3) Mac OS X Dev..
  • 如果您 (GulSoySauce) 将直接引用 Apple 的“指南和示例说明”,那么您应该将其放在引号中并提供完整的参考。否则就是抄袭!!从“确保你不是……”到结尾的所有文本都来自 Apple 文档。只是说。
【解决方案3】:

试试这个:

class func isConnectedToNetwork() -> Bool
        {
            var zeroAddress = sockaddr_in6()
            zeroAddress.sin6_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
            zeroAddress.sin6_family = sa_family_t(AF_INET6)

            let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) {
                $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {zeroSockAddress in
                    SCNetworkReachabilityCreateWithAddress(nil, zeroSockAddress)
                }
            }

            var flags = SCNetworkReachabilityFlags()
            if !SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) {
                return false
            }
            let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
            let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
            return (isReachable && !needsConnection)
        }

【讨论】:

    【解决方案4】:
        func isConnectedToNetwork() -> Bool {
        
        var zeroAddress = sockaddr_in()
        zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
        zeroAddress.sin_family = sa_family_t(AF_INET)
        
        
        let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {zeroSockAddress in
                SCNetworkReachabilityCreateWithAddress(nil, zeroSockAddress)
            }
        }
        //Commented code only work upto iOS Swift 2.3
        //    let defaultRouteReachability = withUnsafePointer(to: &zeroAddress) {
        //
        //        SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
        //    }
        
        var flags = SCNetworkReachabilityFlags()
        
        if !SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) {
            return false
        }
        
        let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
        let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
        return (isReachable && !needsConnection)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多