【问题标题】:Game Center GKMatch GKSendDataReliable packet lostGame Center GKMatch GKSendDataReliable 数据包丢失
【发布时间】:2013-06-03 23:36:36
【问题描述】:

我在应用程序中成功使用 GKMatch 已经有一段时间了。我一直在追查游戏偶尔会停止的问题,并将其追踪到正在发送但未收到的数据包。这只是偶尔发生,但我似乎无法追查为什么会发生。

所有消息都使用 GKSendDataReliable 发送。

记录显示数据包从一台设备成功发送,但目标设备从未收到。

//Code sample of sending method....
//self.model.match is a GKMatch instance    
-(BOOL) sendDataToAllPlayers:(NSData *)data error:(NSError **)error {
        [self.model.debugger addToLog:@"GKManager - sending data"];
        return [self.model.match sendDataToAllPlayers:data withDataMode:GKSendDataReliable error:error];
    }

...

//Code sample of receiving method....
// The match received data sent from the player.
-(void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID {
    [self.model.debugger addToLog:@"GKManager - received data"];
    [super didReceiveData:data fromPlayer:playerID];
}

我看到的情况是,“sendDataToAllPlayers”方法会定期(可能 100 条消息中的 1 条)发送而没有错误,但接收设备从未点击“didReceiveData”方法。我的理解是,使用 GKSendDataReliable 应该发送消息,然后在收到确认之前不会发送另一个消息。未收到消息,但从同一设备发送新消息。

发送方法返回 'YES' 并且错误为 nil,但 didReceiveData 从未命中...!

有人见过吗?有谁知道这可能是什么?我不知道我还能做些什么来调试它。

【问题讨论】:

  • 我的用户也抱怨在游戏过程中可能会不小心丢失一些数据。但我仍然无法自己重现此错误。您是否有一个示例项目,该错误始终可以重现?如果是的话,你能分享一下吗(可能在github上)?谢谢。
  • 我的项目非常大(当前商店中的应用程序处于活动状态),但我会尝试将它的一个较小版本放在一起,看看它是否能够始终如一地重现。
  • 我遇到了同样的问题,尤其是当其中一台设备的互联网连接较弱时。 GKSendDataReliable 是否真的会在收到确认之前停止发送消息?
  • 您是否为此提交了错误报告?这似乎从根本上破坏了功能,应该会影响任何使用实时匹配的开发人员。
  • 我也证实了这一点。 Apple 真的非常令人惊讶(更不用说令人失望了)。可靠模式的重点是连接应该缓冲和延迟,直到它可以发送,而不仅仅是丢弃消息。

标签: ios game-center multiplayer gksession


【解决方案1】:

我确认错误。 我制作了一个示例项目,始终如一地重现该问题:https://github.com/rabovik/GKMatchPacketLostExample。我在互联网连接较弱的情况下测试了它(iPad 3 和 Wi-Fi,iPhone 4S 和 EDGE;两者都在 iOS 6.1.3 上),一些数据包经常丢失,游戏中心 API 没有任何错误。此外,有时设备停止接收任何数据,而另一个仍然成功发送和接收消息。

因此,如果我们确定存在错误,唯一可能的解决方法是添加额外的传输层以实现真正可靠的交付。

为此我编写了一个简单的库:https://github.com/rabovik/RoUTP。它保存所有发送的消息,直到每个接收到的确认,重新发送丢失的消息并在序列中断的情况下缓冲接收到的消息。 在我的测试中,“RoUTP + GKMatchSendDataUnreliable”组合比“RoUTP + GKMatchSendDataReliable”效果更好(当然也比不可靠的纯 GKMatchSendDataReliable 更好)。

【讨论】:

  • RoUTP 现在似乎被 iOS 9 破坏了。如果我使用它发送数据,并非所有设备都会收到数据。我是否使用可靠或不可靠的运输方式都没关系。如果我禁用 RoUTP,一切正常。
【解决方案2】:

[编辑:RoUTP 在 iOS9 中似乎不再正常工作]

我昨天在发生丢包的 wifi 范围边缘进行了一些测试。发生的情况是,当使用 GKMatchSendDataReliable 丢失数据包时,播放器会突然与 GKMatch 会话断开连接。 match:player:didChangeState 使用 GKPlayerStateDisconnected 调用,并且玩家的 ID 从 playerIDs 字典中删除。发生这种情况时只有轻微的数据包丢失。例如,我仍然可以通过此连接浏览互联网。

现在,如果我切换到不可靠地发送数据包,那么 match:player:didChangeState 永远不会触发,并且匹配会继续没有问题(除了丢失可能很重要的偶尔数据包)。只有当数据包丢失变得很大时,它才会断开连接。现在这就是 Yan 的 RoUTP 库派上用场的地方,因为我们可以跟踪并重试这些重要消息,而不会在玩家遇到轻微丢包时断开连接。

此外,使用 GKMatchSendDataReliable 发送数据只会在消息已成功排队等待传递时返回 YES。它不会告诉您消息是否已成功传递。怎么可能?它立即返回。

【讨论】:

  • 嘿,我一直在开发一个非常复杂的 rts 游戏,我已经注意到你所描述的问题。你推荐我试试 RoUTP 库吗?
  • 它确实有效,但它非常基础。例如,一旦您开始使用它,所有数据包都必须通过 RoUTP 发送。它会一直尝试永远发送数据包。这可能会导致一连串延迟的数据包同时通过。我可能会考虑使用完整的客户端服务器而不是点对点并放弃 RoUTP。如果客户端丢失数据包并断开连接,那么这可能只是保持其他客户端正常游戏的理想结果,而不是让玩家在场景中突然出现,因为数据包涌入而在任何人做出反应之前杀死其他玩家。跨度>
  • 它也没有说明谁发送了什么数据包,因为该信息被丢弃。因此,您必须使用 char 数组将 playerID 编码到消息中。所有玩家都会收到所有消息,因此如果您使用客户端服务器,那并不理想。也就是说,您不能向特定玩家发送消息。只发给所有玩家,然后让玩家忽略不适合他们的消息。
  • 您好,感谢您的回复。所以我最初发送的数据包是可靠的,但由于 Game Center 处理与可靠数据包断开连接的方式,我需要尝试其他方法,因为即使是最小的超时也会断开用户连接。所以我最终做的是在不可靠的发送消息上编写自己的层并自己管理可靠队列。这使我可以将某些消息优先于其他消息,并在不再需要它们时手动丢弃数据包(即如果花费了太长时间)。到目前为止,我已经通过这种方法取得了成功。并且没有发生断开连接。
  • 多年来,我一直在经历“可靠”数据包的丢失和自发的-didChangeState 断开连接。我从没想过可靠的数据包丢失会触发断开连接,因此我通过将所有数据更改为不可靠进行了快速测试。不用找了。在 3 或 4 人游戏中,我仍然会出现 -didChangeState 断开连接。但是,在 2 人游戏中似乎不会发生。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多