Swift 如何为Network.framework编写NWProtocolFramer,使用分隔符将流拆分为帧?

Swift 如何为Network.framework编写NWProtocolFramer,使用分隔符将流拆分为帧?,swift,tcp,network.framework,Swift,Tcp,Network.framework,我尝试使用以下代码创建一个成帧器,将ASCII字节流拆分为由管道ASCII字符分隔的帧:“|” 问题是,从我得到一个不以“|”结尾的块的那一刻起,框架构建者就被卡在该块上。因此,这个不完整块之后的其他块永远不会完全到达framer.parseInput(…)调用。因为它总是解析最小完整长度的块,因此永远不会到达下一个“|”的位置 下面是这个问题的简单再现: 创建TCP服务器 设置服务器,以便在客户端连接时发送消息块 使用上面的框架器连接到服务器(在1中创建) 开始接收消息 Swift代码: im

我尝试使用以下代码创建一个成帧器,将ASCII字节流拆分为由管道ASCII字符分隔的帧:
“|”

问题是,从我得到一个不以
“|”
结尾的块的那一刻起,框架构建者就被卡在该块上。因此,这个不完整块之后的其他块永远不会完全到达
framer.parseInput(…)
调用。因为它总是解析
最小完整长度的块,因此永远不会到达下一个
“|”
的位置

