web-dev-qa-db-ja.com

切断されたピアへの再接続

アプリでiOS7 Multipeerフレームワークを使用していますが、デバイスの切断で問題が発生しています。デバイスAとデバイスBの2つのデバイスでアプリを開くと、2つのデバイスは自動的に相互に接続します。ただし、数秒後、デバイス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(およびドキュメント)は少しまばらに見えるので、私はそれがうまくいくと思っていました。この状況では、どのようにデバイスを再接続する必要がありますか?

30
James Andrews

同じ問題が発生していましたが、アプリの閲覧と広告が同時に行われ、2つの招待状が送信/承認されたことが関係しているようです。これをやめて、一方のピアが招待を他のピアに延期させたとき、デバイスは接続されたままでした。

ブラウザのデリゲートで、検出されたピアのdisplayNameのハッシュ値を確認し、ピアのハッシュ値が高い場合にのみ招待状を送信しています。

編集

@Masaが指摘しているように、hashNSString値は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が本当に私たちに何をしたいのかを知っていますが、私は単一のセッションを使用して招待状を送信および受信し、新しいセッションを作成することも実験しました受け入れ/送信された招待ごとに、しかしこの特定のやり方で私は最も成功しました。

22
ChrisH

興味のある人のために、私はMCSessionのアドホックネットワーク機能を説明するデモアプリ MCSessionP2P を作成しました。アプリはローカルネットワーク上で自身をアドバタイズし、プログラムで利用可能なピアに接続して、ピアツーピアネットワークを確立します。ピアを招待するためにハッシュ値を比較する彼のテクニックについては、@ ChrisHへのヒントです。

5
Marco

私はChrisHのソリューションが好きでした。これは、一方のピアだけがもう一方のピアに接続し、両方には接続しないという重要な洞察を明らかにします。相互接続を試みると、相互切断が発生します(ただし、片側接続が実際にはisであり、直感に反して、ステータスと通信の観点から相互接続であるため、正常に機能します)。

ただし、1つのピアinvitingよりも優れたアプローチは、両方のピアを招待することですが、acceptに1つのピアのみを招待することです。 。私は現在このメソッドを使用していますが、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
SG1

デバイスが同時に相互に接続しようとすると同じ問題が発生しますが、MCSessionStateNotConnectedのエラーがないため、理由を見つける方法がわかりません。

この問題を解決するには、巧妙な方法を使用できます。txtレコード(検出情報)に時刻を入力します[[NSDate date] timeIntervalSince1970]アプリの起動時。誰が最初に始めたのか-他の人に招待状を送る。

しかし、それは正しい方法ではないと思います(アプリが同時に起動する場合、可能性は低いです... :))。その理由を理解する必要があります。

3
Max Sokolov

これは私がAppleに報告したバグの結果です。別の質問への回答で修正する方法を説明しました: MCSessionピアがランダムに切断されるのはなぜですか?

根本的なバグと解決策は同じですが、2つの質問は異なる問題を説明しているため、これらの質問にマージのフラグを立てていません。

2
Andrew Cone

ピアBのハッシュを保存します。タイマーを使用して接続の状態を継続的にチェックし、接続されていない場合は、指定された期間ごとに再接続を試みます。

1
artud2000

Appleドキュメント マルチピア接続を使用する場合の招待者の選択 「iOS7では、同時に招待を送信すると、両方の招待が失敗し、両方のピアがそれぞれと通信できなくなる可能性があります。その他。」

しかし、iOS8はそれを修正しました。

0
Qiulang