Tutorial: Networking and Bonjour on iPhone

By
On May 20, 2009

Guest author Peter Bakhyryev (email) is co-founder of ByteClub, a software development company that provides online multiplayer technologies and services to iPhone application developers. He is located in Brooklyn, New York.

In this tutorial, we are going to explore a simple chat application for the iPhone. It allows you to host your own chat room and advertise it on your local Wi-Fi network (in which case your app acts as a chat “server”) or find and join chat rooms hosted by other people on your network (acting as a chat “client”). Both announcement and discovery of chat rooms are implemented using Apple’s Bonjour protocol. The goal of this app is to show you how to use various networking-related frameworks available in the iPhone SDK version 2.x. The UI is minimal (consisting of only 3 simple views) – just enough to be able to play with the core functionality of the app without having to deal with complex UIKit code.

Source code for the tutorial

The app is called “Chatty.” Its source code is located here – it is being released under the MIT license, which means that you are free to modify and reuse it at will. Before we begin with the tutorial, download and open the zip file, and double-click Chatty.xcodeproj.

In order to see how Chatty works, you’ll need to run at least 2 instances of the app on your local network. The easiest way to get there is to use iPhone Simulator on your computer in conjunction with an iPhone or iPod Touch that is connected to the same Wi-Fi network.

Instead of going through the process of constructing this app step-by-step, we are going to examine various parts of completed source code. You don’t need to read the whole article – feel free to look through whatever sections interest you the most. Majority of the source code is pretty well commented, and the purpose of the tutorial is to cover “what to do” and “why do it this way”, as opposed to “how to do it” – that’s what the comments in the code are for.

To keep things interesting, at the very end of this article I’ll present you with a little puzzle that has to do with figuring out how to improve the way messages are sent over the network.

Lets begin with a quick overview of the basics.

Overview: Networking frameworks

The lowest level (closest to the metal, so to speak) networking framework available in the iPhone SDK is the BSD socket library. Most developers probably won’t need something this powerful. Many common tasks (sending and receiving data, connecting to HTTP servers etc) require quite a bit of coding in C if implemented using straight-up BSD sockets. Apple decided to hide some of the complexity by introducing another, higher level, framework called CFNetwork. Even though we are still in the C (as opposed to Objective-C) territory here, it has some clear advantages, with run-loop integration being one of them (more on this later). As a rule of thumb, anything that start with “CF”, which stands for “Core Foundation”, is in C. Objective-C and CocoaTouch comes into play with classes whose names start with “NS” (Next Step). A lot of components have both “CF” and “NS” implementations: CFReadStream vs NSInputStream, CFNetService vs NSNetService. Typically, “NS” versions are of higher level and easier to use, but that often means that the corresponding “CF” version is more flexible and feature-rich.

Overview: Sockets vs Streams

Socket represents a unique communication endpoint on the network. When your app needs to exchange data with another app, it creates a socket and uses it to connect to the other app’s socket. You can both send and receive data through the same socket. Each socket has an IP address and a port number (between 1 and 65535) associated with it. IP address uniquely identifies each computer on a given network and port number uniquely identifies a network socket on that computer.

Stream is a one-way channel through which data is transmitted serially. There are 2 types of streams: the ones into which you can write data, and the ones from which you can read. By itself, stream is just a buffer that temporarily holds data before or after its transmission. In order to actually deliver data somewhere meaningful, streams need to be tied to something (like a file, a memory location etc). In this tutorial, we’ll use streams that are paired up with sockets to allow our app to send data over network.

Overview: Bonjour

Bonjour is a protocol that allows devices or applications to find each other on the network. More precisely, it provides a way for an application to tell others what IP address and port they can connect to in order to communicate with it. In Bonjour terminology, such announcement is called publishing a service. Other apps can then look for services by browsing. Once an app finds a service that it would like to talk to, it resolves the service to find out what IP address and port number it needs to establish a socket connection to.

In the SDK, Bonjour can be used via NSNetServices and CFNetServices APIs.

Overview: Synchronous vs Asynchronous operations

Majority of interactions on a network involve waiting for something to happen: socket connections take time to get established; waiting for your peer to send you some data; waiting for your data to be delivered to the other side, and so on and so forth. If your app has only one thread of execution, you can’t really afford sitting inside of a fictional waitForDataToArrive() method call, because that means that all other important things, such as handling of various events, processing UI-related tasks etc, will most likely stall and your whole app will appear unresponsive and slow.