下面是这个问题的简单再现:

  • 创建TCP服务器
  • 设置服务器,以便在客户端连接时发送消息块
  • 使用上面的框架器连接到服务器(在1中创建)
  • 开始接收消息
  • Swift代码:

    import Network
    
    let client = DispatchQueue(label: "Server")
    let server = DispatchQueue(label: "Client")
    let networkParameters = NWParameters.tcp
    networkParameters.defaultProtocolStack.applicationProtocols.insert(NWProtocolFramer.Options(definition: PipeFramer.definition), at: 0)
    let server = try! NWListener(using: .tcp)
    
    server.newConnectionHandler = { connection in
        print("server: new connection from", connection.endpoint)
    
        print("server (client \(connection.endpoint)): state", connection.state)
    
        connection.viabilityUpdateHandler = { viable in
            print("server (client \(connection.endpoint)): state", connection.state)
            if viable {
                print("server: sending")
                connection.send(content: "A|Be||Sea".data(using: .utf8)!, isComplete: false, completion: .idempotent)
    
                serverQueue.asyncAfter(deadline: .now() + 5) {
                    print("server: sending second part")
                    connection.send(content: " is longer than expected|0|".data(using: .utf8)!, isComplete: true, completion: .idempotent)
                }
                serverQueue.asyncAfter(deadline: .now() + 8) {
                    print("server: sending last part")
                    connection.send(content: "Done|".data(using: .utf8)!, isComplete: true, completion: .idempotent)
                }
            }
        }
    
        connection.start(queue: serverQueue)
    }
    
    server.stateUpdateHandler = { state in
        print("server:", state)
        if state == .ready, let port = server.port {
            print("server: listening on", port)
        }
    }
    
    server.start(queue: serverQueue)
    
    let client = NWConnection(to: .hostPort(host: "localhost", port: server.port!), using: networkParameters)
    
    func receiveNext() {
        client.receiveMessage { (data, context, complete, error) in
            let content: String
            if let data = data {
                content = String(data: data, encoding: .utf8) ?? data.description
            } else {
                content = data?.debugDescription ?? "<no data>"
            }
            print("client: received \"\(content)\"", context.debugDescription, complete, error?.localizedDescription ?? "No error")
    
            receiveNext()
        }
    }
    
    client.stateUpdateHandler = { state in
        print("client:", state)
    
        if state == .ready {
            print("client: receiving")
            receiveNext()
        }
    }
    
    client.start(queue: clientQueue)
    
    导入网络
    让客户端=DispatchQueue(标签:“服务器”)
    让服务器=调度队列(标签:“客户端”)
    让networkParameters=NWParameters.tcp
    networkParameters.defaultProtocolStack.applicationProtocols.insert(NWProtocolFramer.Options(定义:PipeFramer.definition),位于:0)
    让服务器=试试!NWListener(使用:.tcp)
    server.newConnectionHandler={中的连接
    打印(“服务器:新连接自”,connection.endpoint)
    打印(“服务器(客户端\(connection.endpoint)):状态”,connection.state)
    connection.viabilityUpdateHandler={viable in
    打印(“服务器(客户端\(connection.endpoint)):状态”,connection.state)
    如果可行的话{
    打印(“服务器:发送”)
    connection.send(内容:“A | Be | | Sea”。数据(使用:.utf8)!,isComplete:false,completion:.幂等)
    serverQueue.asyncAfter(截止日期:.now()+5){
    打印(“服务器:发送第二部分”)
    connection.send(内容:“比预期的长| 0 |”。数据(使用:.utf8)!,isComplete:true,completion:.幂等)
    }
    serverQueue.asyncAfter(截止日期:.now()+8){
    打印(“服务器:发送最后一部分”)
    connection.send(内容:“Done |”。.data(使用:.utf8)!,isComplete:true,completion:.幂等)
    }
    }
    }
    connection.start(队列:serverQueue)
    }
    server.stateUpdateHandler={中的状态
    打印(“服务器:”,状态)
    如果state=.ready,则让port=server.port{
    打印(“服务器:侦听”,端口)
    }
    }
    server.start(队列:serverQueue)
    让client=NWConnection(到:.hostPort(主机:“localhost”,端口:server.port!),使用:networkParameters)
    func receiveNext(){
    client.receiveMessage{(数据、上下文、完成、错误)位于
    让内容:字符串
    如果let data=data{
    content=String(数据:数据,编码:.utf8)??data.description
    }否则{
    内容=数据?.debugDescription??“”
    }
    打印(“客户端:已接收\“(内容)\”,context.debugDescription,complete,error?。localizedDescription??“无错误”)
    receiveNext()
    }
    }
    client.stateUpdateHandler={state in
    打印(“客户端:”,状态)
    如果状态==.ready{
    打印(“客户:接收”)
    receiveNext()
    }
    }
    client.start(队列:clientQueue)
    
    结果:

    server: waiting(POSIXErrorCode: Network is down)
    server: ready
    server: listening on 54894
    client: preparing
    client: ready
    client: receiving
    server: new connection from ::1.53179
    server (client ::1.53179): state setup
    server (client ::1.53179): state ready
    server: sending
    client: parsing buffer: "A|Be||Sea"
    client: minLength set to 1
    client: parsing buffer: "Be||Sea"
    client: minLength set to 1
    client: parsing buffer: "|Sea"
    client: minLength set to 1
    client: parsing buffer: "Sea"
    client: minLength set to 4
    client: parsing buffer: ""
    client: minLength set to 1
    client: received "A" Optional(Network.NWConnection.ContentContext) true No error
    client: received "Be" Optional(Network.NWConnection.ContentContext) true No error
    client: received "<no data>" Optional(Network.NWConnection.ContentContext) true No error
    client: parsing buffer: "Sea"
    client: minLength set to 4
    server: sending second part
    client: parsing buffer: "Sea "
    client: minLength set to 5
    client: parsing buffer: "Sea i"
    client: minLength set to 6
    server: sending last part
    client: parsing buffer: "Sea is"
    client: minLength set to 7
    client: parsing buffer: "Sea is "
    client: minLength set to 8
    
    服务器:正在等待(POSIXErrorCode:网络已关闭)
    服务器:准备好了吗
    服务器:正在收听54894
    客户:准备
    客户:准备好了吗
    客户:收到
    服务器:来自::1.53179的新连接
    服务器(客户端::1.53179):状态设置
    服务器(客户端::1.53179):状态就绪
    服务器:正在发送
    客户端:解析缓冲区:“A | Be | Sea”
    客户端:minLength设置为1
    客户端:解析缓冲区:“Be | | Sea”
    客户端:minLength设置为1
    客户端:解析缓冲区:“| Sea”
    客户端:minLength设置为1
    客户端:解析缓冲区:“Sea”
    客户端:minLength设置为4
    客户端:正在分析缓冲区:“”
    客户端:minLength设置为1
    客户端:收到“A”可选(Network.NWConnection.ContentContext)true无错误
    客户端:收到“Be”可选(Network.NWConnection.ContentContext)true无错误
    客户端:接收到“”可选(Network.NWConnection.ContentContext)true无错误
    客户端:解析缓冲区:“Sea”
    客户端:minLength设置为4
    服务器:发送第二部分
    客户端:解析缓冲区:“Sea”
    客户端:minLength设置为5
    客户端:解析缓冲区:“Sea i”
    客户端:minLength设置为6
    服务器:正在发送最后一部分
    客户端:解析缓冲区:“Sea是”
    客户端:minLength设置为7
    客户端:解析缓冲区:“Sea是”
    客户端:minLength设置为8
    
    请注意,客户端从未收到第四条和第五条消息。我应该如何编写框架程序,以便它在传入的不完整块之后接收消息


    工具书类

      • 我也有同样的问题。。。我正在使用的网络协议也有一个简单的分隔符,用于分隔每个“消息”,并且该协议没有告诉我预期内容的标题。通常在缓冲区的末尾,只有一个不带分隔符的部分消息,需要读取更多字节才能获取消息的其余部分。大概是这样的:

        |              PACKET A              |              PACKET B             |
        |<message>|<message>|<message><mess...age>|<message><message><message><m...essage>
             1         2         4      5a    5b      6        7        8      9a    9b
        
        Note:
        delimiter = | - single character
        lhsMessage = message 5a 
        rhsMessage = message 5b
        
        |数据包A |数据包B|
        ||||
        1 2 4 5a 5b 6 7 8 9a 9b
        注:
        分隔符=|-单个字符
        LHS消息=消息5a
        rhsMessage=消息5b
        
        即使在观看了WWDC和苹果的其他示例之后,我仍然不完全理解handleInputparseInput应该如何工作

        我假设我可以使用(
        lhsMessage.count+1
        )简单地从handleInput返回,它会将部分消息保留在当前缓冲区中,并向parseInput可以检查的缓冲区(即数据包B)中添加额外的字节

        然而,它似乎确实是这样工作的。相反,我将lhsMessage的值存储在一个类var中,然后返回
        lh
        
        |              PACKET A              |              PACKET B             |
        |<message>|<message>|<message><mess...age>|<message><message><message><m...essage>
             1         2         4      5a    5b      6        7        8      9a    9b
        
        Note:
        delimiter = | - single character
        lhsMessage = message 5a 
        rhsMessage = message 5b