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