GKSession对等体断开连接导致其他对等体出现断开连接

我的应用程序使用GKSessionModePeer的GKSession。 它必须处理任意连接和断开连接的对等,因为这是一个长时间运行的应用程序,用户应该能够后台回来。 这在大多数情况下工作正常。 但是有时,当一个对端断开连接时,其他设备会接收到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中使用简单的repro例子(使用arc):

 - (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 

我从苹果支持听说,这种断开行为正在发生,因为设备连接“通过”彼此。 例如,设备A通过设备B连接到设备C.如果设备B丢弃,则设备A将看到设备C断开并立即重新连接。 我没有听说过这个问题是否会被解决。

这可能为时已晚,但我认为如果将会话模式从GKSessionModePeer更改为服务器上的GKSessionModeServer,它将解决此问题。

基本上他们都与对方连接,技术上同样的服务器,但你得到适当的通知断线。