多点连接终止会话
Posted
技术标签:
【中文标题】多点连接终止会话【英文标题】:Multipeer Connectivity kill session 【发布时间】:2015-03-18 00:40:21 【问题描述】:我正在使用主机/客户端方法来使用 MultiPeer Connectivity。
所以,当用户按下断开按钮时
-(IBAction)disconnect:(id)sender
[_appDelegate.mcManager.session disconnect];
[_arrConnectedDevices removeAllObjects];
ConnectionsViewController *game = [self.storyboard instantiateViewControllerWithIdentifier:@"ConnectionsViewController"];
[self presentViewController:game animated:YES completion:nil];
现在,这工作正常。从主机的角度来看,它会在日志中收到一条断开连接消息。并且客户端移动到新的视图控制器。并且表格已更新。有了这个。
-(void)peerDidChangeStateWithNotification:(NSNotification *)notification
MCPeerID *peerID = [[notification userInfo] objectForKey:@"peerID"];
NSString *peerDisplayName = peerID.displayName;
MCSessionState state = [[[notification userInfo] objectForKey:@"state"] intValue];
if (state != MCSessionStateConnecting)
if (state == MCSessionStateConnected)
if (_makeSureImHost)
[_arrConnectedDevices addObject:peerDisplayName];
[_tblConnectedDevices performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
else
[self sendMessageToHostWithMessage:@"deviceInfo"];
else if (state == MCSessionStateNotConnected)
if ([_arrConnectedDevices count] > 0)
int indexOfPeer = (int)[_arrConnectedDevices indexOfObject:peerDisplayName];
[_arrConnectedDevices removeObjectAtIndex:indexOfPeer];
NSLog(@"%@ Disconnected", peerDisplayName);
[_tblConnectedDevices performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
_tblConnectedDevices.frame = CGRectMake(_backgroundImage.frame.size.width / 2 - 150, self.backgroundImage.frame.size.height / 3, 300, 150);
大厅视图控制器结束
开始连接视图控制器
当客户端按下浏览本地设备时,它会运行
- (IBAction)browseForDevices:(id)sender
[UIView animateWithDuration:0.5f
animations:^
_searchButton.frame = CGRectMake(-100, self.backgroundImage.frame.size.height/2 + 60, 100, 35.0);
_hostButton.alpha = 0;
_modeLabel.alpha = 0;
];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^
[[_appDelegate mcManager] setupPeerAndSessionWithDisplayName:[UIDevice currentDevice].name];
[[_appDelegate mcManager] advertiseSelf:false];
[[_appDelegate mcManager] setupMCBrowser];
[[[_appDelegate mcManager] browser] setDelegate:self];
_appDelegate.mcManager.browser.maximumNumberOfPeers = 1;
_appDelegate.mcManager.browser.modalTransitionStyle=UIModalTransitionStyleCrossDissolve;
[self presentViewController:[[_appDelegate mcManager] browser] animated:YES completion:nil];
);
建立连接时
-(void)browserViewControllerDidFinish:(MCBrowserViewController *)browserViewController
[_appDelegate.mcManager.browser dismissViewControllerAnimated:NO completion:^
[self launchViewController];
];
-(void)launchViewController
LobbyViewController *lobby = [self.storyboard instantiateViewControllerWithIdentifier:@"LobbyViewController"];
[self presentViewController:lobby animated:NO completion:nil];
从这里
-(void)peerDidChangeStateWithNotification:(NSNotification *)notification
MCPeerID *peerID = [[notification userInfo] objectForKey:@"peerID"];
NSString *peerDisplayName = peerID.displayName;
MCSessionState state = [[[notification userInfo] objectForKey:@"state"] intValue];
if (state != MCSessionStateConnecting)
if (state == MCSessionStateConnected)
[self browserViewControllerDidFinish:[[_appDelegate mcManager] browser]];
else if (state == MCSessionStateNotConnected)
if ([_arrConnectedDevices count] > 0)
int indexOfPeer = (int)[_arrConnectedDevices indexOfObject:peerDisplayName];
[_arrConnectedDevices removeObjectAtIndex:indexOfPeer];
现在。首次建立连接时。这一切都完美无缺。它连接,加载视图,主机启动游戏,游戏运行正常,数据传输完美。
但是,如果您断开与大厅的连接。移动到连接视图控制器,然后再次浏览设备。它将连接,但大厅视图控制器将不在视图层次结构中,并将关闭浏览器并留在连接视图控制器中。
然后,最重要的是,连接已经建立。然而,当它收到来自主机的消息时,它会发送响应,两次..或三次,或四次,导致我进入死胡同。我唯一可以推测的是,从“客户”的角度来看,之前的会话正在以某种方式被记住。
现在,我可以采取一些措施来避免这种混乱。如果我终止应用程序并重新启动它,我现在可以从客户端的角度再次连接。这让我相信,问题出在客户端。
我的问题是我必须彻底解决这个问题。因此,断开连接将完全从会话中删除所有内容。所以他们可以重新连接。并且不能依靠消息来告诉用户重新启动他们的应用程序。只是不可能。
这是我的整个 MCManager.m 文件。
@implementation MCManager
-(id)init
self = [super init];
if (self)
_peerID = nil;
_session = nil;
_browser = nil;
_advertiser = nil;
return self;
-(void)setupPeerAndSessionWithDisplayName:(NSString *)displayName
_peerID = [[MCPeerID alloc] initWithDisplayName:displayName];
_session = [[MCSession alloc] initWithPeer:_peerID];
_session.delegate = self;
-(void)setupMCBrowser
_browser = [[MCBrowserViewController alloc] initWithServiceType:@"chat-files" session:_session];
-(void)advertiseSelf:(BOOL)shouldAdvertise
if (shouldAdvertise)
_advertiser = [[MCAdvertiserAssistant alloc] initWithServiceType:@"chat-files"
discoveryInfo:nil
session:_session];
[_advertiser start];
else
[_advertiser stop];
_advertiser = nil;
-(void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state
NSDictionary *dict = @@"peerID": peerID,
@"state" : [NSNumber numberWithInt:state]
;
[[NSNotificationCenter defaultCenter] postNotificationName:@"MCDidChangeStateNotification"
object:nil
userInfo:dict];
-(void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID
NSDictionary *dict = @@"data": data,
@"peerID": peerID
;
[[NSNotificationCenter defaultCenter] postNotificationName:@"MCDidReceiveDataNotification"
object:nil
userInfo:dict];
-(void)session:(MCSession *)session didStartReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID withProgress:(NSProgress *)progress
-(void)session:(MCSession *)session didFinishReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID atURL:(NSURL *)localURL withError:(NSError *)error
-(void)session:(MCSession *)session didReceiveStream:(NSInputStream *)stream withName:(NSString *)streamName fromPeer:(MCPeerID *)peerID
@end
#import <MultipeerConnectivity/MultipeerConnectivity.h>
@interface MCManager : NSObject <MCSessionDelegate>
@property (nonatomic, strong) MCPeerID *peerID;
@property (nonatomic, strong) MCSession *session;
@property (nonatomic, strong) MCBrowserViewController *browser;
@property (nonatomic, strong) MCAdvertiserAssistant *advertiser;
-(void)setupPeerAndSessionWithDisplayName:(NSString *)displayName;
-(void)setupMCBrowser;
-(void)advertiseSelf:(BOOL)shouldAdvertise;
@end
如果有人知道我做错了什么,我将不胜感激。这让我发疯了。
【问题讨论】:
谢谢。请为 nieve 读者添加一些上下文。我来到这里是因为我想知道我是否需要大厅,或者连接到另一台设备是否会导致 MPC 向已连接到该另一台设备的所有其他设备发送连接事件?你的代码对我有什么作用,即为什么要使用主机/客户端? @bootchk 这个问题的目的是在断开连接后重新连接。但是,我想我会提到我正在以特定的模式使用它。您对所有客户接收的问题是否定的。如果您使用 peerID 向该特定客户端发送消息,那么您可以单独向该客户端发送消息。但是,作为主持人。每个人都接收到客户端来托管消息,这可以很容易地用一个简单的布尔值来解释。使用主机/客户端的原因是为了简化比赛/游说。或者,您最终会陷入混乱,试图弄清楚。 【参考方案1】:[[NSNotificationCenter defaultCenter] removeObserver:name:object:];
解决了我所有的问题。希望也能帮助其他人。
【讨论】:
【参考方案2】:使用 Swift,我按如下方式结束多人会话(在完成会话跟踪器的 deinit
的检查后):
func stopSession()
self.serviceBrowser.stopBrowsingForPeers()
self.serviceBrowser.delegate = nil
self.serviceAdvertiser.stopAdvertisingPeer()
self.serviceAdvertiser.delegate = nil
self.session.disconnect()
self.peerSessionIDs.removeAll()
self.session.delegate = nil
self.session = nil
self.multipeerConnectivityService = nil
self.serviceType = nil
换句话说,所有已注册和初始化程序都被取消初始化。我以相反的顺序执行此操作,但我不确定这里的顺序是否重要。
【讨论】:
以上是关于多点连接终止会话的主要内容,如果未能解决你的问题,请参考以下文章