I want achieve what @eskimo said in his answer on this page - https://developer.apple.com/forums/thread/663596:
Have each peer decide on its own unique ID.
When a client connects to a server, the first message it sends across that connection contains its unique ID.
The server then responds with its own unique ID.
If either end discovers that a connection with that unique ID pair already exists, it drops one of the connections. As long as they both agree to drop the same connection, everything will be fine. A good strategy here is to drop the one with the lesser ID.
I looked at Apple's TicTokToe example app and they set a password string using a custom initializer. I followed some of their code but once the Listener starts and the connection.stateUpdateHandler is called it never goes past .preparing:
connection.stateUpdateHandler = { [weak self](nwConnectionState) in
	 switch nwConnectionState {
				case .preparing:
	 print("Connection preparing") // it's stuck here
				// ...
		}
}
Here is how I use the custom param (rest of setup is in this question): - https://developer.apple.com/forums/thread/669062?answerId=651917022#651917022
var listener: NWListener?
init () {
		do {
				let uid = UUID().uuidString
				let parameters = NWParameters(uid: uid)
				listener = try NWListener(using: parameters)
				listener?.service = NWListener.Service(name: "MyName", type: "_myApp._tcp")
				startListening()
		} catch {
		}
}
I'm using UUID().uuidString to create the uid just so that I can attempt what @eskimo proposed in step 2 and step 4. Once the user kills the app and opens it again a new uid will be generated every time they try to connect with other devices. Because of this I don't need the uid to be secure. The Apple TikTokToe tls code seemed like overkill for my situation so I removed all of the encryption features that they used.
How do I add the uid string to the NWProtocolTLS.Options()?
extension NWParameters {
convenience init(uid: String) {
	let tcpOptions = NWProtocolTCP.Options()
tcpOptions.enableKeepalive = true
tcpOptions.keepaliveIdle = 2
	 self.init(tls: NWParameters.tlsOptions(uid: uid), tcp: tcpOptions)
}
private static func tlsOptions(uid: String) -> NWProtocolTLS.Options {
	let tlsOptions = NWProtocolTLS.Options()
	return tlsOptions
}
}
It should be noted that outside of the problems inside the link, - https://developer.apple.com/forums/thread/669062?answerId=651917022#651917022 the problem from this question is avoided and .ready is called when I use the normal initializer:
let tcpOptions = NWProtocolTCP.Options()
tcpOptions.enableKeepalive = true
tcpOptions.keepaliveIdle = 2
let parameters = NWParameters(tls: nil, tcp: tcpOptions)
parameters.includePeerToPeer = true
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I have a NWBrowser and a NWConnection on my iPhone 7+ (real device) that sends out some data. On the simulator I have a NWListener and a NWConnection that receives the data.
Inside the NWListener class named PeerListener, inside the listener.newConnectionHandler callback I have a delegate to create a NWConnection that gets hit multiple times when I put a break point on it. This results in the NWConnection's connection.stateUpdateHandler printing out the following multiple times below:
// these are all .preparing and .ready cases
Connection preparing
Connection established
Connection preparing
Connection established
Connection preparing
Connection established
Connection preparing
Connection established
Connection preparing
Connection established
Connection preparing
Connection established
Connection preparing
Connection established
Connection preparing
Connection established
Connection preparing
Connection established
Connection preparing
Connection established
After the last print statement, which is .ready, the connection is sent over to the VC via a delegate where connection.receiveMessage runs. I put a break point on it, it gets hit, but the call back is never entered.
I'm not sure what the problem is because the connection is definitely happening between the device and simulator, all the correct methods are hit (unfortunately multiple times), but the callback is never entered. What is the problem here?
NWListener
protocol PeerListenerDelegate: class {
func createNewIncoming(_ connection: NWConnection)
}
class PeerListener {
weak var delegate: PeerListenerDelegate?
fileprivate var listener: NWListener?
		init () {
do {
let tcpOptions = NWProtocolTCP.Options()
tcpOptions.enableKeepalive = true
tcpOptions.keepaliveIdle = 2
let parameters = NWParameters(tls: nil, tcp: tcpOptions)
parameters.includePeerToPeer = true
listener = try NWListener(using: parameters)
listener?.service = NWListener.Service(name: "MyName", type: "_myApp._tcp")
startListening()
} catch let error as NSError {
print("Failed to create listener", error.debugDescription)
}
}
		fileprivate func startListening() {
guard let listener = listener else { return }
listener.stateUpdateHandler = { [weak self](newState) in
switch newState {
						case .setup: print("listener setup")
case .ready: print("Listener ready on \(String(describing: listener.port))")
case .cancelled: print("listener cancelled")
case .failed(let error):
if error == NWError.dns(DNSServiceErrorType(kDNSServiceErr_DefunctConnection)) {
listener.cancel()
self?.startListening()
} else {
print(error.debugDescription)
listener.cancel()
}
default:break
}
}
receivedNewConnectionFrom(listener)
listener.start(queue: .main)
}
		fileprivate func receivedNewConnectionFrom(_ listener: NWListener) {
listener.newConnectionHandler = { [weak self](newConnection) in
self?.delegate?.createNewIncoming(newConnection)
}
}
}
VC that initializes the Listener, connection.receiveMessage is in here, last function at the bottom, line 23
class ViewController: UIViewController {
		fileprivate var listener: PeerListener?
		fileprivate var connectionIncoming: ConnectionIncoming?
		override func viewDidLoad() {
super.viewDidLoad()
				listener = PeerListener()
listener?.delegate = self
		}
		// 1. PeerListenerDelegate to create NWConnection object
		func createNewIncoming(_ connection: NWConnection) {
self.connectionIncoming = ConnectionIncoming(connection:connection, delegate: self)
}
		// 2. ConnectionIncomingDelegate to receive data from connection object
		func receivedIncoming(_ connection: NWConnection) {
connection.receiveMessage { [weak self](data, context, isComplete, error) in
print(" *** callback entered * THIS NEVER GETS HIT *** ")
if let err = error {
print("Recieve error: \(err.debugDescription)")
return
}
if isComplete {
print("Receive is complete")
if let data = data, !data.isEmpty {
										self?.received(data, from: connection)
}
} else {
print("Not Complete")
}
}
}
}
NWConnection
protocol ConnectionIncomingDelegate: class {
func receivedIncoming(_ connection: NWConnection)
}
class ConnectionIncoming {
weak var delegate: ConnectionIncomingDelegate?
private var connection: NWConnection?
init(connection: NWConnection, delegate: ConnectionIncomingDelegate) {
self.delegate = delegate
self.connection = connection
startConnection()
}
func startConnection() {
guard let connection = connection else { return }
connection.stateUpdateHandler = { [weak self](nwConnectionState) in
switch nwConnectionState {
						case .preparing: print("Connection preparing")
case .setup: print("Connection setup")
case .waiting(let error): print("Connection waiting: ", error.debugDescription)
case .ready:
print("Connection established")
self?.delegate?.receivedIncoming(connection)
case .failed(let error):
print("Connection failed: ", error.debugDescription)
connection.cancel()
default:break
}
}
connection.start(queue: .main)
}
}
When using MultipeerSession I can set a limit to the number of peers on each connection using:
func peerDiscovered(_ peer: MCPeerID) -> Bool {
if multipeerSession.connectedPeers.count > 4 {
// Do not accept more than four users in the experience.
return false
}
}
Im using peer-to-peer with NWConnection, NWListener, and NWBrowser:
let params = NWParameters()
params.includePeerToPeer = true
How can I set a limit to the number of users/peers allowed per connection?
self.connection?.receiveMessage { (data, context, isComplete, error) in
if (isComplete) {
if let data = data, !data.isEmpty {
						// do something with data
				}
		}
}