使用Network.framework检测UDP客户端断开连接

6
我正在尝试确定使用Network.framework时UDP客户端停止向服务器发送数据包的时间。
我已经构建了一个小例子,演示了当客户端连接被取消时,服务器无法改变状态为“已取消”。
客户端示例:
import Foundation
import Network

func sendMessage(on connection: NWConnection) {
    connection.send(content: "hello".data(using: .utf8), completion: .contentProcessed({error in
        if let error = error {
            print("error while sending hello: \(error)")
            return

        }

        connection.receiveMessage {data, context, isComplete, error in
            if let error = error {
                print("error while receiving reply: \(error)")
                return

            }

            connection.cancel()

        }

    }))
}

var connection: NWConnection = {
    let connection = NWConnection(
        to: .service(
            name: "Hello",
            type: "_test._udp",
            domain: "local",
            interface: nil
        ),
        using: .udp
    )

    connection.stateUpdateHandler = {newState in
        switch newState {
        case .ready:
            sendMessage(on: connection)
        case .failed(let error):
            print("client failed with error: \(error)")
        case .cancelled:
            print("Cancelled connection")
        default:
            break
        }
    }

    return connection
}()

connection.start(queue: DispatchQueue(label: "test"))

RunLoop.main.run()

示例服务器:

import Foundation
import Network

func receive(on connection: NWConnection) {
    connection.receiveMessage { (data, context, isComplete, error) in
        if let error = error {
            print(error)
            return

        }

        connection.send(content: "world".data(using: .utf8), completion: .contentProcessed({error in
            if let error = error {
                print("error while sending data: \(error)")
                return

            }

        }))

        receive(on: connection)

    }

}

var listener: NWListener = {
    let listener = try! NWListener(using: .udp)

    listener.service = NWListener.Service(name: "Hello", type: "_test._udp", domain: nil, txtRecord: nil)
    listener.newConnectionHandler = {newConnection in
        newConnection.stateUpdateHandler = {newState in
            switch newState {
            case .ready:
                receive(on: newConnection)
            case .failed(let error):
                print("client failed with error: \(error)")
            case .cancelled:
                print("Cancelled connection")
            default:
                break
            }
        }

        newConnection.start(queue: DispatchQueue(label: "new client"))


    }
    return listener
}()

listener.start(queue: DispatchQueue(label: "test"))

RunLoop.main.run()

当客户端在服务器运行时运行时,客户端发送和接收一个数据包,然后被取消。客户端会打印“连接已取消”。然而,在服务器上的NWConnection状态不会改变,并且当没有从客户端读取数据时,connection.receiveMessage会静默失败。
我期望服务器连接的状态要么改变,要么即使没有数据存在,receiveMessage也会调用其完成处理程序(毕竟data是Data?)。
因此,我不确定如何检测使用Network.framework的UDP服务器时客户端停止发送数据包。我应该如何检测“断开连接”的客户端?

我画了一张图来回答你在 https://dev59.com/qbLma4cB1Zd3GeqPYEIm#59439022 上的问题。 - Victor Kushnerov
1个回答

4
一个UDP服务器无法通过网络获得有关UDP客户端是否已断开连接或离开的任何信息,除非客户端显式地通过UDP、TCP或其他侧通道发送某种附加消息来报告其断开状态。因此,除了服务器本身出现问题外,没有任何东西可以更改NWConnection状态。

也许服务器可以在达成某些约定或协商的超时时间内没有某种活动发生后假定断开连接。 或者数据包的数量、数据字节数等。然后关闭连接本身。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接