0

I have been studying the bonjour/NSStream sample code from lecture #17 of Stanford's CS193p course (iOS programming) on iTunes U from the winter of 2010. The example code is available here.

In a nut shell, the sample code creates a socket and binds to port 0 so that it will be given a free port. It then publishes a service with that port using NSNetService (bonjour). An NSNetServiceBrowser is also started when the app starts up. Available services are placed in a UITableView. When a cell is selected, the corresponding service is resolved, an NSOutputStream is created, and data can be sent.

This is a naive implementation because connections are rejected if a connection already exists. My question is, what is the proper way to handle multiple connections? Once multiple clients are connected to the server, how does the server distinguish between them? i.e. How can data be sent specifically to one client and not the others?

- (void) _acceptConnection:(int)fd
{
    int     junk;

// If we already have a connection, reject this new one.  This is one of the 
// big simplifying assumptions in this code.  A real server should handle 
// multiple simultaneous connections.

    if ( self.isReceiving ) {
        junk = close(fd);
        assert(junk == 0);
    } else {
        [self _startReceive:fd];
    }
}


// Called by CFSocket when someone connects to our listening socket.  
// This implementation just bounces the request up to Objective-C.
static void AcceptCallback(CFSocketRef s, 
                           CFSocketCallBackType type, 
                           CFDataRef address, 
                           const void *data, 
                           void *info)

{
    ReceiveServer *  obj;

    assert(type == kCFSocketAcceptCallBack);

    assert(data != NULL);

    obj = (ReceiveServer *) info;
    assert(obj != nil);

    assert(s == obj->_listeningSocket);


    [obj _acceptConnection:*(int *)data];
}
RyanM
  • 4,474
  • 4
  • 37
  • 44
  • 1
    Before answering this question: Do you know how to write a multi-client server with either plain BSD sockets on a Mac (or linux, Windows, or other desktop/server system)? If not, you should probably learn that first, or switch to a higher-level framework that takes care of that stuff so you don't have to learn it. (CFSocket is a sort of mid-level framework that adds a lot on top of sockets, but not enough to just plug in your server logic and have a server.) – abarnert May 11 '12 at 00:22
  • Hey abarnert. Thanks for your response. I don't know how to write a multi-client server with plain BSD sockets, but I definitely want to learn. Can you suggest some good resources or sample code? I have looked at [Beej's Guide to Network Programming](http://beej.us/guide/bgnet/output/print/bgnet_USLetter.pdf) a little bit. Would an understanding of that get me there? P.s. is this something that I would learn in a basic networking class? – RyanM May 11 '12 at 03:56
  • Just started reading Addison Wesley: Unix Network Programming :D – RyanM May 12 '12 at 09:44

1 Answers1

1

I'm not specifically familiar with that course or sample code, but: separate out the code for handling a connection into a different class from the code which accepts new connections. So, in the posted code, you'd move the -startReceive: method and everything which it calls to another class.

Then, each time a connection is accepted, create an instance of that other class. That instance will be responsible for processing all of the communication on that connection. It will be given the information about the connection (mainly the fd) during initialization. The main controller object of the server could hold those instances in an array.

Where things go from here will depend on what your server actually does. At the very least, your connection objects will need to inform the main controller object when they are closed, so the main controller can remove them from the array. You can use notifications or the delegate pattern for that.

Ken Thomases
  • 88,520
  • 7
  • 116
  • 154