문제

커뮤니티에서 직면한 모든 버그를 고려할 때 이 Multipeer Connectivity 프레임워크가 실제 세계에서 사용할 준비가 되었는지 궁금합니다.나는 그것을 올바르게 설정했다고 생각하지만, 내가 시도한 다른 모든 샘플 프로젝트에서도 비슷한 문제가 발생했습니다.

내가 겪고 있는 문제는 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 장치에서 내 앱을 실행하고 다른 iOS 장치에 연결 한 다음 (Xcode에서 재실행 할 때) 종료하고 다시 실행 한 경우, 연결된 메시지를 얻은 다음 연결되지 않은 상황에 처한 것 같습니다.조금 나중에 메시지.이것은 나를 던지고 있었다.그러나 더 자세히 찾으려면 연결된 메시지가 실제로 연결된 다른 피레점에 대해서는 실제로 다른 피어리트가 의미합니다.

여기서 문제는 PeerID의 DisplayName을 보살펴 주었고 동일한 장치 / DisplayName에 대해 여러 피어리드를 얻을 수 있다는 사실을 방치하는 대부분의 샘플이 그렇게 생각합니다.

이제 먼저 DisplayName을 확인한 다음 PeerID가 Pointers의 비교를 수행하여 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];
            }
        );
    }
}
...
.

}

스위프트 3에서 다음 코드가있는 McBrowserViewController에서 피어를 삭제할 수 있습니다.

self.mySession.cancelConnectPeer(self.myPeerID)
.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top