Slide 1

Slide 1 text

App-to-App Communication with Bonjour Kevin Conner @connerk

Slide 2

Slide 2 text

Goal iOS and Mac apps finding each other connecting over wifi sharing data no C

Slide 3

Slide 3 text

Bonjour • Deals with sockets • Selects ports for you • Listens for clients / Connects to servers • Sends and receives data

Slide 4

Slide 4 text

Not! • Deals with sockets • Selects ports for you • Listens for clients / Connects to servers • Sends and receives data

Slide 5

Slide 5 text

Bonjour • Publish a service you’re already running • Find published services • Resolve an address and a port

Slide 6

Slide 6 text

Bonjour • NSNetService • NSNetServiceBrowser

Slide 7

Slide 7 text

Publish a service // TODO Get a socket to an open port // TODO Start listening for incoming connections // Publish the service NSNetService *netService = [[NSNetService alloc] initWithDomain:@"" type:@"_myservice._tcp" name:@"" port:port]; netService.delegate = self; [netService publish];

Slide 8

Slide 8 text

Find published services NSNetServiceBrowser *browser = [[NSNetServiceBrowser alloc] init]; [browser setDelegate:self]; [browser searchForServicesOfType:@"_myservice._tcp" inDomain:@""]; - (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing; - (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didRemoveService:(NSNetService *)aNetService moreComing:(BOOL)moreComing; - (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didNotSearch:(NSDictionary *)errorDict;

Slide 9

Slide 9 text

Resolve address & port [netService setDelegate:self]; [netService resolveWithTimeout:5]; - (void)netServiceDidResolveAddress:(NSNetService *)sender { NSInputStream *is = nil; NSOutputStream *os = nil; [sender getInputStream:&is outputStream:&os]; // TODO open the streams } - (void)netService:(NSNetService *)sender didNotResolve: (NSDictionary *)errorDict;

Slide 10

Slide 10 text

Goal iOS and Mac apps finding each other connecting over wifi sharing data no C

Slide 11

Slide 11 text

// TODO Get a socket to an open port // TODO Start listening for incoming connections

Slide 12

Slide 12 text

Listening on a socket: NSSocketPort // Get a vacant socket port and start listening NSSocketPort *socketPort = [[NSSocketPort alloc] initWithTCPPort:0];

Slide 13

Slide 13 text

Finding the port // Inspect the NSSocketPort to find the actual port number struct sockaddr *addr = (struct sockaddr *)[[socketPort address] bytes]; int port; if (addr->sa_family == AF_INET) { port = ntohs(((struct sockaddr_in *)addr)->sin_port); } else if (addr->sa_family == AF_INET6) { port = ntohs(((struct sockaddr_in6 *)addr)->sin6_port); }

Slide 14

Slide 14 text

Almost no C

Slide 15

Slide 15 text

Accepting connections: NSFileHandle // Get a file handle to the socket NSFileHandle *fileHandle = [[NSFileHandle alloc] initWithFileDescriptor:[socketPort socket] closeOnDealloc:YES]; // Accept connections [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(connectionAccepted:) name:NSFileHandleConnectionAcceptedNotification object:fileHandle]; [fileHandle acceptConnectionInBackgroundAndNotify];

Slide 16

Slide 16 text

Accepting connections: NSFileHandle - (void)connectionAccepted:(NSNotification *)notification { NSDictionary *userInfo = [notification userInfo]; NSFileHandle *clientSocketHandle = [userInfo objectForKey:NSFileHandleNotificationFileHandleItem]; NSNumber *errorNo = [userInfo objectForKey:@"NSFileHandleError"]; if (errorNo) { /* Handle it */ } // Keep listening for more connections [self.fileHandle acceptConnectionInBackgroundAndNotify]; if (clientSocketHandle) { // Save the client connection and start reading data [self.clientSocketHandles addObject:clientSocketHandle]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(clientSocketReadCompletion:) name:NSFileHandleReadCompletionNotification object:clientSocketHandle]; [clientSocketHandle readInBackgroundAndNotify]; } }

Slide 17

Slide 17 text

Receiving data: NSFileHandle - (void)clientSocketReadCompletion:(NSNotification *)notification { NSDictionary *userInfo = [notification userInfo]; NSNumber *errorNo = [userInfo objectForKey:@"NSFileHandleError"]; if (errorNo) { /* Handle it */ } NSData *data = [userInfo objectForKey:NSFileHandleNotificationDataItem]; // TODO accumulate data, parse your protocol // Read more data when it becomes available [self.fileHandle readInBackgroundAndNotify]; }

Slide 18

Slide 18 text

I know the pieces fit… • NSNetService & NSNetServiceBrowser • NSSocketPort & NSFileHandle • NSInputStream & NSOutputStream • Custom code for your app’s protocol

Slide 19

Slide 19 text

KCSession • Server: Sets up socket, port, Bonjour, accepts connections • NSNetServiceBrowser is up to you • Client: Connects to a NSNetService • Sends and receives Cocoa objects

Slide 20

Slide 20 text

degreesgame.com github.com/kconner/KCSession Kevin Conner @connerk