Here, you have 2 solutions: launch more threads or utilize the one thread in a more efficient manner. In this particular example, we’ll go with the latter, only because it allows us to use a clever piece of code called a run loop and learn to do things in an asynchronous (or non-blocking) manner, without wasting valuable resources, like extra threads and such. In some cases, you have to use more than one thread to accomplish something – but on a small device such as the iPhone, it’s better to keep your resource usage to a minimum.

Overview: Run loops

A run loop is literally a loop that runs in a thread – think of a more complex version of while(true){ processNextEvent(); }. Its job is to process events that arrive from elsewhere. Events represent things that happen in an app: “User touched screen”, “Network connection established”, “Timer has fired”, “Device’s orientation has changed” etc. You write the code to handle some of those and the OS takes care of everything else, like scheduling, receiving and sending them. You can also specify which additional sources of events, like sockets or streams, the run loop should process. This way, one thread is able to process many different things in an efficient manner, without wasting time on waiting for something specific to happen.

Of course, there is more that goes on behind the scenes and you can always find out the details by digging into the documentation that comes with the SDK.

Structure of the app

But enough with the theory, it’s time to get our hands dirty. Lets open up Chatty and see what it is made of.

All classes that comprise the app are separated into 3 categories (layers): “UI”, “Business Logic” and “Networking” (Each category is represented by a “File group” in the XCode project). We use delegates and protocols in order to wire all of the pieces together.

Business Logic deals with 2 different implementations of chat rooms: local and remote. Whenever we want to host our own chat, we’ll create a local chat room, which will automatically launch a server and announce it via Bonjour. Remote chat room, on the other hand, allows us to connect to another instance of the app on the same network and join the chat room hosted there.

The 3 Networking classes encapsulate everything that is needed to make Chatty work over a network.

Server class:

  • Create a server
  • Announce the server via Bonjour

Connection class:

  • Resolve Bonjour services
  • Establish connections to other servers
  • Exchange data via socket streams

ServerBrowser class:

  • Browse for other servers via Bonjour

Control flow in the app

Since we have quite a few classes interacting with each other in various ways, it might be helpful to step back and look at the “big picture” before we dive into the details. The diagram below shows how various layers of our application work with one another:

All user interactions get processed in the UI layer. Each time user wants to send a chat message (broadcastChatMessage:fromUser:), Business Logic layer decides whether to simply forward the message to the server (in case of the Remote chat room) or send a copy of the message to each client that’s connected (for Local chat room). Whenever a network message is received via a connection, Business Logic layer is notified, and, in addition to distributing a copy of the chat message to all connected clients (for Local chat room), it in turn passes the message on to the UI, which displays it to the user.

Socket+Streams+Buffers=Connection

The lowest level networking class that we deal with is called Connection. It encapsulates several things necessary for the inter-app communication:

  • 2 socket streams, one for writing and one for reading
  • 2 data buffers, one for each socket stream
  • various control flags and values

Here is how it all works together:

Lets go through various parts of that diagram. As I mentioned earlier, implementing network communication using sockets alone requires quite a bit of coding. Some of that work has already been done for us and we shall reuse as much of it as possible. That’s why we are using streams to help us along. Since streams are one-way channels, we will require 2 of those for each socket, in order to be able to both read and write data. We initialize the streams in the connect and setupSocketStreams methods of the Connection class. In Chatty, a socket can be created in 2 ways:

1. By connecting to another host by specifying its IP address (or host name) and port, or
2. By accepting a connection request from another app, in which case the socket is created automatically by the OS and is passed to us in the form of a native socket handle.

Regardless of how the connection is actually made, we use same exact code to initialize our streams, which is why setupSocketStreams method ends up being called from connect in each branch of the if-else tree there.

