简体   繁体   English

游戏中心GKMatch GKSendDataReliable数据包丢失

[英]Game Center GKMatch GKSendDataReliable packet lost

I have been using GKMatch for quite a while successfully in an app. 我在应用程序中成功使用GKMatch已经有一段时间了。 I have been chasing down and issue with the game occasionally stopping and have tracked it down to packets being sent but not received. 我一直在追逐游戏并偶尔停止游戏,并将其跟踪到正在发送但未收到的数据包。 This happens only occasionally but I can't seem to track down why it happens. 这只是偶尔发生,但我似乎无法追查它为什么会发生。

All messages are sent using GKSendDataReliable. 所有消息都使用GKSendDataReliable发送。

Logging has shown that the packet is being sent from one device successfully, but it is never received at the target device. 记录显示数据包正在从一台设备成功发送,但从未在目标设备上接收。

//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];
}

What I see happen is that periodically (maybe 1 in 100 messages) is sent without error from the 'sendDataToAllPlayers' method, but the receiving device never hits the 'didReceiveData' method. 我所看到的是周期性地(可能是100个消息中的1个)在没有错误的情况下从'sendDataToAllPlayers'方法发送,但是接收设备永远不会遇到'didReceiveData'方法。 My understanding is that using GKSendDataReliable should send messages and then won't send another until it receives an acknowledgement. 我的理解是,使用GKSendDataReliable应该发送消息,然后在收到确认之前不会发送另一个消息。 Messages aren't received but new messages are sent from the same device. 未收到消息,但从同一设备发送新消息。

The sending method returns 'YES' and error is nil, but the didReceiveData is never hit...! 发送方法返回'YES'并且错误是nil,但didReceiveData永远不会被命中......!

Has anyone ever seen this? 有没有人见过这个? Does anyone have any ideas what this could be? 有没有人有任何想法这可能是什么? I don't know what else I could do to debug this. 我不知道我还能做些什么来调试这个。

I confirm the bug. 我确认了这个错误。 I made an example project consistently reproducing the issue: https://github.com/rabovik/GKMatchPacketLostExample . 我做了一个示例项目,一直在重现这个问题: https//github.com/rabovik/GKMatchPacketLostExample I tested it on a weak internet connection (iPad 3 with Wi-Fi and iPhone 4S with EDGE; both on iOS 6.1.3), and some packets regularly get lost without any error from Game Center API. 我在一个弱的互联网连接上测试它(带有Wi-Fi的iPad 3和带有EDGE的iPhone 4S;两者都在iOS 6.1.3上),并且一些数据包经常丢失而没有任何来自Game Center API的错误。 Moreover sometimes device stops receiving any data, while another still sends and receives messages successfully. 此外,有时设备停止接收任何数据,而另一个仍然成功发送和接收消息。

So if we are sure the bug exists, the only possible workaround is to add an extra transport layer for truly reliable delivery. 因此,如果我们确定存在错误,唯一可行的解​​决方法是添加额外的传输层以实现真正可靠的传输。

I wrote a simple lib for this purpose: https://github.com/rabovik/RoUTP . 我为此编写了一个简单的lib: https//github.com/rabovik/RoUTP It saves all sent messages until acknowledgement for each received, resends lost and buffers received messages in case of broken sequence. 它保存所有已发送的消息,直到确认每个接收到的消息,重新发送丢失并缓冲接收到的消息,以防序列中断。 In my tests combination "RoUTP + GKMatchSendDataUnreliable" works even beter than "RoUTP + GKMatchSendDataReliable" (and of course better than pure GKMatchSendDataReliable which is not really reliable). 在我的测试组合中,“RoUTP + GKMatchSendDataUnreliable”甚至比“RoUTP + GKMatchSendDataReliable”更好(当然比纯粹的GKMatchSendDataReliable更好,这不是真正可靠的)。

[Edit: RoUTP no longer seems to work properly in iOS9] [编辑:在iOS9中,RoUTP似乎不再正常工作]

I did some testing yesterday at the edge of my wifi's range where packet loss was occuring. 我昨天在wifi的范围边做了一些测试,丢失了。 What happens is that when packets are lost using GKMatchSendDataReliable the player is abruptly disconnected from the GKMatch session. 当使用GKMatchSendDataReliable丢失数据包时,播放器突然与GKMatch会话断开连接。 match:player:didChangeState is called with GKPlayerStateDisconnected and the player's ID is removed from the playerIDs dictionary. match:player:使用GKPlayerStateDisconnected调用didChangeState,并从playerIDs字典中删除播放器的ID。 This happens with only slight packet loss. 这种情况只会发生轻微丢包。 I can still browse the internet from this connection for instance. 我仍然可以从这个连接浏览互联网。

Now, if I switch to sending packets unreliably, then match:player:didChangeState never fires and the match keeps going without a problem (except losing the occasional packet which might be important). 现在,如果我切换到不可靠的发送数据包,那么匹配:player:didChangeState永远不会触发并且匹配继续没有问题(除了丢失偶尔可能很重要的数据包)。 It will only disconnect if the packet loss becomes substantial. 只有在数据包丢失变得很大时才会断开连接。 Now this is where Yan's RoUTP library is handy, since we can keep track of and retry these important messages without having our players disconnected when they encounter slight packet loss. 现在这是Yan的RoUTP库很方便的地方,因为我们可以跟踪并重试这些重要的消息,而不会让玩家在遇到轻微丢包时断开连接。

Also, data sending using GKMatchSendDataReliable will only return YES if the message has been successfully queued for delivery. 此外,如果邮件已成功排队等待传送,则使用GKMatchSendDataReliable发送的数据将仅返回YES。 It does not tell you whether or not the message was successfully delivered. 它不会告诉您邮件是否已成功传递。 How could it? 怎么可能呢? It returns right away. 它马上回来了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM