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];
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