iphone : Making Connections with GameKit and Bonjour - Creating a Mac Client for an iPhone Bonjour Service

1/28/2013 6:45:02 PM

There’s nothing intrinsically specific about the roles and the platforms chosen. A Mac could just as easily provide a service and an iPhone its client. Since an iPhone/iPhone client/server pair is best implemented with GameKit, this recipe demonstrates how to cross platforms and use Bonjour for mobile desktop communication.

Recipe 1 limits itself to the methods specific to the Bonjour communications. 

Figure 1. The Macintosh Bonjour client shown here was used with the iPhone Bonjour server .

A Bonjour client begins by browsing for services. Since the service on the iPhone is provided by Bonjour and not GameKit, its name is known in advance of compilation and testing, namely @"PictureThrow". 

The NSNetServiceBrowser class provides the ability to find a given service type. Its delegate receives a netServiceBrowser:didFindService:moreComing: callback when a match appears. The delegate can then stop the browser and begin to resolve the service.

Connections can close for three reasons. First, the data transferred over successfully and the host service closed it deliberately. Second, the user may have denied the connection. Third, the application might have lost its connection by quitting or moving out of range. The same connectionDidClose: callback must handle all three cases.

In this recipe, this callback sets a Boolean value for success. When the connection closes, the connectionDidClose: callback method checks that value. If the data transfer did not succeed, the user is told that the connection was denied or lost.

Recipe 1. Providing a Bonjour Client
// Receive the image and update the interface
- (void) connection:(TCPConnection*)connection
    // Upon receiving the image, update the image view
    success = YES;
    self.imageData = data;
    NSImage *image = [self imageFromData:data];
    [imageView setImage:image];

    // You can now save or catch another image
    [saveItem setEnabled:YES];
    [button setEnabled:YES];
    [progress stopAnimation:nil];
    // Update status
    ANNOUNCE(@"Recived JPEG image (%d bytes).\n\nUse File > Save\
       to save the received image to disk.", data.length);

// If there was no success, apologize and restore UI
- (void) connectionDidClose:(TCPConnection*)connection
    // Failed or completed connection. Check for success.
    if (success) return;
    ANNOUNCE(@"Connection denied or lost. Sorry.");

    // For a failed connection, prepare for the next catch
    self.imageData = nil;
    [saveItem setEnabled:NO];
    [imageView setImage:nil];
    [button setEnabled:YES];
    [progress stopAnimation:nil];

// Upon resolving address, create a connection to that address
// and request data
- (void)netServiceDidResolveAddress:(NSNetService *)netService
    // Gather the addresses and attempt to create a connection
    NSArray* addresses = [netService addresses];
    if (addresses && [addresses count]) {
        struct sockaddr* address = (struct sockaddr*)[[addresses
            objectAtIndex:0] bytes];
        TCPConnection *connection = [[TCPConnection alloc]
        [connection setDelegate:self];
        [statusText setTitleWithMnemonic:@"Requesting data..."];
        [progress startAnimation:nil];
        [netService release];
        [connection receiveData];

// Complain when resolve fails
- (void)netService:(NSNetService *)sender didNotResolve:
    (NSDictionary *)errorDict {
    [statusText setTitleWithMnemonic:
        @"Error resolving service. Sorry."];
// Upon finding a service, stop the browser and resolve
- (void)netServiceBrowser:(NSNetServiceBrowser *)netServiceBrowser
    didFindService:(NSNetService *)netService
    [self.browser stop];
    self.browser = nil;
    [statusText setTitleWithMnemonic:@"Resolving service."];
    [[netService retain] setDelegate:self];
    [netService resolveWithTimeout:0.0f];

// Begin a catch request, start the service browser, and update UI
- (IBAction) catchPlease: (id) sender
    success = NO;
    [self.statusText setTitleWithMnemonic:@"Scanning for service"];

    // Create a new service browser
    self.browser = [[[NSNetServiceBrowser alloc] init] autorelease];
    [self.browser setDelegate:self];
    NSString *type = [TCPConnection
    [self.browser searchForServicesOfType:type inDomain:@"local"];

    // Disable and reset the interactive features while waiting
    [button setEnabled:NO];
    self.imageData = nil;
    [saveItem setEnabled:NO];
    [imageView setImage:nil];

Most View
SilverStone Heligon HE02 CPU Cooler – An Efficient Silence From A Giant (Part 3)
Nvidia GeForce GTX Titan 6GB - Gaming Supercomputer Graphics Card
The Audio Technica RTH-WS55 - Fits Snugly On Your Head
Be Quiet! Shadow Rock Top Flow SR1
Samsung Galaxy NotePro 12.2 (Part 1)
Windows 7 : Installing and Removing Hardware (part 4) - Not-So-Hot-Pluggable Devices - Primary and extended partitions, Partitioning and formatting the disk
Setting For Phones Using Windows Phone 8
Intel NUC Mini-PC – “The Next Unit of Computing”
Windows 8 Architecture from a Developer’s Point of View : Windows 8 Development Architecture
Fujifilm XF1 - A Slim, Retro-Styled Camera With Excellent Image Quality
Top 10
The Mercedes-Benz A45 AMG 4 Matic – The Power Of Four (Part 2)
The Mercedes-Benz A45 AMG 4 Matic – The Power Of Four (Part 1)
The BMW 435i Coupé – One Small Leap (Part 2)
The BMW 435i Coupé – One Small Leap (Part 1)
Sharepoint 2013 : List and library essentials - Sorting and filtering lists
Sharepoint 2013 : List and library essentials - Using list and column validation rules
Sharepoint 2013 : List and library essentials - Editing and deleting list columns
Sharepoint 2013 : List and library essentials - Creating list columns
Sharepoint 2013 : List and library essentials - Adding and editing list items
The Porsche 911 Targa – Wind Blast From The Past