Подтвердить что ты не робот

Повторное подключение к отключенным одноранговым серверам

Я использую инфраструктуру iOS 7 Multipeer в своем приложении, но у меня возникла проблема с отключением устройств. Если я открою приложение на двух устройствах: устройство A и устройство B, два устройства автоматически подключаются друг к другу. Однако через несколько секунд устройство А отсоединяется от устройства В. Вначале соединение выглядит следующим образом:

A ---> B
A <--- B

Через несколько секунд:

A ---> B
A      B

Устройство A поддерживает это соединение, но устройство B получает MCSessionStateNotConnected.

Это означает, что A может отправлять данные в B, но B не может ответить. Я попытался обойти это, проверив, подключено ли устройство, а если нет, повторное инициирование соединения с помощью:

[browser invitePeer:peerID toSession:_session withContext:Nil timeout:10];

Но callback didChangeState просто вызывается с помощью MCSessionStateNotConnected.

Странно, если я отправлю приложение A в фоновый режим, затем снова откройте его, B снова подключится к нему и соединение будет поддерживаться.

API-интерфейс Multipeer (и документация) выглядит немного редким, поэтому я предполагал, что он будет работать. В этой ситуации как я должен повторно подключить устройство?

4b9b3361

Ответ 1

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

В моем делегате браузера я проверяю хэш-значение обнаруженного peer displayName и отправляет только приглашение, если мой партнер имеет более высокое значение хэша:

Edit

Как указано @Masa, значение hash для NSString будет отличаться на 32 и 64-битных устройствах, поэтому безопаснее использовать метод compare: на displayName.

- (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:(NSDictionary *)info {

    NSLog(@"Browser found peer ID %@",peerID.displayName);       

    //displayName is created with [[NSUUID UUID] UUIDString]

    BOOL shouldInvite = ([_myPeerID.displayName compare:peerID.displayName]==NSOrderedDescending);

    if (shouldInvite)
        [browser invitePeer:peerID toSession:_session withContext:nil timeout:1.0];
    else
        NSLog(@"Not inviting");
}

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

Ответ 2

Для всех, кого это интересует, я создал MCSessionP2P, демонстрационное приложение, которое иллюстрирует специальные сетевые функции MCSession. Приложение обе рекламирует себя в локальной сети и программно соединяется с доступными одноранговыми узлами, устанавливая одноранговую сеть. Hat tip для @ChrisH для его метода сравнения значений хэша для приглашения сверстников.

Ответ 3

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

Тем не менее, я думаю, что лучший подход, чем одно приглашение для одноранговых сетей, предназначен для приглашения обоих сверстников, но только для одного партнера. Я использую этот метод сейчас, и он отлично работает, потому что оба одноранговых узла имеют возможность передавать богатую информацию другому через параметр context приглашения, а не полагаться на скудную информацию, доступную в методе делегирования foundPeer.

Поэтому я рекомендую такое решение:

- (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:(NSDictionary *)info
{
    [self invitePeer:peerID];
}

- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void (^)(BOOL accept, MCSession *session))invitationHandler
{
    NSDictionary *hugePackageOfInformation = [NSKeyedUnarchiver unarchiveObjectWithData:context];
    BOOL shouldAccept = ([hugePackageOfInformation.UUID.UUIDString compare:self.user.UUID.UUIDString] == NSOrderedDescending);

    invitationHandler(shouldAccept && ![self isPeerConnected:peerID], [self openSession]);
}

Ответ 4

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

Мы можем использовать какой-то хитрый способ решить эту проблему: Поместите в txt записи (информацию открытия) время [[NSDate date] timeIntervalSince1970], когда приложение запустилось. Кто начал сначала - отправьте приглашение другим.

Но я думаю, что это не правильный путь (если приложения запускаются в то же время, маловероятно...:)). Нам нужно выяснить причину.

Ответ 5

Это результат ошибки, о которой я сообщил Apple. Я объяснил, как исправить это в ответе на другой вопрос: Почему мой MCSession одноранговый доступ отключен случайно?

Я не задавал эти вопросы для слияния, потому что в то время как основная ошибка и решение одинаковы, два вопроса описывают разные проблемы.

Ответ 6

Сохранение хэша сверстника B. Используя таймер, проверьте состояние соединения непрерывно, если он не подключен, попытайтесь повторно подключиться с каждым заданным периодом времени.