Swift网络框架与TCP

7
我正在使用Swift Network框架制作一个简单的测试应用程序。有一个服务器,一个客户端(都是iOS模拟器),并且已经成功地建立了它们之间的TCP连接。我正在尝试发送一系列短消息。
服务器正在发送由1到999的自然数组成的字符串。每个数字都作为单独的数据发送,isCompletecontentContext默认值分别为true.defaultMessage
var count = 0

func send(data: Data) {
    self.connection.send(content: data, completion: .contentProcessed( { error in
        if let error = error {
            self.connectionDidFail(error: error)
            return
        }
        self.count += 1
        let newData = "\(self.count)".data(using: .utf8)!
        if self.count < 1000 {
            self.send(data: newData)
        }
        print("connection \(self.id) did send, data: \(newData as NSData)")
    }))
}

客户端正在接收它们……

private func setupReceive() {
    nwConnection.receive(minimumIncompleteLength: 1, maximumLength: 65536) { (data, contentContext, isComplete, error) in
        if let data = data, !data.isEmpty {
            print("isComplete: \(isComplete)")
            print("isFinal: \(contentContext.isFinal)")
            let message = String(data: data, encoding: .utf8)
            print("connection did receive, data: \(data as NSData) string: \(message ?? "-" )")
        }
        if let error = error {
            self.connectionDidFail(error: error)
        } else {
            self.setupReceive()
        }
    }
}

...但是有些地方出了问题。一些消息看起来像它们的字节黏在一起(例如连续的消息“2”,“3”,“4”,“5”可能被接收成一个单一的消息“2345”)

对于所有接收到的消息,isComplete等于falsecontentContext属性isFinal等于true,而.defaultMessage.isFinal应该等于false

目前,我卡住了。我的参数使用错误了吗(我尝试了各种组合,但似乎没有一个有效的)?NWConnection是否在发送消息时丑陋地改变了它们?

如何发送一系列独立的消息?


代码的第一部分看起来很奇怪。你有一个名为"data"的变量作为内容。然后在几行之后创建了一个新变量名为"data"。 - El Tomato
1
@ElTomato 这只是一个本地变量。在函数范围内,它会覆盖具有相同名称的外部变量(例如函数参数)。但我会将其重命名,以使其更清晰明了。 - Sasha Dudkin
1个回答

0

我不熟悉这个 Network 框架。但是从阅读文档来看,似乎你直接使用传输层来传输消息。

没有应用层协议,客户端可能无法区分不同的消息。例如,使用 http 作为应用程序协议,在请求中有不同的参数来识别是否为完整的消息(Content-Length、Content-Encoding、Transfer-Encoding 等...)(希望专家能够确认这一点)

你可以定义自己的简单协议,以便在客户端进行解码。例如,你可以使用 <Message>your-message</Message> 来包装每个消息,并用它来标识客户端中的不同消息(你将会在这个过程中面临一些简单的缺点)

在开发自定义协议时需要考虑很多事情。如果你认真对待这个问题,最好先阅读一些相关的资料。

进一步阅读后,似乎提供了以下接收:

final func receiveMessage(completion: @escaping (Data?, NWConnection.ContentContext?, Bool, NWError?) -> Void)

...能够读取完整的数据。讨论部分将提供有关传输类型影响和所需帧逻辑的宝贵见解。


所以你认为在TCP层面上使用NWConnection发送完整的Data对象而不需要额外的协议是不可能的。我们只能发送原始的字节流,而不知道消息的结束位置。好吧,但这时isComplete标识的含义是什么?为什么不是所有接收到的字节都被组合起来,实际上大多数消息都会按预期作为完整的对象接收到? - Vladimir
请按照我所说的阅读讨论部分(https://developer.apple.com/documentation/network/nwconnection/3020638-receivemessage)。有一种方法可以使用上述函数接收完整的消息,而不是您使用的那种方法(读取一定范围的字节)。其影响在讨论部分中详细说明。 - jms
@jms 是的,我正在尝试直接使用传输层。并不确定那些HTTP头部及其目的 - 它可能是完整性控制或其他什么东西。但是苹果文档(据我理解)坚持认为我应该能够使用网络来控制完成消息。'isComplete'和'isFinal'参数的定义说明它们正是为此任务而设计的。我考虑过制作自定义完整性协议,但这似乎并不正确,因为已经内置了机制的自定义实现。 - Sasha Dudkin
关于receiveMessage()-似乎它正在检查接收到的数据块的isComplete标志,如果为false,则存储该块,直到我们收到isComplete == true的块,然后所有存储的块都被组合成单个消息。确实是一个非常有用的方法,但它并没有解决问题-每个块的isComplete都会变成false。 - Sasha Dudkin

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