Game Center GKMatch GKSendData Надежный пакет потерян

Я уже довольно давно успешно использую 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', и ошибка равна nil, но didReceiveData никогда не удаляется...!

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

2 ответа

Решение

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

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

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

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

Вчера я провел некоторое тестирование на границе моего Wi-Fi, где происходила потеря пакетов. Что происходит, когда пакеты теряются с помощью GKMatchSendDataReliable, проигрыватель внезапно отключается от сеанса GKMatch. match:player:didChangeState вызывается с помощью GKPlayerStateDisconnected, а идентификатор игрока удаляется из словаря playerIDs. Это происходит с небольшой потерей пакета. Я все еще могу просматривать Интернет из этого соединения, например.

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

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

Другие вопросы по тегам