Le cadre de connectivité multigeer - la perte de la session des pairs
je me demande si ce cadre de connectivité Multipeer est prêt à être utilisé dans le monde réel, étant donné tous les bugs qui ont été rencontrés par la communauté. Je pense que je le fais correctement, mais tous les autres projets que j'ai essayé rencontrent des problèmes similaires.
le problème que j'ai peut être lié à une question inhérente à Bonjour ou quelque chose, Je ne peux pas le comprendre, mais fondamentalement le problème est le suivant:
- j'ai un actif
MCSession
avec un certain nombre de pairs. - Maintenant, si un appareil est dans une session, puis force quitte, que" Peer " reste connecté pour une durée indéterminée.
- Il n'y a rien que je peux faire pour forcer l'utilisateur, même si l'
browser:lostPeer:
la méthode est appelée pour ce Pair et n'est même plus apparaître dans le navigateur comme "Proche." session:peer:didChangeState:
la méthode n'est pas nécessaire pour ce Pair.- quand ce Pair que la force quittée revient à l'application, ils sont "trouvés" à nouveau par le
browser:foundPeer:withDiscoveryInfo:
mais encore, existent aussi dans lesession.connectedPeers
NSArray. De toute évidence, ils ne reçoivent aucune donnée ou mise à jour sur la session et ne sont pas connectés. - La seule chose qui semble fonctionner pour vous inscrire original peer,
MCSessionStateNotConnected
à la session est en reconnectant ce pair à la session originale. Ensuite, il y a un double appel àsession:peer:didChangeState:
où la nouvelle instance du peerID estMCSessionStateConnected
et peu de temps après l'ancienne instance des appels peerIDMCSessionStateNotConnected
.
l'exemple d'application chat illustre bien ce problème: https://developer.apple.com/library/ios/samplecode/MultipeerGroupChat/Introduction/Intro.html
comme il ne semble pas y avoir de moyen de forcer manuellement un pair à quitter la session, Que dois-je faire? Dois-je essayer de reconstruire la session?
ce cadre semble un peu en désordre, mais j'essaie de réserver mon jugement!
5 réponses
ma seule solution à ce type de problème a été d'avoir une relation 1-1 entre les séances et les pairs. Cela complique l'envoi d'émissions, mais permet au moins des déconnexions de niveau Pair et le nettoyage par déconnexion/suppression de la session elle-même.
mise à Jour
pour développer ma réponse originale, afin de pouvoir envoyer des données à des pairs connectés, il est nécessaire de maintenir une référence à la session qui a été créée pour chaque pair. J'ai utilisé un dictionnaire mutable pour ça.
une fois l'invitation envoyée/acceptée avec une nouvelle session, utilisez le MCSession
délégué méthode pour mettre à jour le dictionnaire:
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state {
if (state==MCSessionStateConnected){
_myPeerSessions[peerID.displayName] = session;
}
else if (state==MCSessionStateNotConnected){
//This is where the session can be disconnected without
//affecting other peers
[session disconnect];
[_myPeerSessions removeObjectForKey:peerID.displayName];
}
}
tous les pairs peuvent être consultés avec une méthode qui renvoie toutes les valeurs du dictionnaire, et à leur tour tous connectedPeers
(dans ce cas) pour chaque MCSession
:
- (NSArray *)allConnectedPeers {
return [[_myPeerSessions allValues] valueForKey:@"connectedPeers"];
}
envoyer des données à un pair particulier ou par diffusion peut être fait avec une méthode comme celle-ci:
- (void)sendData:(NSData *)data toPeerIDs:(NSArray *)remotePeers reliable:(BOOL)reliable error:(NSError *__autoreleasing *)error {
MCSessionSendDataMode mode = (reliable) ? MCSessionSendDataReliable : MCSessionSendDataUnreliable;
for (MCPeerID *peer in remotePeers){
NSError __autoreleasing *currentError = nil;
MCSession *session = _myPeerSessions[peer.displayName];
[session sendData:data toPeers:session.connectedPeers withMode:mode error:currentError];
if (currentError && !error)
*error = *currentError;
}
}
Avez-vous essayé de déconnecter la session avant la fermeture de l'application? Cela devrait enlever le Pair de la session correctement et nettoyer toutes les ressources allouées pour le Pair.
spécifiquement je veux dire quelque chose comme [self.peer disconnect]
applicationWillTerminate:
j'ai eu des problèmes similaires. Il semble cependant que si j'ai lancé mon application sur un périphérique iOS, et que je me suis connecté à un autre, puis que j'ai arrêté et que j'ai relancé (par exemple, quand j'ai relancé depuis Xcode), alors je me trouve dans une situation où j'obtiens un message Connecté et un message non connecté un peu plus tard. C'était en me jetant à off. Mais en regardant plus attentivement, je peux voir que le message non connecté est en fait destiné à un peerId différent que celui qui a connecté.
je pense que le le problème ici est que la plupart des échantillons que j'ai vu se soucient juste du displayName du peerID, et négligent le fait que vous pouvez obtenir plusieurs peerIDs pour le même périphérique/displayName.
je vérifie maintenant le displayName d'abord et puis je vérifie que le peerID est le même, en faisant une comparaison des pointeurs.
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state {
MyPlayer *player = _players[peerID.displayName];
if ((state == MCSessionStateNotConnected) &&
(peerID != player.peerID)) {
NSLog(@"remnant connection drop");
return; // note that I don't care if player is nil, since I don't want to
// add a dictionary object for a Not Connecting peer.
}
if (player == nil) {
player = [MyPlayer init];
player.peerID = peerID;
_players[peerID.displayName] = player;
}
player.state = state;
...
Je ne pouvais pas obtenir la réponse acceptée pour jamais travailler, donc ce que j'ai fait à la place est d'avoir un minuteur qui se déclencherait pour réinitialiser la connexion quand le navigateur signalerait non connecté et il n'y avait pas d'autres pairs connectés.
-(void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state{
//DebugLog(@"session didChangeState: %ld",state);
if(resetTimer != nil){
[resetTimer invalidate];
resetTimer = nil;
}
if(state == MCSessionStateNotConnected){
[session disconnect];
[peerSessions removeObjectForKey:peerID.displayName];
[self removeGuidyPeerWithPeerID:peerID];
//DebugLog(@"removing all guides from peer %@",peerID);
if([localSession connectedPeers].count == 0){
DebugLog(@"nothing found... maybe restart in 3 seconds");
dispatch_async(dispatch_get_main_queue(), ^{
resetTimer = [NSTimer
scheduledTimerWithTimeInterval:3.0
target:self selector:@selector(onResetTimer:)
userInfo:nil
repeats:NO];
}
);
}
}
...
}
Vous pouvez supprimer le Pair du contrôleur MCBrowserViewController avec le code suivant dans Swift 3:
self.mySession.cancelConnectPeer(self.myPeerID)