【问题标题】:Swift Network framework with TCP带有 TCP 的 Swift 网络框架
【发布时间】:2021-03-13 20:36:28
【问题描述】:

我正在使用 Swift Network 框架制作一个简单的测试应用程序。一台服务器,一台客户端(都是iOS模拟器),并成功建立了它们之间的tcp连接。我正在尝试发送一系列短消息。

服务器正在发送由 1 到 999 的自然数组成的字符串。每个数字作为单独的数据发送,isCompletecontentContext 默认值为 true em> 和 .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 等于 false 并且 contentContext 属性 isFinal 等于 true,而 .defaultMessage.isFinal 应该等于 false

现在,我被困住了。我只是使用了错误的参数(我尝试了各种组合,但似乎没有一个对我有用)? NWConnection 在发送消息时是否会发生可怕的变化?

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

【问题讨论】:

  • 第一段代码看起来很奇怪。您有一个名为“数据”的人作为内容。然后在几行之后创建一个名为“data”的新变量。
  • @ElTomato 只是一个局部变量。在函数范围内,它会覆盖具有相同名称的外部变量(如函数参数)。但为了清楚起见,我会重命名它。

标签: ios swift tcp network-programming


【解决方案1】:

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

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

您可以定义自己的简单协议,以便在客户端进行解码。例如,您可以用&lt;Message&gt;your-message&lt;/Message&gt; 包装每条消息,并使用它在客户端识别不同的消息(在此过程中您将面临一些如此简单的缺点)

在开发自定义协议时需要考虑很多事情。如果您是认真的,最好阅读有关此主题的内容。

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

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

... 能够读取完整数据。讨论部分将就传输类型的影响和所需的框架逻辑提供一些有价值的见解。

【讨论】:

  • 因此您认为在没有附加协议的情况下,无法在 TCP 级别使用 NWConnection 发送完整的 Data 对象。而且我们只能发送原始字节流而不知道消息在哪里结束。好的。但是那么isComplete标志是什么意思呢?为什么不将所有接收到的字节组合起来,实际上大多数消息都是作为预期的完整对象接收的?
  • 按照我所说的阅读讨论部分 (developer.apple.com/documentation/network/nwconnection/…)。有一种方法可以使用上述函数而不是您使用的函数(读取一系列字节)来接收完整的消息。讨论部分很好地详细说明了这些影响。
  • @jms 是的,我正在尝试直接使用传输级别。不太确定那些 http 标头及其用途 - 它可能是完整性控制或其他东西。但是 Apple 文档(据我了解)坚持认为我应该能够使用 Network 控制完成消息。 'isComplete' 和 'isFinal' 参数的定义表明它们是专门为这个任务而制作的。我考虑过制作自定义完整性协议的可能性,但似乎不对已经内置的机制进行自定义实现。
  • @jms 至于receiveMessage() - 似乎它正在检查接收到的数据块的isComplete标志,如果它是false,则存储块,直到我们收到一个isComplete == true的块,并且然后将所有存储的块组合成一条消息。非常有用的方法,但它并不能解决问题 - isComplete 在每个块上都变为 false。
猜你喜欢
  • 1970-01-01
  • 2014-09-30
  • 2016-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多