Next up: What are data buffers and why do we need those? Lets use an analogy (popular with some politicians) to understand how asynchronous data exchange works: think of a network connection as being a tube. You stuff bytes in one end, and, after spending some time traveling, they come out on the other side. This tube doesn’t have infinite capacity – it can hold only so much stuff at once. And the tube can’t deliver data instantaneously, either. This means that you can send up to certain number of bytes per each second through that connection. What if your application needs to send a message that’s bigger than what the connection can take in at once? What are you going to do with the data that didn’t fit into the tube? That’s right, you will temporarily hold it in the outgoing data buffer. The write stream will tell you when the pipe frees up and is able to take more bytes – that’s when the kCFStreamEventCanAcceptBytes event gets sent and we can check to see if there is any more data that needs to be transmitted (see methods writeStreamHandleEvent: and writeOutgoingBufferToStream).

When bytes arrive to us from another app, we also temporarily store them in a buffer. In order to understand why, lets take a look at how the messages are actually sent and received.

Format of the network messages

Lets define the rules of how different instances of Chatty actually communicate with one another. Some key assumptions:

1. Whenever a user wishes to send a message, we store the text of the message and the user’s name in a new instance of NSDictionary. We call this a chat message.
2. We also have a notion of a network message, which is a sequence of bytes that encode exactly one chat message.
3. We need an ability to send and receive network messages separately from one another.

Why do we need to differentiate between a “chat message” and a “network message”, you ask? That’s because most networking frameworks deal not with objects (like NSDictionary, NSNumber, NSString etc), but with sequences of bytes. Before an object can be sent over the wire, it has to be converted into an array of bytes. Luckily, Cocoa provides us with a pair of classes, called NSKeyedArchiver and NSKeyedUnarchiver, that make this task easy. To see how these classes can be used, take a look at the sendNetworkPacket: and readFromStreamIntoIncomingBuffer methods in Connection.m.

That takes care of assumptions number 1 and 2. What about the 3rd one? Depending upon how much user had to say in their chat message, length of the corresponding network message can vary. When we start sending our byte array via the write stream, how does the other side know how many bytes it is supposed to read before it can actually decode that network message into a chat message and display it to the user? In other words, how do we separate network messages from one another? In general, there are 3 ways to do that:

1. Make all messages have the same length. All we need to do in this case is read same exact number of bytes for each message.
2. Append a marker to each message that will indicate where the message ends, therefore signaling the reader when to stop reading.
3. Before transmitting the actual message, send some kind of a header that includes enough information to deduce how long the actual message is. The other side will then read this header, which will tell it how many more bytes it needs to extract before it gets to the end of the message.

Each of these approaches has advantages and disadvantages. I’ll let you think through them on your own. For Chatty, we are using method number 3, which utilizes message headers. Here is what one network message will look like:

In this case each message consists of 2 parts: header and body. Header has a constant length (4 bytes = 1 integer) and it tells us how long the body is. It’s fairly easy to send such message:

1. Convert NSDictionary object into a byte array and measure its length.
2. Write the integer (4 bytes) that represents the length of our byte array to the stream.
3. Write the actual byte array to the stream.

Reading of the message is a bit more complicated:

1. Read first 4 bytes and interpret those as an integer. Call that variable packetBodySize.
2. Read packetBodySize number of bytes. Stop when enough data has been received.
3. Turn received sequence of bytes into an NSDictionary object.

The complexity of the reading routine comes from the fact that the underlying networking layer might not deliver all of the bytes that comprise one network message in one shot, in which case it will be transmitted in chunks, spoon-feeding us a few bytes at a time (in theory). In that situation, we have to read as much as we can and return again later, when the stream signals us that more bytes have arrived. That’s why you see those ‘if’ statements that check how much data we have actually received so far. On the other hand, it is also possible that more than one network message will be delivered to us at once. That’s the reason why a big while( YES ) loop is dominating our readFromStreamIntoIncomingBuffer method. This also explains the need to have a separate buffer for incoming data: in case an incomplete message arrives, we need to temporarily store it somewhere until the rest is received and the puzzle can be completed, so to speak.

Creating a server

In order to allow others to interact with our instance of Chatty, we need to create a socket that will listen for connections (listeningSocket variable of the Server class) and instruct the networking subsystem of the operating system to notify us every time somebody tries to connect to that socket (we want the serverAcceptCallback function to be called for each new incoming connection). This is accomplished by the createServer method of the Server class.

