为啥多点连接如此缓慢?
Posted
技术标签:
【中文标题】为啥多点连接如此缓慢?【英文标题】:Why is Multipeer Connectivity so slow?为什么多点连接如此缓慢? 【发布时间】:2014-07-15 18:34:35 【问题描述】:所以,我在主线程中有所有与多点连接相关的代码。我有一个MCSession, MCNearbyServiceAdvertiser, and a MCNearbyServiceBrowser
。这些都是用 peerID 创建的,我确保只有一个人发送邀请。
会话已连接。我的问题是,两个客户端大约需要 20-30 秒才能连接。这是不可接受的。客户使用良好的 Wifi 和蓝牙。我希望在 1 秒内完成浏览、邀请处理程序和连接。有谁知道是什么让事情变慢了?
代码与此处提供的完全相同,我还实现了certificateHandler(YES)
@interface SessionController () // Class extension
@property (nonatomic, strong) MCPeerID *peerID;
@property (nonatomic, strong) MCSession *session;
@property (nonatomic, strong) MCNearbyServiceAdvertiser *serviceAdvertiser;
@property (nonatomic, strong) MCNearbyServiceBrowser *serviceBrowser;
// Connected peers are stored in the MCSession
// Manually track connecting and disconnected peers
@property (nonatomic, strong) NSMutableOrderedSet *connectingPeersOrderedSet;
@property (nonatomic, strong) NSMutableOrderedSet *disconnectedPeersOrderedSet;
@end
@implementation SessionController
static NSString * const kMCSessionServiceType = @"mcsessionp2p";
#pragma mark - Initializer
- (instancetype)init
self = [super init];
if (self)
_peerID = [[MCPeerID alloc] initWithDisplayName:[[UIDevice currentDevice] name]];
_connectingPeersOrderedSet = [[NSMutableOrderedSet alloc] init];
_disconnectedPeersOrderedSet = [[NSMutableOrderedSet alloc] init];
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
// Register for notifications
[defaultCenter addObserver:self
selector:@selector(startServices)
name:UIApplicationWillEnterForegroundNotification
object:nil];
[defaultCenter addObserver:self
selector:@selector(stopServices)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
[self startServices];
_displayName = self.session.myPeerID.displayName;
return self;
#pragma mark - Memory management
- (void)dealloc
// Unregister for notifications on deallocation.
[[NSNotificationCenter defaultCenter] removeObserver:self];
// Nil out delegates
_session.delegate = nil;
_serviceAdvertiser.delegate = nil;
_serviceBrowser.delegate = nil;
#pragma mark - Override property accessors
- (NSArray *)connectedPeers
return self.session.connectedPeers;
- (NSArray *)connectingPeers
return [self.connectingPeersOrderedSet array];
- (NSArray *)disconnectedPeers
return [self.disconnectedPeersOrderedSet array];
#pragma mark - Private methods
- (void)setupSession
// Create the session that peers will be invited/join into.
_session = [[MCSession alloc] initWithPeer:self.peerID];
self.session.delegate = self;
// Create the service advertiser
_serviceAdvertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:self.peerID
discoveryInfo:nil
serviceType:kMCSessionServiceType];
self.serviceAdvertiser.delegate = self;
// Create the service browser
_serviceBrowser = [[MCNearbyServiceBrowser alloc] initWithPeer:self.peerID
serviceType:kMCSessionServiceType];
self.serviceBrowser.delegate = self;
- (void)teardownSession
[self.session disconnect];
[self.connectingPeersOrderedSet removeAllObjects];
[self.disconnectedPeersOrderedSet removeAllObjects];
- (void)startServices
[self setupSession];
[self.serviceAdvertiser startAdvertisingPeer];
[self.serviceBrowser startBrowsingForPeers];
- (void)stopServices
[self.serviceBrowser stopBrowsingForPeers];
[self.serviceAdvertiser stopAdvertisingPeer];
[self teardownSession];
- (void)updateDelegate
[self.delegate sessionDidChangeState];
- (NSString *)stringForPeerConnectionState:(MCSessionState)state
switch (state)
case MCSessionStateConnected:
return @"Connected";
case MCSessionStateConnecting:
return @"Connecting";
case MCSessionStateNotConnected:
return @"Not Connected";
#pragma mark - MCSessionDelegate protocol conformance
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state
NSLog(@"Peer [%@] changed state to %@", peerID.displayName, [self stringForPeerConnectionState:state]);
switch (state)
case MCSessionStateConnecting:
[self.connectingPeersOrderedSet addObject:peerID];
[self.disconnectedPeersOrderedSet removeObject:peerID];
break;
case MCSessionStateConnected:
[self.connectingPeersOrderedSet removeObject:peerID];
[self.disconnectedPeersOrderedSet removeObject:peerID];
break;
case MCSessionStateNotConnected:
[self.connectingPeersOrderedSet removeObject:peerID];
[self.disconnectedPeersOrderedSet addObject:peerID];
break;
[self updateDelegate];
- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID
// Decode the incoming data to a UTF8 encoded string
NSString *receivedMessage = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"didReceiveData %@ from %@", receivedMessage, peerID.displayName);
- (void)session:(MCSession *)session didStartReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID withProgress:(NSProgress *)progress
NSLog(@"didStartReceivingResourceWithName [%@] from %@ with progress [%@]", resourceName, peerID.displayName, progress);
- (void)session:(MCSession *)session didFinishReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID atURL:(NSURL *)localURL withError:(NSError *)error
NSLog(@"didFinishReceivingResourceWithName [%@] from %@", resourceName, peerID.displayName);
// If error is not nil something went wrong
if (error)
NSLog(@"Error [%@] receiving resource from %@ ", [error localizedDescription], peerID.displayName);
else
// No error so this is a completed transfer. The resources is located in a temporary location and should be copied to a permenant location immediately.
// Write to documents directory
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *copyPath = [NSString stringWithFormat:@"%@/%@", [paths firstObject], resourceName];
if (![[NSFileManager defaultManager] copyItemAtPath:[localURL path] toPath:copyPath error:nil])
NSLog(@"Error copying resource to documents directory");
else
// Get a URL for the path we just copied the resource to
NSURL *url = [NSURL fileURLWithPath:copyPath];
NSLog(@"url = %@", url);
// Streaming API not utilized in this sample code
- (void)session:(MCSession *)session didReceiveStream:(NSInputStream *)stream withName:(NSString *)streamName fromPeer:(MCPeerID *)peerID
NSLog(@"didReceiveStream %@ from %@", streamName, peerID.displayName);
#pragma mark - MCNearbyServiceBrowserDelegate protocol conformance
// Found a nearby advertising peer
- (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:(NSDictionary *)info
NSString *remotePeerName = peerID.displayName;
NSLog(@"Browser found %@", remotePeerName);
MCPeerID *myPeerID = self.session.myPeerID;
BOOL shouldInvite = ([myPeerID.displayName compare:remotePeerName] == NSOrderedDescending);
if (shouldInvite)
NSLog(@"Inviting %@", remotePeerName);
[browser invitePeer:peerID toSession:self.session withContext:nil timeout:30.0];
else
NSLog(@"Not inviting %@", remotePeerName);
[self updateDelegate];
- (void)browser:(MCNearbyServiceBrowser *)browser lostPeer:(MCPeerID *)peerID
NSLog(@"lostPeer %@", peerID.displayName);
[self.connectingPeersOrderedSet removeObject:peerID];
[self.disconnectedPeersOrderedSet addObject:peerID];
[self updateDelegate];
- (void)browser:(MCNearbyServiceBrowser *)browser didNotStartBrowsingForPeers:(NSError *)error
NSLog(@"didNotStartBrowsingForPeers: %@", error);
#pragma mark - MCNearbyServiceAdvertiserDelegate protocol conformance
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void(^)(BOOL accept, MCSession *session))invitationHandler
NSLog(@"didReceiveInvitationFromPeer %@", peerID.displayName);
invitationHandler(YES, self.session);
[self.connectingPeersOrderedSet addObject:peerID];
[self.disconnectedPeersOrderedSet removeObject:peerID];
[self updateDelegate];
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didNotStartAdvertisingPeer:(NSError *)error
NSLog(@"didNotStartAdvertisingForPeers: %@", error);
@end
【问题讨论】:
客户端是否在同一个 WiFi 上?我注意到如果它们是不同的网络,它们需要很长时间才能连接。 他们都在wifi,蓝牙上。我也只尝试过一种媒介。一样的 但是当他们使用 WiFi 时,是同一个网络吗?当我将一个放在 5GHz 上,另一个放在 2.4Ghz 上时,我可以重现 20 秒的延迟。 延迟到底发生在哪里?是在他们见面之前,在邀请接受阶段,还是在连接之后但在发送数据之前? 它是发现、邀请、接受阶段。 【参考方案1】:我已经注意到了这个问题,但我似乎无法弄清楚这里发生了什么,在调试时似乎在触发状态更改通知之间存在巨大延迟,可能与视图本身有关.
更新:好吧,我想我在阅读了一些内容后发现了问题,现在响应几乎是即时的,在视图中的通知中,我已将进程推回主线程,如下所示:
-(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)
// add the user
[arrConnectedDevices addObject:peerDisplayName];
else if (state == MCSessionStateNotConnected)
// do we have connections
if ([arrConnectedDevices count] > 0)
int indexOfPeer = [arrConnectedDevices indexOfObject:peerDisplayName];
[arrConnectedDevices removeObjectAtIndex:indexOfPeer];
// push to main queue for speedy response
dispatch_async(dispatch_get_main_queue(), ^(void)
[collView reloadData];
BOOL peersExist = ([[appDelegate.mcManager.session connectedPeers] count] == 0);
NSLog(@"PEER COUNT IS %lu",(unsigned long)[[appDelegate.mcManager.session connectedPeers] count]);
[disconnectButton setEnabled:!peersExist];
if ([disconnectButton isEnabled])
[disconnectButton setBackgroundColor:[UIColor colorWithRed:(51/255.0) green:(202/255.0) blue:(168/255.0) alpha:1.0]];
else
[disconnectButton setBackgroundColor:[UIColor colorWithRed:(107/255.0) green:(107/255.0) blue:(107/255.0) alpha:1.0]];
);
希望这对遇到问题的人有所帮助。
【讨论】:
嗨,这很简单。任何需要快速更改 ui 的东西都需要在主线程上调度。我的问题涉及一个不同的问题。无论如何,我找到了解决方案。我很快就会在这里发帖。 @Legolas 我也会对您的解决方案感兴趣。 @Legolas 对此有何意见? @Legolas 您是否找到了加快速度的解决方案?谢谢 @Legolas,你的姓是 Fermat 吗? ;)以上是关于为啥多点连接如此缓慢?的主要内容,如果未能解决你的问题,请参考以下文章