ios - 失败(POSIXErrorCode : Address already in use)

标签 ios swift sockets networking tcp

我确实在 Apple 开发门户上问过同样的问题,还有其他人也有同样的问题。
我在 GitHub 上创建了简单的可重现项目:(按照 README 中的步骤操作)
https://github.com/ChoadPet/NWListenerTest.git

我有屏幕和现在 ConnectionListenerinitialized并关闭它 deinitialized (称为 stopListening() )。
第一次打开屏幕一切正常:

Listener stateUpdateHandler: waiting(POSIXErrorCode: Network is down)
Listener stateUpdateHandler: ready

"📞 New connection: 10.0.1.2:50655 establish"
"Connection stateUpdateHandler: preparing"
"Connection stateUpdateHandler: ready"
但对于接下来的 n 次尝试,只有此消息:
[] nw_path_evaluator_evaluate NECP_CLIENT_ACTION_ADD error [48: Address already in use]
[] nw_path_create_evaluator_for_listener nw_path_evaluator_evaluate failed
[] nw_listener_start_locked [L3] nw_path_create_evaluator_for_listener failed

Listener stateUpdateHandler: waiting(POSIXErrorCode: Network is down)
Listener stateUpdateHandler: failed(POSIXErrorCode: Address already in use)

It happens on iPhone 6 iOS 12.4.1, iPhone Xs Max iOS 13.3, iPhone 11 Pro iOS 13.5.1(also iOS 13.6)


but NOT on iPhone 7 Plus iOS 12.1.4, iPhone 11 iOS 13.5.1.



这是我用于监听入站连接的代码:
final class ConnectionListener {
        
  var dataReceivedHandler: ((Data) -> Void)?
   
  private let port: UInt16
  private let maxLength: Int
   
  private var listener: NWListener!
  private var connection: NWConnection!
   
  init(port: UInt16, maxLength: Int) {
    self.port = port
    self.maxLength = maxLength
  }
   
  deinit {
    print("❌ Deinitialize \(self)")
  }
   
  // MARK: Public API
   
  func startListening() {
    let parameters = NWParameters.tcp
    parameters.allowLocalEndpointReuse = true
    self.listener = try! NWListener(using: parameters, on: NWEndpoint.Port(integerLiteral: port))
    self.listener.stateUpdateHandler = { state in print("Listener stateUpdateHandler: \(state)") }
    self.listener.newConnectionHandler = { [weak self] in self?.establishNewConnection($0) }
    self.listener.start(queue: .main)
  }
   
  func stopListening() {
    listener.cancel()
    connection?.cancel()
  }
   
  // MARK: Private API
   
  private func establishNewConnection(_ newConnection: NWConnection) {
    connection = newConnection
    debugPrint("📞 New connection: \(String(describing: connection.endpoint)) establish")
    connection.stateUpdateHandler = { [weak self] state in
      guard let self = self else { return }
      debugPrint("Connection stateUpdateHandler: \(state)")
      switch state {
      case .ready:
        debugPrint("Connection: start receiving ✅")
        self.receive(on: self.connection)
      default: break
      }
    }
    self.connection.start(queue: .main)
  }
   
  private func receive(on connection: NWConnection) {
    connection.receive(minimumIncompleteLength: 1, maximumLength: maxLength, completion: { [weak self] content, context, isCompleted, error in
      guard let self = self else { return }
      if let frame = content {
        self.dataReceivedHandler?(frame)
      }
      self.receive(on: connection)
    })
  }
   
}
如果您需要更多信息,请告诉我。
谢谢!

最佳答案

在您的应用程序“失败”后,单击 STOP,等待 2 分钟,然后再次尝试 START。我向你保证,它会再次正常工作。我试过你的代码,它最初对我来说也“失败”了。
发生了什么:您遇到了 TCP 关闭超时。把它想象成一个邮政服务,你是收件人。如果邮政服务说“我们已停止向您递送”,您可以立即删除整个邮箱,不会出现任何递送失败的情况。这相当于关闭 TCP 连接的客户端。但是您告诉邮政服务您接受递送,您实际上已经收到了,并且您决定搬出。这相当于服务器关闭 TCP 连接。邮箱(你的 iOS 应用进程)还在,你只是不想再接收了。在现实世界中,在每个人(在合理范围内)注意到之前,您应该确保至少有更多时间在邮箱上显示您的名字。在 TCP 中,这称为 TIME_WAIT .
TCP 主要不是为第二种情况构建的,但无论如何它都在尽力避免丢失数据包,由于 TCP 路由,这些数据包只是在带外(晚于其他数据包)传送。特定的等待长度以特定操作系统标记和版本的 TCP 堆栈参数为单位指定。所以它可能在某些人身上更短,而在其他人身上可能更长。不应超过 2 分钟。
仔细考虑您的用例。你想通过关闭整个服务器来实现什么,而应用程序仍在运行?

  • 客户端应该关闭,而不是服务器
  • 服务器只能取消单个连接,而不是整个监听器
  • 服务器可以在它仍在运行时拒绝新连接
  • 关于ios - 失败(POSIXErrorCode : Address already in use),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63052894/

    相关文章:

    ios - 如何根据 View 图层的颜色更改状态栏颜色

    iPhone 上的 iOS 8 多个 <select> 严重错误?

    ios - 将 PHAsset 转换为 UIImage 时失去透明度

    ios - 用于在 Swift 中获取 facebook 好友列表的图形路径和参数

    Java 网络 - 在同一线程中的不同端口上并行启动多个服务器套接字

    python - 如何故意导致Errno 23 ENFILE

    python - 如何检查 IP 地址或代理是否正常工作

    ios - 从其类型创建一个 UIViewController 具体类

    ios - 无法快速提取模型类型

    具有不接受输入参数类型的通用参数类型的 Swift 高阶函数(Church pair aka cons)