How do other applications know how to connect to us? Each endpoint on the network must be identified by an IP address and port number. The address is determined by our network card – whenever iPhone or iPod Touch connects to the Wi-Fi network, it gets assigned an address automatically (or it can be set manually by the user). This means that we don’t have to worry about picking a value for the address (that’s what INADDR_ANY is for). But what about the other crucial piece of information – which port should we choose to listen on? Some servers must use pre-determined values in order to operate correctly (mail servers, web servers, virtual private servers etc). We don’t have such strict requirements and we can let the OS assign a port that is not occupied by any other application. To do that, we will use port number 0. The only caveat here is that we will need to tell other apps which exact port we are listening on in order for them to connect to us. We find out our actual port number in part 3 of the createServer method.

In part 4, we register our listening socket as a source of events for the application’s run loop. This will let the OS know to execute serverAcceptCallback whenever a new connection request comes in.

Whenever serverAcceptCallback gets called, we try to create a new Connection object (see handleNewNativeSocket method in Server.m) and tie it in with the socket that was created by the OS in response to the new connection request. After that, our freshly established connection gets passed on to the delegate.

Announcing the server via Bonjour

Strictly speaking, Bonjour is not the only way for apps to find each other on a network. But it turns out to be one of the easiest, and that’s why we are using it in this particular example. Publishing a service involves creating an instance of the NSNetService class, just like we do in the publishService method located in Server.m

When you search for services on the network, you need to specify what type you are interested in. Chatty uses “_chatty._tcp.” service type to differentiate itself from other Bonjour services that might be published on the same network. Additionally, each service must have a name that’s unique among all published services of the same type. Publishing will fail if there is already another service on the network with the same name. The last important piece of information is the port on which our server is listening.

Just like with the sockets, we want to perform Bonjour operations asynchronously in order to avoid blocking our main thread for long periods of time. That’s why, before actually publishing the service, we need to schedule it in the run loop. This allows us to handle various events, such as “Publishing succeeded”, “Publishing failed” etc. In this case, we are only interested in hearing about things that went wrong, and that’s why we are assigning self to be netService’s delegate and implementing the netService:didNotPublish: method. All we want to do in case of such an error is to propagate it further up the delegate chain.

Browsing for servers via Bonjour

Finding other Chatty apps on the network is a relatively easy task. Take a look at ServerBrowser.m. Whenever start method gets called, we create and initialize an object of type NSNetServiceBrowser and kick off the search for “_chatty._tcp.” services . Every time a new service is found or a service that was found earlier disappears from the network, our delegate gets called. This allows us to maintain an accurate list of services and tell our delegate to refresh the list when appropriate.

Resolving services via Bonjour

Whenever the user picks one of the chat rooms from the list, the app has to figure out how to connect to that particular server. All we have at this point is an NSNetService object (see ChattyViewController.m, method named joinChatRoom:). This is where we need to resolve the service. We accomplish this by calling resolveWithTimeout: on that object and wait until either netService:didNotResolve or netServiceDidResolveAddress get called (see Connection.m). And since that operation is happening on the background, we are free to do other things in the meantime, like switching to the chat room view.

As soon as netServiceDidResolveAddress gets called, we can proceed with establishing a connection to that server, which consists of creating a socket by calling CFStreamCreatePairWithSocketToHost() from within the connect method and setting up streams in setupSocketStreams.

The End: What’s next?

I would argue that a chat application is pretty close to being the “hello world” of networking programs. And while it’s very simple, it is also easily extensible. What can you do with Chatty to make it bigger/better/faster/more usable? Here are some random ideas for you:

  • If you decide to send messages between applications that might be running on platforms other than iPhone, consider encoding messages using XML instead of the binary property list format that Chatty is using right now.
  • If you want to squeeze every last bit of performance out of the message sending/receiving code, consider introducing a separate thread that will handle all of the networking stuff. You will also need to reduce the size of network messages by changing the message format to something slimmer.
  • You can write a simple game on top of this example by replacing the chat view with something more like a playing field. At first, you probably don’t even need to get dirty with the networking code itself – just replacing LocalRoom/RemoteRoom delegates might be enough (for board games or card games).
  • If you need more features, such as support for UDP protocol, for example, take a look at the cocoaasyncsocket project on Google Code.

One more thing: A puzzle

Before we go, here is a fun little exercise for those of you that like puzzles (or, as software developers call them, “last minute requirement changes”):

