【问题标题】:Reconnecting to disconnected peers重新连接到断开连接的对等体
【发布时间】:2013-10-28 11:55:26
【问题描述】:

我在我的应用程序中使用 iOS 7 Multipeer 框架,但我遇到了设备断开连接的问题。如果我在两个设备中打开应用程序:设备 A 和设备 B,这两个设备会自动相互连接。然而,几秒钟后,设备 A 与设备 B 断开连接。即起初连接是这样的:

A ---> B
A <--- B

几秒钟后:

A ---> B
A      B

设备 A 保持其连接,但设备 B 获得 MCSessionStateNotConnected。

这意味着 A 可以向 B 发送数据,但 B 不能回复。我试图通过检查设备是否已连接来解决此问题,如果未连接,请使用以下方法重新启动连接:

[browser invitePeer:peerID toSession:_session withContext:Nil timeout:10];

但是 didChangeState 回调只是被 MCSessionStateNotConnected 调用。

奇怪的是,如果我将应用程序 A 发送到后台,然后重新打开它,B 重新连接到它并保持连接。

Multipeer API(和文档)似乎有点稀疏,所以我假设它可以正常工作。在这种情况下我应该如何重新连接设备?

【问题讨论】:

  • 是局部问题还是物理问题?你有没有试过在每个 B 到 A 之间做一些tracepath
  • 我很确定这不是物理问题,因为我已经能够使用 DNS-SD 和 CFSockets 手动获得稳定的蓝牙连接。这似乎是一个 MultiPeer 问题。
  • 啊对不起,我以为是远程上网,但它是蓝牙!
  • 您是否同时浏览和投放广告? A 和 B 都邀请和接受吗?
  • 是的 - 只是想在我提供答案之前检查您是否与我在同一条船上。

标签: ios iphone bluetooth multipeer-connectivity


【解决方案1】:

我遇到了同样的问题,这似乎与我的应用同时浏览和广告有关,并且发送/接受了两个邀请。当我停止这样做并让一个对等方推迟到另一个邀请时,设备保持连接。

在我的浏览器委托中,我正在检查已发现对等方的 displayName 的哈希值,并且仅在我的对等方具有更高的哈希值时发送邀请:

编辑

正如@Masa 所指出的,NSStringhash 值在 32 位和 64 位设备上会有所不同,因此在 displayName 上使用 compare: 方法会更安全。

