5

我正在尝试编写一个应用程序,通过 Game Kit 框架与运行该应用程序的其他 iPhone 交换数据。iPhone相互发现并连接良好,但是当我发送数据时会出现问题。我知道 iPhone 连接正确,因为当我序列化一个 NSString 并通过连接发送它时,它在另一端很好。但是当我尝试归档一个更大的对象(使用 NSKeyedArchiver)时,我收到错误消息“AGPSessionBroadcast failed (801c0001)”。

我假设这是因为我发送的数据太大(我的文件大小约为 500k,Apple 似乎建议最大为 95k)。我曾尝试将数据拆分为多个传输,但我永远无法在另一端正确地取消归档。我想知道是否有其他人遇到过这个问题,以及您是如何解决的。

4

2 回答 2

5

我在 300K 左右的文件中遇到了同样的问题。问题是发送方需要知道接收方在发送下一个块之前何时清空了管道。

我最终得到了一个在两边都运行的简单状态引擎。发送方发送一个标头,其中包含将发送的总字节数和数据包大小,然后等待对方的确认。一旦它得到握手,​​它就会继续发送固定大小的数据包,每个数据包都带有一个序列号。

接收者获取每一个,读取它并将其附加到缓冲区,然后将它收到的具有序列#的数据包写回管道。发送方读取数据包#,切出另一个缓冲区的值,依此类推。每一方都跟踪它们所处的状态(空闲、发送标头、接收标头、发送数据、接收数据、错误、完成等)。双方必须跟踪何时读取/写入最后一个片段,因为它是可能小于完整缓冲区大小。

这工作正常(虽然有点慢),它可以扩展到任何大小。我从 5K 数据包大小开始,但运行速度很慢。将它推到 10K,但它开始引起问题,所以我退后并保持在 8096。它适用于二进制和文本数据。

于 2009-08-22T06:24:15.493 回答
3

请记住,GameKit 不是通用的文件传输 API。它更多地用于更新玩家的位置、当前位置或其他对象等。因此,为游戏发送 300k 似乎并不明智,尽管我可以理解劫持 API 用于一般共享机制。

问题是它不是 TCP 连接。它更像是一个UDP(数据报)连接。在这些情况下,数据不是流(由 TCP 打包),而是一大块数据。(从技术上讲,UDP 可以被分割成多个 IP 数据包——但如果丢失其中一个,整个 UDP 都会丢失,而 TCP 会重新尝试)。

大多数有线网络的 MTU 约为 1.5k;对于蓝牙,大约为 0.5k。因此,您发送的任何 UDP 数据包 (a) 可能会丢失,(b) 可能会拆分为多个 MTU 大小的 IP 数据包,以及 (c) 如果其中一个数据包丢失,那么您将自动丢失整个数据包。

您最好的策略是模拟 TCP - 它发送带有序列号的数据包。然后,接收端可以请求对后来丢失的数据包进行重复传输。如果您使用的是 NSKeyedArchiver 的等价物,那么一个建议是遍历键并将它们写为单独的键(假设每个键值本身并不那么大)。您需要为每个发回的数据包提供某种 ACK,并在完成后提供总 ACK,以便发送者知道可以从内存中删除数据。

于 2009-08-22T07:02:11.410 回答