Right now, each chat message that gets sent from client to the server contains name of the user that the message is coming from, which then gets displayed right next to the message itself (i.e. when John types “Hello world!”, everybody else see it as “John: Hello world!” on the screen). This is a bit redundant: if John sends 100 messages to the same chat server, every single one of those will also carry the string “John” in it. Your goal is to change the code so that you wouldn’t send user’s name more than once after you connect to a server, and it would still be displayed in the chat view, just like it is now. Think of it as an optimization aimed at reducing the bandwidth used by the app.

This shouldn’t be too hard to do if you understand how Chatty works. But if you would like some hints on how to get started on the solution, take a look at puzzle.txt, which is included in the source code archive.

0 responses to “Tutorial: Networking and Bonjour on iPhone”

  1. Jens Alfke says:

    This is a very nice tutorial!

    The networking code in Chatty is pretty similar to my “MYNetwork” library for Mac and iPhone. MYNetwork is more complex under the hood, but provides additional features like SSL, TXT records, concurrent message streaming, message replies, high-priority traffic, and ZIP compression. It’s already being used in a few apps such as Flying Meat’s VoodooPad Reader.

    I’ve created a forked version of Chatty that replaces the custom networking classes with MYNetwork.

    Thanks again for writing this tutorial. It’s a great overview of networking and message-passing.

  2. Ptitaw says:

    Thanks again for this tutorial. But i have a question.

    If I have a complex chat application, with a lot of screens en multiple room opened in the same time. Do i have to use threading or keeping everything in the same thread is the best way to do it?

    Thanks

  3. Guillaume says:

    Any chance to have a version running on iPhone OS 3.0 Beta ?

    Thank you in advance

  4. Ryan says:

    Hello,
    I am a new iPhone developer so I might be doing something wrong, but when I build this for the iPhone 3.0 simulator, it gives the error of “error: type of accessor does not match the type of property ‘servers'” I am guessing that this s because of iPhone 3.0 software? Thanks, and if you have any more tips for getting started please reply.

  5. I’ll take a look at making Chatty work under iPhone SDK 3.0 and will post a comment about it here as appropriate.

  6. Tokyo Dan says:

    Can this example be used over the internet instead of just on a cal Wi-Fi network?

  7. Vavdiya Haresh says:

    Hi,

    This code is superb but it is giving error on OS 3.0 and crashes on OS 2.2.1. Can we use this code on project which is based on Internet?.

    Thanks.

  8. Ingrid says:

    To build for 3.0, just change

    @property(nonatomic,readonly) NSArray* servers;

    to

    @property(nonatomic,readonly) NSMutableArray* servers;

    in ServerBrowser.h.

  9. ajay rawat says:

    thanks very much, this is very nice tutorial

  10. Mohammed says:

    Thanks a lot .. I was messing p with sockets in Iphone for a past few days.. This helped out a lot .. By gods grace i am able to see this tutorials….

  11. zs says:

    Hi,
    Thanks for this. I’ve been playing around with it, and it works great. I have a question … right now, the client can only pick up any new messages that are broadcast. I want to add the feature that whenever a new client joins, he/she gets the full list of conversation on that chatroom, from even before the client joined. But i’m stuck… it seems all the communication is happening asynchronously, so the only option is to send a unique message which the server reads and then sends back. But the ‘chat’ text view is in the UI layer, and it doesn’t seem possible to send it across to the one client who just joined. Any ideas of how I could go about this?

  12. @zs The easiest way to do that is have the server keep a backlog of last X messages (in an array, for example). Whenever a new client connects, server can send those messages to it.

  13. Jordan says:

    Any chance of getting it working on OS 3.0. I get accessor method errors similar to the ones listed above.

  14. Pradeep says:

    Very nice tutorial it helped me a lot.
    Thanks

  15. prateek says:

    hi
    can you help me to compile this source code in iphone sdk 3.1.2

    please mail me the source code

    thanks

  16. Thank you very much for this illuminating and very well written article. I really do appreciate it.

    Have you by any chance looked at what is the iPhone’s maximum throughput using wifi under ideal conditions and what is the impact on the CPU when sending/receiving data? I’m intending to write a small project to answer those questions for myself, but I thought I’d ask you first, since you are well versed in this subject.

    cheers

  17. KermiDT says:

    Thank you, this code is just perfect.

  18. Eric Peter says:

    Inside the dealloc methods for classes such as Connection and Server, you set your instance variables to nil instead of calling release on them. I’m new to the iPhone, but it has been engrained in me thus far to always make sure to call release on (retain)’ed properties — is there a reason you do it this way?

  19. Peter says:

    @marc I haven’t done it myself, but would be interested in hearing about results of your tests!

  20. Peter says:

    @eric That’s because those variables are declared as properties, and “self.netService = nil” automatically becomes something like “[netService release]; netService = nil”.

    See here for more info: https://developer.apple.com/mac/library/documentation/cocoa/Conceptual/ObjectiveC/Articles/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW27

  21. Serign Jobe says:

    Your code is awesome, the more I use it, the more I love it.. Thanks!!

  22. Peter says:

    Thanks for the kind words. I’m glad that you found it useful 🙂

  23. Duy Pham says:

    Hi
    Can it work on the internet?

  24. Peter says:

    @Duy, you can reuse the Connection class to connect to servers on the internet, but Bonjour only works on local networks, so the app as a whole will not work online without some re-engineering.

  25. pfo says:

    It seems that the discovery works with Bluetooth, but the messaging doesn’t. Do you have an idea what would have to be changed to make this work both with WIFI and Bluetooth? Thanks.

  26. koko says:

    Has anyone any suggestions as to where to begin to implement Bluetooth to this tutorial as pfo has asked directly above me? Thanks

  27. Ritesh says:

    hi
    I am not getting any compilation problem over iphone SDk 3.1.2 but I do not recieve message from other servers.

    Could you please mail me the source code for SDK 3.1.2

    thanks

  28. Peter says:

    @pfo @koko I’ll try to test with Bluetooth next time I get my hands on an iPod Touch.. Not sure why messaging wouldn’t work there. Have you tried debugging it?

  29. Peter says:

    @Ritesh Are you going over Wi-Fi or Bluetooth?

  30. EJay says:

    Hi,

    Thanks for the nice tutorial!

    At the moment I’m using Apple’s GameKit for Bluetooth and Wifi networking for my turn based game, but I found it to be quite unreliable, e.g. client can still “see” closed servers etc, also you can’t run it on 2.1 devices.

    Have you encountered any issues like the one I’ve mentioned with your implementation? I hope that this problem is not Bonjour implementation issue, but rather GameKit bug.

    I guess I can just try your code as requirements for my game is super simple, just send x,y coordinates for each turn.

  31. pfo says:

    I just took the time to start debugging with Bluetooth. No clue why I had a problem the last time, but everything seemed to work fine!

  32. Helmut Forren says:

    Peter,

    First, thanks for the sample and granted permissions.

    I’ve been developing under Windows for almost 30 years. I’ve been developing on the iPhone for 3 days, with my first Mac I purchased a day earlier.

    Perhaps you can offer some advice to me. I’d like to ‘morph’ Chatty into an RS232 dumb terminal. At the Networking level, I’ll modify the code to connect to a WiFi-to-RS232 piece of hardware I’ve found (WiSnap at SerialIO.com). Where ever it exists, I’ll strip out Bonjour and instead (temporarily) hard code the IP address and port for the WiFi-to-RS232 hardware. Then, I’ll make some changes to the UI. When done, you’ll be able to plug the WiFi-to-RS232 into a real serial terminal (or rather the serial port of a PC running Hyperterm). Text typed in on the PC will appear on the iPhone, and text typed in on the iPhone will appear on the PC, each traveling over RS232. Note that the app is one-sided to the extent that the app only runs on the iPhone. The other side (the only other chat member) is actually a dumb terminal (Hyperterm).

    With the above in mind, I’m already “stuck” before starting. I want to connect to the WiFi-to-RS232 rather than to anything through Bonjour. I have a code snippet of socket access, and it wants IP addr and port. I know the IP address of the WiFi-to-RS232 as seen by the iPhone, but I don’t know the port. Do you know how I can find the port number?

    I think that after I can actually ‘connect’ to the WiFi-to-RS232, I’ll be able to accomplish the rest on my own.

    Any suggestions?

    -Helmut

    P.S. The app won’t be a dumb terminal for long. I’ll then replace the UI with some smart non-terminal application logic.

    P.P.S. WiSnap Setup app does the same thing already, but I don’t get source code. I need working source code for the dumb terminal function so that I can then upgrade it to my smart non-terminal application logic.

  33. pfo says:

    You might want to try the standard Telnet port: 25.

  34. Brandon says:

    Hi love you code simple to understand.
    I was wandering if you could add Bluetooth to the tutorial? That would be awesome. Also I am having trouble getting the welcome view and the second view that has the join button on it, to rotate propely to landscape mode.

  35. Ben says:

    Peter,

    Amazing tutorial. I learned a lot! Is it at all possible to do something similar i.e. connecting devices using sockets, but over the internet? So you don’t have to be on the same network/close by?

    b

  36. Peter says:

    @Brandon – same exact code will work over Bluetooth as long as it’s turned on in your iPhone/iPod settings. Bonjour framework takes care of it.

  37. Peter says:

    @Ben – you can use sockets to connect over the Internet, but you won’t be able to use Bonjour to discover those devices. Also, you will need a server that will facilitate communication between the devices. It’s a topic that’s a bit longer than what can fit in a comment – if you need more info, feel free to send me an email at (peter at byteclub . com).

  38. Rob says:

    Great tutorial and just what I’ve been looking for as the starting point to add network communications between instances of my app on the net. I wanted to start with the basic app, one on my phone & the other on the sim, but when I try to build & install, I get the error:
    CodeSign error: code signing is required for product type 'Application' in SDK 'Device - iPhone OS 3.1.3'
    I’ve never seen that with other demo code and since this is new to me, I’m at a loss. Any suggestions?
    OSX 10.6.2, Xcode 3.1.4

  39. zs says:

    You can use GameKit to setup the same client-server model over wifi (as of OS 3.1). Developers should probably use that instead of doing all this networking yourself (though it is a useful excercise).

  40. Peter says:

    @zs Good point. If you are planning to keep your code limited to iPhones and iPod touches, and no interoperability is required with Mac OS X, sticking to GameKit peer-to-peer might be a good idea.

  41. Rich says:

    Thanks for the great article and the sample code! Very helpful. I’m looking at some way to secure the communication between the peers and the server.

    Any pointers on where to look for code to help implement security?

  42. Peter says:

    Rich, I’m assuming you are talking about (at least) clients running on iPhone?

    One option is to try using OpenSSL library. Here is an article that talks about how to compile OpenSSL for iPhone: https://www.therareair.com/2009/01/01/tutorial-how-to-compile-openssl-for-the-iphone/

    Look for more libraries like that.

    One other thing: Apple has special requirements for apps that include cryptography – more information here: https://stackoverflow.com/questions/802879/iphone-and-crypto-libraries

  43. Steven says:

    I dont normally leave comments on sites like this but just want to show my appreciation for this. Im new to programming for the iPhone (very new) and have thrown myself in the deep end by taking on a project for uni. Have been struggling quite a bit with things but this has helped big time!
    Thanks again!

  44. Peter says:

    Steven, glad to hear. Good luck with the iPhone development!

  45. Gergely Kis says:

    Hi,

    I saw, that you are successfully using Bonjour over Bluetooth. What do you set for the service type? _bluetooth instead of _tcp?
    Does it also work on desktop (MacOSX), or only on iPhone?

    Best Regards,
    Gergely

  46. Peter says:

    Gergely, keep the service type “_tcp”. You need to make sure that Bluetooth is turned on in your iPhone’s settings.

    As far as I know, this only works on iPhones and iPod touches, and is called a “Personal Area Network”, which is a TCP/IP network established over Bluetooth. But you cannot connect Mac OS X to it out-of-the-box. 3rd party tools might be available, but I’m not aware of any.

  47. Metalboyblue says:

    Thanks for this tutorial. I too am interested in a link or more info in performing a connection between iphones without the wifi or bluetooth connections. Do you need to host a server or is there a way to connect to another iphone via a straight internet connection?

  48. Ricky Lung says:

    Great tutorial. But while Bonjour works over bluetooth, it fails in resolving the IP.
    I really want to use Bonjour with socket stream over Bluetooth instread of using Game Kit, any idea around?

  49. Vivek Tamrakar says:

    Very Nice tutorial.Thanks

  50. Ria says:

    You mentioned that exact same code will work over bluetooth once bluetooth is enabled on iphone, but it is not working, service is discoverable only in case of wi-fi. Am I missing something?