- (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:(NSDictionary *)info {

    NSLog(@"Browser found peer ID %@",peerID.displayName);       

    //displayName is created with [[NSUUID UUID] UUIDString]

    BOOL shouldInvite = ([_myPeerID.displayName compare:peerID.displayName]==NSOrderedDescending);

    if (shouldInvite){
        [browser invitePeer:peerID toSession:_session withContext:nil timeout:1.0]; 
    }
    else {
        NSLog(@"Not inviting");
    }
}

正如您所说,文档很少,所以谁知道 Apple 真正想让我们做什么,但我已经尝试过使用单个会话发送和接受邀请,并为每个接受/发送的邀请创建一个新会话,但这种特殊的做事方式给了我最大的成功。

【讨论】:

  • 非常有帮助,谢谢。请注意,NSString 上的哈希返回一个 NSUInteger。因此,32 位和 64 位系统上的结果不同。所以我只是遇到了没有人发送邀请的情况。我通过简单地对 displayNames 进行字符串比较而不是使用哈希来解决它。 (除此之外,还要注意 NSString 上的哈希值应该小心使用:abakia.de/blog/2012/12/05/nsstring-hash-is-bad
  • @Masa 这很有趣,谢谢。我肯定会改用字符串比较。
  • 设备具有相同的显示名称是否存在风险?如果我有 2 部 iPhone 名称为“Joon 的 iPhone”怎么办?
  • @joon 您有责任确保创建唯一的对等 ID,它们应该始终如此。
  • 这方面的最佳做法是什么?我看到的演示只是使用设备名称,这不是唯一的 afaik。
【解决方案2】:

对于任何感兴趣的人,我创建了MCSessionP2P,这是一个演示应用程序,展示了MCSession 的ad-hoc 网络功能。该应用程序既在本地网络上宣传自己,又以编程方式连接到可用的对等点,从而建立一个对等网络。向@ChrisH 致敬,感谢他为邀请同行比较哈希值的技术。

【讨论】:

  • 对于目前使用 MCBrowserViewControllerMCAdvertiserAssistant 的人来说,这是一个不错的起点
【解决方案3】:

我喜欢 ChrisH 的解决方案,它揭示了只有一个对等方应该连接到另一个对等方的关键见解,而不是两者。相互连接尝试会导致相互断开连接(尽管并非单边连接实际上,违反直觉的是,在状态和通信方面是相互连接,因此可以正常工作)。

但是,我认为比一个同伴邀请更好的方法是让两个同伴都邀请但只有一个同伴接受。我现在使用这种方法,效果很好,因为双方都有机会通过邀请的context 参数将丰富的信息传递给对方,而不必依赖foundPeer 委托方法中可用的少量信息.

因此,我推荐这样的解决方案:

- (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:(NSDictionary *)info
{
    [self invitePeer:peerID];
}

- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void (^)(BOOL accept, MCSession *session))invitationHandler
{
    NSDictionary *hugePackageOfInformation = [NSKeyedUnarchiver unarchiveObjectWithData:context];
    BOOL shouldAccept = ([hugePackageOfInformation.UUID.UUIDString compare:self.user.UUID.UUIDString] == NSOrderedDescending);

    invitationHandler(shouldAccept && ![self isPeerConnected:peerID], [self openSession]);
}

【讨论】:

    【解决方案4】:

    当设备尝试同时相互连接时,我遇到了同样的问题,我不知道如何找到原因,因为我们在 MCSessionStateNotConnected 方面没有任何错误。

    我们可以使用一些巧妙的方法来解决这个问题: 将应用启动时的时间 [[NSDate date] timeIntervalSince1970] 放入 txt 记录(发现信息)。谁先开始 - 向其他人发送邀请。

    但我认为这不是正确的方法(如果应用程序同时启动,不太可能...... :))。我们需要找出原因。

    【讨论】:

    • 更好的解决方案是在邀请上下文参数中传递信息。由于两个设备都可以很好地相互邀请,但只有一个可以接受,因此您可以使用此上下文在收到的邀请委托方法中识别谁应该接受,而不是应该邀请谁 在 found-peer 委托方法中。
    • 我认为@SG1 的方法不太理想,因为它浪费带宽。
    【解决方案5】:

    这是我已向 Apple 报告的错误的结果。我在回答另一个问题时解释了如何解决它:Why does my MCSession peer disconnect randomly?

    我没有将这些问题标记为合并,因为虽然基本错误和解决方案相同,但这两个问题描述了不同的问题。

    【讨论】:

    • 这似乎是拼图中缺失的部分,至少对我来说是这样。谢谢!
    • 即使使用证书处理程序,我仍然会断开连接
    【解决方案6】:

    保存对等体 B 的哈希值。使用计时器连续检查连接状态,如果未连接,则尝试在每个给定时间段内重新连接。

    【讨论】:

    • ——invitePeer:toSession:withContext:timeout: yes
    • 我试过了,它只是向状态委托发送了一个 PeerNotConnected。
    • 第一次查找设备时,您将什么作为 serviceType 传递?
    • 不需要计时器。连接后,您将永远在状态更改时收到委托方法。如果它断开连接,则在连接超时期限到期后尝试重新连接,如果对等方在此期间尚未连接。 @Ben,这与您的问题的解决方案相同。
    【解决方案7】:

    根据苹果文档Choosing an inviter when using Multipeer Connectivity “在 iOS 7 中,同时发送邀请会导致两个邀请都失败,导致双方无法相互通信。”

    但 iOS 8 已修复它。

    【讨论】:

      猜你喜欢
      • 2012-08-07
      • 2018-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多