Search code examples
objective-ciosgksession

How to: Implement server forcing disconnect of client in GKSession


I am implementing the GKSession server/client mode operation in my application on iOS. I found one question related to mine but with no answer. I am trying to allow the server to disconnect any client that is currently connected to the session. I thought that calling disconnectPeerFromAllPeers:(NSString *)peerID would allow me to do this, but is seems to have no effect.

Any suggestions?

Thanks


Solution

  • Actually answered via question update ion 01/03/2012, but moved this text to the answer section

    I wanted to share how I implemented a disconnect request sent from server to client. All of the code presented below is contained within a class I created to completely encapsulate all the interfacing with a GKSession instance (also implements the GKSessionDelegate methods).

    First I have the server send a disconnect request to the client that shall be disconneted. Any data that is sent from client to server or vice versa is contained within a dictionary that also has a key-value pair to specify the type of data that is sent (in this case the data is a disconnect request).

    - (void)sendDisconnectRequestToPeer:(NSString *)peer {
    
    //create the data dictionary that includes the disconnect value for the data type key
    NSMutableDictionary *dictPrvw = [[NSMutableDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithInt:GKSessionDataTypeDisconnect], kDictKeyDataType, nil];
    
    NSData *dataChunk = [[NSKeyedArchiver archivedDataWithRootObject:dictPrvw] retain];
    //[self printDict:dictPrvw];
    
    NSArray *peers = [[NSArray alloc] initWithObjects:peer, nil];
    
    [self sendData:dataChunk toPeers:peers];
    
    [dataChunk release];
    [dictPrvw release];
    
    }
    

    The client receives the data, casts it into a dictionary and examines the key-value pair that specifies what type of data was sent. If it's a disconnect request, my "GKSessionManager" class then implements a disconnect.

    - (void)recievedAllDataChunksInSession:(GKSession *)session fromPeer:(NSString *)peer context:(void *)context {
    
    //The chunk was packaged by the other user using an NSKeyedArchiver, 
    //so unpackage it here with our NSKeyedUnArchiver
    NSMutableDictionary *responseDictionary = (NSMutableDictionary *)[[NSKeyedUnarchiver unarchiveObjectWithData:self.recievedPackets] mutableCopyWithZone:NULL];
    
    //[self printDict:responseDictionary];
    
    //get the enumerator value for the data type
    NSNumber *gkSessDataType = [responseDictionary objectForKey:kDictKeyDataType];
    int intDataType = [gkSessDataType intValue];
    
    UIAlertView *anAlrtVw;
    
    switch (intDataType) {
        case GKSessionDataTypeMessageData:
            [self sessionManager:self recievedDataDictionary:responseDictionary];
            break;
    
        case GKSessionDataTypePreviewRequest:
            if (sess.sessionMode == GKSessionModeServer) {
                [self sendMsgPreviewToPeer:peer];
            }
            break;
    
        case GKSessionDataTypePreviewSend:
            //[self sessionManager:self recievedDataDictionary:responseDictionary];
            [self sessionManager:self connectedWithPrelimData:responseDictionary];
            break;
    
        case GKSessionDataTypeDisconnect:
            anAlrtVw = [[UIAlertView alloc] 
                        initWithTitle:nil 
                        message:@"The server has disconnect you." 
                        delegate:self cancelButtonTitle:@"OK" 
                        otherButtonTitles:nil];
            [anAlrtVw show];
            [anAlrtVw release];
            [self closeSession];
            [self disconnectedByServer];
    
        default:
            break;
    
    }
    }
    
    
    - (void)closeSession {
      [sess disconnectFromAllPeers];
      [sess setDataReceiveHandler: nil withContext: NULL];
      sess.available = NO; 
      sess.delegate = nil;
      self.sess = nil;
      self.serverId = nil;
      self.rqstPeerId = nil;
      serverIsConnecting = NO;
    }
    

    The user never sees the disconnect request and so has no control over whether or not to deny it.

    Hope this information helps. I realize what I wrote my not be entirely clear and I have left a lot of other code out (on purpose) so feel free to comment or ask questions.