多对等连接框架 - 丢失的对等保持在会话中
-
21-12-2019 - |
题
考虑到社区遇到的所有错误,我想知道这个多点连接框架是否已准备好在现实世界中使用。我认为我的设置是正确的,但是我尝试过的所有其他示例项目都遇到了类似的问题。
我遇到的问题可能与 Bonjour 固有的问题或其他问题有关,我无法弄清楚,但基本上问题如下:
- 我有一个活跃的
MCSession
与许多同行。 - 现在,如果设备处于会话中,然后 强制退出, ,“对等点”无限期地保持连接。
- 我无法强制该用户退出,即使
browser:lostPeer:
方法被称为该同行,甚至不再以“附近”的形式出现在浏览器中。 - 这
session:peer:didChangeState:
没有为该对等点调用方法。 - 当强制退出的对等点返回应用程序时,他们会再次被“找到”
browser:foundPeer:withDiscoveryInfo:
但仍然还存在于session.connectedPeers
NSArray。显然,他们仍然没有收到有关会话的任何数据或更新,并且实际上并未连接。 - 似乎唯一可以将原始对等点注册为
MCSessionStateNotConnected
会话的方法是将该对等点重新连接到原始会话。然后有一个重复的调用session:peer:didChangeState:
其中peerID 的新实例是MCSessionStateConnected
在旧的 PeerID 实例调用后不久MCSessionStateNotConnected
.
示例聊天应用程序很好地演示了这个问题: https://developer.apple.com/library/ios/samplecode/MultipeerGroupChat/Introduction/Intro.html
由于似乎没有任何方法可以手动强制从会话中删除对等方,我该怎么办?我应该尝试以某种方式重建会话吗?
这个框架看起来有点乱,但我试图保留判断力!
解决方案
我解决此类问题的唯一方法是在会话和对等点之间建立 1-1 关系。它使广播的发送变得复杂,但至少允许通过断开/删除会话本身来进行对等级断开连接和清理。
更新
为了详细说明我原来的答案,为了能够向连接的对等点发送数据,有必要维护对为每个对等点创建的会话的引用。我为此一直使用可变字典。
通过新会话发送/接受邀请后,请使用 MCSession
更新字典的委托方法:
- (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];
}
}
可以使用返回字典所有值的方法来访问所有对等点,然后依次返回所有对等点 connectedPeers
(在本例中为一个)对于每个 MCSession
:
- (NSArray *)allConnectedPeers {
return [[_myPeerSessions allValues] valueForKey:@"connectedPeers"];
}
可以使用如下方法将数据发送到特定对等点或通过广播来完成:
- (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;
}
}
其他提示
您是否尝试过在应用程序关闭之前断开会话?这应该正确地将对等点从会话中删除,并清除分配给对等点的所有资源。
具体来说我的意思是 [self.peer disconnect]
在 applicationWillTerminate:
我也遇到过类似的问题。看起来,如果我在一台 iOS 设备上运行我的应用程序,并连接到另一台设备,然后退出并重新启动(比如当我从 Xcode 重新运行时),那么我会遇到这样的情况:收到一条“已连接”消息,然后收到一条“未连接”消息稍后再留言。这让我很失望。但仔细一看,我可以发现“未连接”消息实际上是针对与已连接的peerId不同的peerId。
我认为这里的问题是,我见过的大多数示例只关心对等点 ID 的显示名称,而忽略了您可以为同一设备/显示名称获取多个对等点 ID 的事实。
我现在首先检查displayName,然后通过比较指针来验证peerID 是否相同。
- (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;
...
我无法得到任何工作的可接受答案,所以我所做的是有一个计时器,当浏览器报告未连接并且没有其他连接的对等点时,该计时器会触发重置连接。
-(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];
}
);
}
}
...
}
您可以在 Swift 3 中使用以下代码从 MCBrowserViewController 中删除对等点:
self.mySession.cancelConnectPeer(self.myPeerID)