Why is MultipeerConnectivity so unstable?

Hello!
I've been trying to use the MultipeerConnectivity framework but it seems that it is very unstable.
Most of the times the connection doesn't succeed, others it does. Sometimes it only works on the first time the app is built into the device, other times it works after the first build but depends if a certain combination of Wi-Fi, Bluetooth or mobile data is enabled. I just can't get it to work properly every time!
The error occurs when the device starts browsing for other devices, it detects the other device but when the name of the second device appears on the screen, and after selecting it, the connection is not established and is not possible to click "Done" on the BrowserViewController - the only option is to return to the previous ViewController with no connection established.

Other times, even when it connects, I get ICE errors like the one listed here.

I've read on this forum that it is not the first time this framework has some stability issues.

Is this framework still having problems? If so, when are they going to be solved?

If you have no issues with this framework can you please share your project here so I can see if there is any difference between your implementation and mine?

Thanks in advance!

Multipeer Connectivity combines two technologies, each with their own issues:

  • The core Multipeer Connectivity networking code itself

  • The peer-to-peer networking infrastructure

Multipeer Connectivity’s approach, which emphasises simplicity over configurability, makes it hard to tease these issues apart.

Before going further I’d like to investigate whether your network architecture and Multipeer Connectivity’s architecture are well matched. The most common problem I see with Multipeer Connectivity is that folks who have a standard client/server networking architecture try to implement that on top of Multipeer Connectivity. This generally doesn’t end well. If you’re doing client/server, you would typically use standard TCP/IP APIs, using NSNetService for service discovery, and enabling peer-to-peer if you want to work over peer-to-peer network interfaces.

So, can you explain more about your networking architecture? How many peers do you typically have? Is there relationship asymmetric (client/server) or symmetric (à la Multipeer Connectivity)?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

For the app I'm talking about I implemented MultipeerConnectivity in the easiest way possible just to see if I was able to get it to work. I followed this tutorial but instead of sharing photos through the service I just send text.
Since I'm a rookie developer I still don't understand some terms that you asked me, but you can see my simple implementation on GitHub here.
I was just testing this app so the maximum number of peers that I was able to establish a connection was 3 (my iPhone 5S, iPad 3 and xCode simulator).
I just tried the app now and although it worked the first time I still got errors, even with the connection established. After that I tried closing the app on both devices, launch it and connect again but it didn't work anymore, not even showing errors, the only thing that happens is that the didChange method returns MCSessionState.notConnected. Here is the log of the time I was able to establish a connection (running on my iPhone, connecting to the simulator - host):


Started hosting
Connecting: iPhone
2017-03-29 15:28:02.407752 TextPeer[24407:483376] [ViceroyTrace] [ICE][ERROR] ICEStopConnectivityCheck() found no ICE check with call id (327809769)
Connected: iPhone
2017-03-29 15:28:03.995441 TextPeer[24407:485567] [ViceroyTrace] [ICE][ERROR] Send BINDING_REQUEST failed(C01A0041).
2017-03-29 15:28:04.133165 TextPeer[24407:485567] [ViceroyTrace] [ICE][ERROR] Send BINDING_REQUEST failed(C01A0041).
2017-03-29 15:28:04.272925 TextPeer[24407:485567] [ViceroyTrace] [ICE][ERROR] Send BINDING_REQUEST failed(C01A0041).
2017-03-29 15:28:04.453636 TextPeer[24407:485567] [ViceroyTrace] [ICE][ERROR] Send BINDING_REQUEST failed(C01A0041).
2017-03-29 15:28:04.845815 TextPeer[24407:485567] [ViceroyTrace] [ICE][ERROR] Send BINDING_REQUEST failed(C01A0041).
2017-03-29 15:28:05.626820 TextPeer[24407:485567] [ViceroyTrace] [ICE][ERROR] Send BINDING_REQUEST failed(C01A0041).
2017-03-29 15:28:06.794911 TextPeer[24407:485567] [ViceroyTrace] [ICE][ERROR] Send BINDING_REQUEST failed(C01A0041).
2017-03-29 15:28:08.397170 TextPeer[24407:485567] [ViceroyTrace] [ICE][ERROR] Send BINDING_REQUEST failed(C01A0041).
2017-03-29 15:28:09.930196 TextPeer[24407:485567] [ViceroyTrace] [ICE][ERROR] Send BINDING_REQUEST failed(C01A0041).
2017-03-29 15:28:11.441832 TextPeer[24407:485567] [ViceroyTrace] [ICE][ERROR] Send BINDING_REQUEST failed(C01A0041).
2017-03-29 15:28:12.721926 TextPeer[24407:483385] [GCKSession] Not in connected state, so giving up for participant [1389FAE9] on channel [0].
2017-03-29 15:28:12.731429 TextPeer[24407:483385] [GCKSession] Not in connected state, so giving up for participant [1389FAE9] on channel [1].
2017-03-29 15:28:12.738291 TextPeer[24407:483385] [ViceroyTrace] [ICE][ERROR] ICEStopConnectivityCheck() found no ICE check with call id (327809769)
2017-03-29 15:28:12.740297 TextPeer[24407:483385] [GCKSession] Not in connected state, so giving up for participant [1389FAE9] on channel [2].
2017-03-29 15:28:12.745598 TextPeer[24407:483385] [ViceroyTrace] [ICE][ERROR] ICEStopConnectivityCheck() found no ICE check with call id (327809769)
2017-03-29 15:28:12.746819 TextPeer[24407:483385] [GCKSession] Not in connected state, so giving up for participant [1389FAE9] on channel [3].
2017-03-29 15:28:12.753022 TextPeer[24407:483385] [ViceroyTrace] [ICE][ERROR] ICEStopConnectivityCheck() found no ICE check with call id (327809769)
2017-03-29 15:28:29.660144 TextPeer[24407:483230] [MC] System group container for systemgroup.com.apple.configurationprofiles path is /Users/Sandro/Library/Developer/CoreSimulator/Devices/4293C02B-FC4A-43D3-A610-526593234314/data/Containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles
2017-03-29 15:28:29.661097 TextPeer[24407:483230] [MC] Reading from private effective user settings.
2017-03-29 15:28:43.798318 TextPeer[24407:483385] [ViceroyTrace] [ICE][ERROR] ICEStopConnectivityCheck() found no ICE check with call id (327809769)
Not Connected: iPhone

