Пакет Game Center 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 должно отправлять сообщения, а затем не отправлять другие, пока не получит подтверждение. Сообщения не принимаются, но новые сообщения отправляются с того же устройства.

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

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


person Jonathan Hebert    schedule 07.06.2013    source источник
comment
Мои пользователи также жалуются, что некоторые данные могут быть случайно потеряны во время игры. Но я до сих пор не могу воспроизвести этот баг самостоятельно. У вас есть пример проекта, в котором эта ошибка постоянно воспроизводима? Если да, не могли бы вы поделиться им (может быть на github)? Спасибо.   -  person Yan    schedule 10.06.2013
comment
Мой проект очень большой (в настоящее время активное приложение в магазине), но я попытаюсь собрать его меньшую версию, чтобы убедиться, что он последовательно воспроизводим.   -  person Jonathan Hebert    schedule 10.06.2013
comment
У меня та же проблема, особенно когда подключение к Интернету на одном из устройств слабое. Правда ли, что GKSendDataReliable прекращает отправку сообщений, пока не получит подтверждение?   -  person jyek    schedule 13.06.2013
comment
Вы подали отчет об ошибке для этого? Это похоже на фундаментально сломанную функциональность, которая должна повлиять на всех разработчиков, использующих матчи в реальном времени.   -  person Shaun Budhram    schedule 15.01.2014
comment
Я это тоже подтвердил. Действительно очень удивительно от Apple (не говоря уже о разочаровании). Весь смысл надежного режима заключается в том, что соединение должно буферизоваться и задерживаться, пока оно не сможет отправлять, а не просто отбрасывать сообщения.   -  person theLastNightTrain    schedule 19.08.2014
comment
Если есть отчет об ошибке, я бы хотел его продублировать, у вас есть номер? Я нахожу эту ошибку возмутительной на самом деле. Создание транспортного уровня в приложении поверх Game Kit, который уже находится поверх надежного транспортного уровня, откровенно смущает их. Кого-то где-то надо несколько раз ударить по лицу.   -  person theLastNightTrain    schedule 19.08.2014
comment
У меня эта проблема с первого дня игры в Game Center. Написал несколько ошибок в Apple об этом, но спустя 4 года ничего не было сделано для их устранения.   -  person BGreenstone    schedule 10.11.2014


Ответы (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, который не очень надежен).

person Yan    schedule 06.07.2013
comment
RoUTP, похоже, теперь не работает с iOS 9. Если я отправлю данные с его помощью, не все устройства получат данные. Неважно, пользуюсь я надежным или ненадежным транспортом. Если я отключу RoUTP, все будет работать нормально. - person Robert Wasmann; 07.04.2016

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

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

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

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

person Robert Wasmann    schedule 10.11.2014
comment
Эй, я работал над довольно сложной игрой в реальном времени и заметил именно ту проблему, которую вы описываете. Вы рекомендуете мне попробовать библиотеку RoUTP? - person Epic Byte; 26.12.2014
comment
Это определенно работает, но это очень просто. Например, все пакеты должны быть отправлены через RoUTP, как только вы начнете его использовать. И он будет пытаться доставить пакеты вечно. Это может привести к одновременному прохождению пакета задержанных пакетов. Я могу подумать о переходе на полноценный клиентский сервер вместо одноранговой сети и отказе от RoUTP. Если клиенты теряют пакеты и отключаются, то это может быть просто желаемым последствием, чтобы поддерживать нормальную игру для других клиентов, вместо того, чтобы игрок появлялся на сцене, убивая других игроков, прежде чем кто-либо сможет отреагировать из-за всплеск пакетов. - person Robert Wasmann; 28.12.2014
comment
Он также не говорит, кто отправляет какой пакет, поскольку эта информация отбрасывается. Таким образом, вам нужно закодировать playerID в сообщении, используя массив символов. Все игроки получают все сообщения, поэтому если вы переходите на клиент-сервер, то это не идеально. То есть вы не можете отправлять сообщения конкретным игрокам. Только всем игрокам, а затем игроки игнорируют сообщения, не предназначенные для них. - person Robert Wasmann; 28.12.2014
comment
Эй, спасибо за ответ. Итак, изначально я отправлял надежные пакеты, но из-за того, как Game Center обрабатывает разъединения с надежными пакетами, мне нужно было попробовать что-то еще, потому что даже самый маленький тайм-аут отключил пользователя. Итак, в итоге я написал свой собственный слой поверх ненадежного сообщения отправки и сам управлял надежной очередью. Это позволяет мне отдавать предпочтение определенным сообщениям по сравнению с другими и вручную отбрасывать пакеты, если они больше не нужны (т. е. если это заняло слишком много времени). До сих пор я добился успеха с этим подходом. И никаких отключений не происходит. - person Epic Byte; 28.12.2014
comment
В течение многих лет я страдал как от потери надежных пакетов, так и от спонтанных отключений -didChangeState. Я никогда не думал, что надежная потеря пакетов приведет к отключению, поэтому я провел быстрый тест, изменив все свои данные на ненадежные. Без изменений. Я все еще получаю отключение -didChangeState в игре с 3 или 4 игроками. Однако в играх для двух игроков этого не происходит. - person BGreenstone; 21.04.2015