Posts

Post marked as solved
2 Replies
1.4k Views
NetServiceBrowser has 2 delegate functions. The first delegate gets called when it discovers a service netServiceBrowser(: didFind: moreComing: ) and the second delegate (below) gets triggered when the address is resolved. You can use that delegate to get the ipaddress:func netServiceDidResolveAddress(_ sender: NetService) { print("did resolve address") var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST)) guard let data = sender.addresses?.first else { print("guard let data failed"); return } data.withUnsafeBytes { (pointer: UnsafeRawBufferPointer) -> Void in let sockaddrPtr = pointer.bindMemory(to: sockaddr.self) guard let unsafePtr = sockaddrPtr.baseAddress else { return } guard getnameinfo(unsafePtr, socklen_t(data.count), &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 else { return } } let ipAddress = String(cString:hostname) print(ipAddress) }How can i get the ipAddress when a NWBrowser connects with a NWListener and the NWListener responds back to the NWBrowser?Listener/Advertiser:var listener: NWListener? listener?.newConnectionHandler = { (nwConnection) in // new connection and/or data came in from Browser, what is its ipAddress? }Browser:var browser: NWBrowser? var connection: NWConnection? browser?.browseResultsChangedHandler = { (results, changes) in for result in results { // Advertiser endpoint found, what is its ipAdress? print(result.endpoint.debugDescription) } } connection?.receiveMessage { (content, _, _, error) in if let messageData = content { // received data from Advertiser, what is its ipAddress? } }
Posted
by lsamaria.
Last updated
.
Post marked as solved
8 Replies
6.2k Views
I'm a complete noob to networking but I need local discovery to share ARKit Worldmaps. The MCSession peer limit of 8 users isn't enough for me because I need unlimited peer connections (all peer to peer). I decided to use Bonjour and got a discovery system setup. Where I got stumped is actually connecting user to user and sending data back and forth. To do that I need to create sockets for inputstreams and outputstreams and somehow add to the them to the NetService Delegate method:func netService(_ sender: NetService, didAcceptConnectionWith inputStream: InputStream, outputStream stream: OutputStream) { }All I know is I have to use CocoaAsyncSocket to make life easier but I'm still lost on what to do in the didAcceptConnectionWith and this is turning into a daunting task. In my reearch I came across the NWConnection class. From my understanding it's supposed to replace Bonjour but I don't have much reference on how to use it. For eg I followed this tutorial, this tutorial, and ths code from Eskimo but that's all that I could find.There are 2 problems with NWConnection the first being unlike Bonjour which has delegate methods to find all local peers and to remove them:// find func netServiceBrowser(_ browser: NetServiceBrowser, didFind service: NetService, moreComing: Bool) { } // remove func netServiceBrowser(_ browser: NetServiceBrowser, didRemove service: NetService, moreComing: Bool) { }I cannot see how to do this with NWConnection. I did find this question where the op was trying to use the Bonjour service to discover address and then hook those into NWConnection as an endpoint but eskimo said not to do it that way. It does seem like a good idea to get around this issue I'm having.The second problem is that I need the users of my app to discover all the other users around them. With the above Bonjour delgate method that is taken care. But with NWConnection it seems you have to set the endpoint in advance:let connection = NWConnection(host: "example.com", port: 80, using: .tcp) connection.stateUpdateHandler = self.stateDidChange(to:)That's fine if you're connecting to a webpage but I don't see how one http endpoint correlates to local discovery for the users using my app.Here is my Bonjour code below and how i use it in my ARKit VCARKitController:import Network class ARKitController: UIViewController { lazy var sceneView: ARSCNView = { let sceneView = ARSCNView() sceneView.translatesAutoresizingMaskIntoConstraints = false sceneView.delegate = self return sceneView }() let configuration = ARWorldTrackingConfiguration() var connection: NWConnection? var netBrowser: NetBrowser! var arrOfIPAddrresses = [String]() func overrideViewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) netBrowser = NetBrowser() netBrowser.delegate = self netBrowser.startSearch() sceneView.session.run(configuration, options: []) } func overrideViewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) netBrowser.stopDiscovery() netBrowser = nil sceneView.session.pause() } func saveIP(address: String) { arrOfIPAddresses.append(address) } func remove(_ service: NetService) { // get the ipaddress from the service then remove it from the array } func sendDataUsing(_ sockAddr: UnsafeBufferPointer ) { // get host and port from socket address ... let hostUDP = NEWEndpoint.Host ... let portUDP = NWEndpoint.Post ... connectToUDP(hostUDP, portUDP) } } //MARK:- NWConnection Methods extension ARKitController { func connectToUDP(_ hostUDP: NWEndpoint.Host, _ portUDP: NWEndpoint.Port) { self.connection = NWConnection(host: hostUDP, port: portUDP, using: .udp) self.connection?.stateUpdateHandler = { (newState) in switch (newState) { case .ready: print("State: Ready\n") self.sendThisUsersWorldMap() self.receiveOtherUsersWorldMap() case .setup: print("State: Setup\n") case .cancelled: print("State: Cancelled\n") case .preparing: print("State: Preparing\n") default: print("ERROR! State not defined!\n") } } self.connection?.start(queue: .global()) } func sendThisUsersWorldMap() { sceneView.session.getCurrentWorldMap { (worldMap, error) in guard let map = worldMap else { print("Error: \(error!.localizedDescription)") return } guard let data = try? NSKeyedArchiver.archivedData(withRootObject: map, requiringSecureCoding: true) else { print("can't encode map") return } self.connection?.send(content: data, completion: NWConnection.SendCompletion.contentProcessed(({ (NWError) in if (NWError == nil) { print("Data was sent to UDP") } else { print("ERROR! Error when data (Type: Data) sending. NWError: \n \(NWError!)") } }))) } } func receiveOtherUsersWorldMap() { self.connection?.receiveMessage { (data, context, isComplete, error) in if (isComplete) { print("Receive is complete") if let data = data { self.mergeOtherUsersWorldMap(data) } } } } }Bonjour:protocol NetBrowserDelegate: class { func saveIP(address: String) func remove(_ service: NetService) func sendDataUsing(_ sockAddr: UnsafeBufferPointer) } class NetBrowser: NSObject, NetServiceBrowserDelegate, NetServiceDelegate { var browser: NetServiceBrowser? var services = [NetService]() let domain = "local." let name = "_http._tcp" weak var delegate: NetBrowserDelegate? func startSearch() { services.removeAll() browser = NetServiceBrowser() browser?.includesPeerToPeer = true browser?.delegate = self browser?.stop() browser?.schedule(in: RunLoop.current, forMode: .default) browser?.searchForServices(ofType: self.name, inDomain: self.domain) RunLoop.current.run() } func stopDiscovery() { browser?.stop() browser?.delegate = nil browser = nil } } // MARK:- Delegate Methods extension NetBrowser { func netServiceBrowser(_ browser: NetServiceBrowser, didFind service: NetService, moreComing: Bool) { print("found service") services.append(service) service.delegate = self service.publish(options: NetService.Options.listenForConnections) service.resolve(withTimeout: 5.0) } func netServiceBrowser(_ browser: NetServiceBrowser, didRemove service: NetService, moreComing: Bool) { if let index = self.services.firstIndex(of:service) { self.services.remove(at:index) print("removing a service") delegate?.remove(service) } } func netServiceDidResolveAddress(_ sender: NetService) { print("netServiceDidResolveAddress get called with \(sender).") var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST)) guard let data = sender.addresses?.first else { print("guard let data failed") return } data.withUnsafeBytes { (pointer: UnsafeRawBufferPointer) -> Void in let sockaddrPtr = pointer.bindMemory(to: sockaddr.self) guard let unsafePtr = sockaddrPtr.baseAddress else { return } guard getnameinfo(unsafePtr, socklen_t(data.count), &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 else { return } delegate?.sendDataUsing(sockaddrPtr) } let ipAddress = String(cString:hostname) print(ipAddress) delegate?.saveIP(address: ipAddress) } func netService(_ sender: NetService, didNotResolve errorDict: [String : NSNumber]) { print("netServiceDidNotResolve:\(sender)"); } } extension NetBrowser { func netService(_ sender: NetService, didAcceptConnectionWith inputStream: InputStream, outputStream stream: OutputStream) { print("netServiceDidAcceptConnection:\(sender)"); } func netServiceWillPublish(_ sender: NetService) { print("netServiceWillPublish:\(sender)"); //This method is called } func netServiceDidPublish(_ sender: NetService) { print("netServiceDidPublish:\(sender)"); } func netService(_ sender: NetService, didNotPublish errorDict: [String : NSNumber]) { //debugPrint(errorDict) print("didNotPublish:\(sender)") } }
Posted
by lsamaria.
Last updated
.
Post not yet marked as solved
0 Replies
339 Views
I want multiple users to share their experience with other users and I decided to use Bonjour for discovery because there isn't a peer limit. There is no host or guest (peer to peer), discovery is automatic (no user interaction). Once one user is nearby with the app open it will automatically send their world map to anyone else who is nearby with the app open. The other person's worldmap will also get sent to that first user in return. If there are 50 users nearby all 50 of them will have a copy of each other's worldmap. Think of it like a bunch of users all sharing worldmaps with each other.My app is not a multiplayer game or anything with "action". It's more like each user has a Pokemon character and once their worldmap is shared every user in that vicinity will all see each other's Pokemon character. 1. When sharing a worldmap are only the anchors shared (each Pokemon object, node, and its worldPosition) or is the entire scene shared with the accompanying anchors? For eg there are 50 users in a mall food court and one user puts their Pokemon node on a table and shares their world scnen. Will each other user get a copy of the entire food court area or just the Pokemon object, its node, and its anchor?2. How much does data does each worldmap take up and what determines the size of the data? For eg if I'm in my kitchen that's one thing but if I'm at the beach that's another. Once I share my worldmap would that be considered the size of a small compressed photo or large uncompressed video. The problem with not knowing this is in my app if each worldmap is 1 gigabyte and 20 users all have each other's worldmaps then they would all have 20 gigabytes of worldmaps on their app.3. Is there any specific reason MCSession and ARKit only supports 8 peers in a shared experience? I know it's built on top of Bonjour but Bonjour has no limit so there has to be some reason MCSession does.
Posted
by lsamaria.
Last updated
.
Post marked as solved
2 Replies
599 Views
I came across this post. The op asked when sharing an ARKit WorldMap in a Multipeer session is there a limit. MCSession does have an 8 person limit:Sessions currently support up to 8 peers, including the local peerEskimo suggested to the op to use "NSNetService" and its "includePeerToPeer" flag to go beyond that limit.I want multiple users to share their experience with other users and I decided to usee Bonjour for discovery because there isn't a peer limit. There is no host or guest, discovery is automatic (no user interaction). Once one user who is nearby with the app open it will automatically send their world map to anyone else who is nearby with the app open. The other person's worldmap will also get sent to that first user in return. If there are 50 users nearby all 50 of them will have a copy of each other's worldmap. Think of it like a bunch of users all sharing worldmapos with each other.My app is not a multiplayer game or anything with "action". It's more like each user has a Pokemon character and once their worldmap is shared every user in that vicinity will all see each other's Pokemon character. This isn't a host/guest type setup, it;s 100% peer to peer. Every user auto connects to every other user. Once the connection is made it sends the user's worldmap (if no connection create a connection and send worldmap)When Eskimo posted the anwer he didn't specify if there would be any issues with sharing a worldmap beyond 8 people. I have 4 questions:1. In the worldmap docs it says Use the networking technology of your choice to send the resulting data to another device. The MultipeerConnectivity are example projects and it doesn't say anything about not using Bonjour or limiting the amount of users. In the application I described above (no action) should there be a limit to the number of users who can automatically share worldmaps and if so what should that limit be?2. When sharing a worldmap are only the anchors shared (each Pokemon node and its worldPosition) or is the entire scene shared? For eg there are 50 users in a mall food court and one user puts their Pokemon node on a table will each of get a copy of the entire food court area or just the anchor that the Pokemon node is anchored to (and the Pokemon also)?3. How much does data does each worldmap take up and what determines the size of the data? For eg if I'm in my kitchen that's one thing but if I'm at the beach that's another. Once I share my worldmap would that be considered the size of a small compressed photo or large uncompressed video. The problem with not knowing this is in my app if each worldmap is 1 gigabyte and 20 users all have each other's worldmaps then they would all have 20 gigabytes of worldmaps on their app.4. Is there any specific reason MCSession and ARKit only supports 8 peers in a shared experience? I know it's built on top of Bonjour but Bonjour has no limit so there has to be some reason MCSession does.Thanks,Lance
Posted
by lsamaria.
Last updated
.