Understanding NSNetService and peer-to-peer streaming


Graham Cox
 

Hi all,

I’m trying to add a peer-to-peer communication feature to a game I’m developing.

So far it’s half working, which given the paucity of documentation, I’m actually quite proud of…

Because it’s peer-to-peer, any app can act as both client and server, so getting straight which bit is doing what is quite hard. But for the sake of discussion, I’ll call the service that initiates a connection the server, and the app that receives it the client.

I’m using NSNetService and NSNetServiceBrowser to act as an interface to Bonjour to discover other copies of my game on the network. This part works well - I can advertise myself as a service, and I can receive notifications of other identical services. The ’server' NSNetService receives a -netService:didAcceptConnectionWithInputStream:outputStream:, and schedules those streams in the main run loop and opens them. The ‘server’ also implements -netServiceBrowser:didFindService:moreComing: to wrap the NSNetService representing the client and its streams in a ‘remote player’ object for that client.

I can use the ‘remote player’ object to send data to the client via the streams associated with its NSNetService.

The client receives the data OK, as the stream delegate’s -stream:handleEvent:

So far, so good. But now I need to return data to the ‘server’ peer. The problem is, I don’t know which stream I need to use to do that. When the ‘server’ accepts a connection, it is handed two streams, which are presumably the ones to use. The problem I have is that these streams are just naked streams - there is no associated information that will tell me which ‘client’ they are connected to. At the moment I just schedule these streams in a run loop and open them, and set my general ‘server’ to be their delegate, which is how I am able to receive the data. But given that there will be a pair of these for every connected server, I don’t know which stream to use to return data to a specific server.

I have the idea that what I should do is to wrap the stream pair in another object so I can keep them separate, but that still leaves the problem of identifying that object as being a particular server. I can send that identifying information over the stream the first time I use it, and the ‘client’ can then add that information to the server object, but that seems like a kludge - it is relying on my private protocol to pass information that should already be known to the basic NSNetService infrastructure.

If you’ve followed this, kudos to you. It’s hard to keep straight who is the client and who is the server, to be honest. But even with that muddle, I feel I’m missing something.

If anyone has done something like this successfully and can offer any insights, I’d be most grateful.

—Graham

Join cocoa@apple-dev.groups.io to automatically receive all group messages.