Since I'm a rookie developer I still don't understand some terms that you asked me …

I do not, alas, have time to watch YouTube tutorials. At the networking level my questions are about who initiates communication. In a client/server model, there’s a single server passively listening for incoming connections and clients actively connect to that server. In a multipeer model you have a group of clients that, once things are set up, can all communicate with each other.

This difference is often reflected in the UI. Safari connecting to a web server is the canonical example of a client/server setup. OTOH, many games work in multipeer mode: all the pairing is done up front after which each peer talks directly to the other peers.

So, what sort of UI are you looking for?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I understand, I included the Youtube tutorial just for reference. I thought that by sharing my simple implementation on GitHub you would be able to easily understand what kind of architecture I was using and clarify your questions.

My project is a single view application that currently looks like this.

The unique purpose of the app is to allow the user to host a session, or to join an existing one, and by doing this they can send messages between each other. In this case, when the user clicks on the "Connect to Peers" button a UIAlertController is presented. If the user selects "Host a session" the MCAdvertiserAssistant is started, if the user selects "Join a session" the MCBrowserViewController is presented. Once the connection between the two users is established, they can write something into the text field and when they click "Send message" the "Waiting for message" string will be populated with the string that was just sent.

Regarding your question of whether I want it to be a client/server or multipeer model: Honestly this is not clear to me since my implementation appears to have characteristics of both models simultaneously. From my understanding, it seems that the user that selects "Host a session" is being the server and others - clients, but at the same time, it seems to me that the pairing is done upfront and each peer talks directly to other peers.

I tried to make the easiest implementation of the MultipeerConnectivity framework as possible and even this way, with just 2 peers, it is very unstable and I can't find the logic of why sometimes it works and others it doesn't.

Regarding your question of whether I want it to be a client/server or multipeer model …

Multipeer Connectivity seems like a reasonable choice here, given that once things are set up all of the devices are essentially peers.

A good way to think about this is, after everything is set up, what happens if the original “host a session” device falls off the network? If you want the session to remain viable, you’ll need a peer-to-peer approach. OTOH, if it’s fine for the session to go away in that case, a client/server approach will work (and is generally easier).

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thank you for the clarification on the client/server and multipeer model Quinn!

However the problem I explained that I'm having with the MultipeerConnectivity Framework are still not solved.
Can you please re-read my detailed explanation and tell me how I can solve it or how I can help you understand better the problem?

The most common gotcha with Multipeer Connectivity relates to the handling of the local peer ID. This is explained in detail in the MCPeerID reference. Not following this advice can cause all sorts of weird behaviour in the scenarios you’ve described: each time the app launches it gets a new local peer ID, which can result in ‘ghost peers’, which have the expected name but aren’t actually connected to anything.

I recommend that you fix this in your code and then re-test.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
Why is MultipeerConnectivity so unstable?
 
 
Q