My current project involves creating an iPhone application that communicates with another application (hosted on a PC). Ideally, I wanted to do this via Bluetooth, but like a lot of other (useful) stuff, Apple's API doesnt expose it for any communication other than peer-to-peer (iphone to iphone) and audio gateway. So using that was out of question, though my personal side project is to write a program for PC that
fools the iphone into thinking that its talking to one of its own. So for now I am using the WiFi/Network connection.
My goal: Create a simple app, that connect to a TCP host, sends "Hello World" and closes the connection.Being a complete beginner in iPhone development, my first step was check out the Apple's official Networking guides. I found and followed
Cocoa Streams how-to. This document is filed under
iPhone Reference, and can be accessed from the developer webpage. After hours of struggling with the seemingly simple code, I realized that iPhone OS
does not support +getStreamsToHost:. I have filed a bug regarding this document's classification. After some chitchatting and more documentations, I found the correct way to create a connection is to use the
CFNetwork framework, which is well explained by Apple
here.
Following the sample code, I created an app that uses CFStreams to create a socket connection.
-(IBAction) connect_button {
CFWriteStreamRef writeStream = NULL;
CFStringRef host = CFSTR("10.212.97.159 ");
UInt32 port = 22701;
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, host, port, NULL, &writeStream);
CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
if(!CFWriteStreamOpen(writeStream)) {
NSLog(@"Error Opening Socket");
}
else{
UInt8 buf[] = "Hello WOrld!";
int bytesWritten = CFWriteStreamWrite(writeStream, buf, strlen((char*)buf));
NSLog(@"Written: %d", bytesWritten);
if (bytesWritten < 0) {
CFStreamError error = CFWriteStreamGetError(writeStream);
/** How do I print out description? All i get is -1 here. i.e What is perror() equivalent? **/
}
}
CFWriteStreamClose(writeStream);
}
Very simple and familiar looking code, so this should definitely work. Right? Well no it did not. I kept getting an error, which is stored in CFStreamError type. Problem is I had no way of interpreting that error. The CFError type is very well documented, but CFStreamError has a lot of loose ends. I spent quite a time trying to figure out what the error meant so that I could debug my application.
Update: The above code works! I still do not know how to print out the description of CFStreamError, but I found the error when I rewrote the code. The culprit is Line 5. Do you see it? :). Its the whitespace after the IP. Damn! That little error wasted atleast a few hours of my coding time.Finally, I gave up on
apple's way of networking and decided to do it the classic C-style way. I found an amazing library called the
SmallSockets that uses the linux style of sockets under the hood, wrapped inside a Obj-C class. Downloaded it, added the headers file in my project and
Voila!, it worked! All under 5 minutes!
-(IBAction) connect_button {
Socket *socket;
int port = 22701;
NSString *host = @"10.212.97.159";
socket = [Socket socket];
@try{
[socket connectToHostName:host port:port];
[socket writeString:@"Hello World!"];
//** Connection was successful **//
//[socket retain]; // Must retain if want to use out of this action block.
}
@catch (NSException* exception) {
NSString *errMsg = [NSString stringWithFormat:@"%@",[exception reason]];
NSLog(errMsg);
socket = nil;
}
//** Disconnect **//
[socket close];
}
Though my project is now up and running with 2-way network comm, I still want to get back to the CFNetwork and figure out where I went wrong, and try to implement a bare bone hello world app, the apple way.