Игровой центр GKMatch GKSendDataReliable потерянный пакет

Я давно использую 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];
}

Я вижу, что периодически (возможно, 1 из 100 сообщений) отправляется без ошибок из метода sendDataToAllPlayers, но принимающее устройство никогда не обращается к методу 'didReceiveData'. Я понимаю, что использование GKSendDataReliable должно отправлять сообщения, а затем не будет отправлять другой, пока не получит подтверждение. Сообщения не принимаются, но новые сообщения отправляются с одного и того же устройства.

Метод отправки возвращает "YES", а ошибка равна нулю, но didReceiveData никогда не попадает...!

Кто-нибудь когда-нибудь видел это? Есть ли у кого-нибудь идеи, что это может быть? Я не знаю, что еще я мог сделать, чтобы отладить это.

Ответ 1

Я подтверждаю ошибку. Я сделал примерный проект, последовательно воспроизводящий проблему: https://github.com/rabovik/GKMatchPacketLostExample. Я тестировал его на слабом интернет-соединении (iPad 3 с Wi-Fi и iPhone 4S с EDGE, как на iOS 6.1.3), так и некоторые пакеты регулярно теряются без ошибок в Game Center API. Более того, иногда устройство перестает получать какие-либо данные, в то время как другой по-прежнему отправляет и принимает сообщения успешно.

Итак, если мы уверены, что ошибка существует, единственным возможным обходным путем является добавление дополнительного транспортного уровня для действительно надежной доставки.

Я написал для этого простой lib: https://github.com/rabovik/RoUTP. Он сохраняет все отправленные сообщения до тех пор, пока не будет получено подтверждение для каждого полученного, отправленного сообщения об утере и буферов полученных сообщений в случае нарушения последовательности. В моих тестах комбинация "RoUTP + GKMatchSendDataUnreliable" работает даже быстрее, чем "RoUTP + GKMatchSendDataReliable" (и, конечно, лучше, чем чистый GKMatchSendDataReliable, который не очень надежный).

Ответ 2

[Edit: RoUTP больше не работает должным образом в iOS9]

Вчера я провел некоторое тестирование на краю диапазона wifi, где происходила потеря пакетов. Случается, что когда пакеты теряются с помощью GKMatchSendDataReliable, игрок внезапно отключается от сеанса GKMatch. match: player: didChangeState вызывается с GKPlayerStateDisconnected, а идентификатор игрока удаляется из словаря playerID. Это происходит с небольшой потерей пакетов. Например, я могу просматривать интернет из этого соединения.

Теперь, если я переключаюсь на отправку пакетов неудовлетворительно, то матч: player: didChangeState никогда не срабатывает, и совпадение продолжается без проблем (за исключением потери случайного пакета, который может быть важен). Он будет отключен, только если потеря пакетов станет существенной. Теперь здесь удобна библиотека Yan RoUTP, поскольку мы можем отслеживать и повторять эти важные сообщения, не отключая наших игроков, когда они сталкиваются с небольшой потерей пакетов.

Кроме того, отправка данных с использованием GKMatchSendDataReliable вернет только YES, если сообщение было успешно поставлено в очередь для доставки. Он не сообщает вам, было ли сообщение успешно доставлено. Как это могло быть? Он сразу возвращается.