Отключение однорангового узла GKSession приводит к тому, что другие одноранговые узлы кажутся отключенными - PullRequest
3 голосов
/ 04 декабря 2011

Мое приложение использует GKSession с GKSessionModePeer. Он должен обрабатывать одноранговые соединения, произвольно подключаясь и отключаясь, потому что это приложение работает долго, и пользователи должны иметь возможность перейти в фоновый режим и вернуться позже. Это прекрасно работает большую часть времени. Но иногда, когда одноранговый разъединяется, другие устройства получают уведомление с didChangeState: GKPeerStateDisconnected не только для устройства, которое действительно отключено, но также и для других устройств, которые фактически все еще связаны.

Я могу воспроизвести это поведение с помощью кода ниже и 4 устройств (все на iOS 5). Когда все идет, как ожидалось, когда устройство A выходит из приложения, все другие устройства получают уведомление, и вывод журнала на этих устройствах:

Service: didChangeState: peer A disconnected (12345)

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

Service: didChangeState: peer A disconnected (...) // expected

Service: didChangeState: peer B disconnected (...) // never disconnected

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

dnssd_clientstub DNSServiceRefDeallocate called with NULL DNSServiceRef

и / или * * тысячу двадцать-один

dnssd_clientstub DNSServiceProcessResult called with DNSServiceRef with no ProcessReply function

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

Я пробовал разные способы обработки GKSession при переходе в фоновый режим (доступны только настройки = НЕТ и отсутствие отключения, вообще ничего не делал), ни один из которых не работал лучше.

Кто-нибудь еще сталкивался с этим поведением (и решил его)?

Простой случай воспроизведения в AppDelegate (с использованием дуги):

- (void)startGKSession 
{
    self.gkSession = [[GKSession alloc] initWithSessionID:nil displayName:nil sessionMode:GKSessionModePeer];
    gkSession.disconnectTimeout = 10;
    gkSession.delegate = self;
        gkSession.available = YES;
}

- (void)shutdownGKSession 
{
    gkSession.available = NO;
    [gkSession disconnectFromAllPeers];
    gkSession.delegate = nil;    
    gkSession = nil;
    [self.connectedDevices removeAllObjects];
}

- (void)connectToPeer:(NSString *)peerId 
{
    [gkSession connectToPeer:peerId withTimeout:10];
}

- (void)session:(GKSession *)session peer:(NSString *)peerId didChangeState:(GKPeerConnectionState)state 
{

        switch (state) {
                case GKPeerStateAvailable:
            NSLog(@"Service: didChangeState: peer %@ available, connecting (%@)", [session displayNameForPeer:peerId], peerId);
            [self performSelector:@selector(connectToPeer:) withObject:peerId afterDelay:.5];            
                        break;

                case GKPeerStateUnavailable:
                        NSLog(@"Service: didChangeState: peer %@ unavailable (%@)", [session displayNameForPeer:peerId], peerId);
                        break;

                case GKPeerStateConnected:
            NSLog(@"Service: didChangeState: peer %@ connected (%@)", [session displayNameForPeer:peerId], peerId);
                        break;

                case GKPeerStateDisconnected:
                        NSLog(@"Service: didChangeState: peer %@ disconnected (%@)", [session displayNameForPeer:peerId], peerId);
                        break;

                case GKPeerStateConnecting:
                        NSLog(@"Service: didChangeState: peer %@ connecting (%@)", [session displayNameForPeer:peerId], peerId);
                        break;
        }
}

- (void)session:(GKSession *)session didReceiveConnectionRequestFromPeer:(NSString *)peerID 
{
    [session acceptConnectionFromPeer:peerID error:nil];
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.connectedDevices = [[NSMutableArray alloc] init];
    [self startGKSession];

    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];
    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];
    return YES;
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{    
    [self shutdownGKSession];
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    [self startGKSession];
}

@end

Ответы [ 2 ]

1 голос
/ 06 марта 2012

Я слышал от поддержки Apple, что такое поведение отключения происходит из-за того, что устройства подключаются друг к другу.Например, устройство A подключается к устройству C через устройство B. Если устройство B падает, устройство A увидит, что устройство C отключено и сразу же снова подключено.Я не слышал, если / когда это будет исправлено.

0 голосов
/ 20 марта 2013

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

По сути, все равноправные узлы подключаются друг к другу, но один сервер технически работает одинаково, но вы получаете соответствующие уведомления об отключениях.

...