I’ve been working with CFNetwork to create a client application for iPad, it is a small application, nothing fancy.
This is how I create the connection to the server (running in windows).
- (void) startConnection
{
char ip[] = "192.168.0.244";
NSString *ipAddress = [[NSString alloc] initWithCString:ip];
/* Build our socket context; this ties an instance of self to the socket */
CFSocketContext CTX = { 0, self, NULL, NULL, NULL };
/* Create the server socket as a TCP IPv4 socket and set a callback */
/* for calls to the socket's lower-level connect() function */
TCPClient = CFSocketCreate(NULL, PF_INET, SOCK_STREAM, IPPROTO_TCP,
kCFSocketDataCallBack, (CFSocketCallBack)DataCallBack, &CTX);
if (TCPClient == NULL)
return;
/* Set the port and address we want to listen on */
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_len = sizeof(addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);// PORT = 5001
addr.sin_addr.s_addr = inet_addr([ipAddress UTF8String]);
CFDataRef connectAddr = CFDataCreate(NULL, (unsigned char *)&addr, sizeof(addr));
CFSocketConnectToAddress(TCPClient, connectAddr, -1);
CFRunLoopSourceRef sourceRef =
CFSocketCreateRunLoopSource(kCFAllocatorDefault, TCPClient, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), sourceRef, kCFRunLoopCommonModes);
CFRelease(sourceRef);
CFRunLoopRun();
}
As you can see, when I create the server socket I register a callback to listen to incoming data from the server.
Then I use the CFRunLoopAddSource(…) and CFRunLoopRun() methods to have this callback listen in the background.
Now, this is how it looks my send method
- (void) send
{
if (TCPClient == NULL)
return;
Byte byteData[3];
for (int i = 1; i <= 25; i++) {
receivedLastAnswer = NO;
globalPos = i;
byteData[0] = i;
byteData[1] = 4;
byteData[2] = 0;
int len = 3;//strlen(byte)+1;
CFDataRef refData = CFDataCreate(kCFAllocatorDefault, byteData, len);
CFSocketSendData(TCPClient, NULL, refData, 0);
while (!receivedLastAnswer) {
//this while is to wait until a response is send by the server
}
}
}
What I want to do is send a command to the server (the 3 bytes array you see is the command) and wait for the server to respond before sending the next command, to do this I use a while, the variable “receivedLastAnswer” is a flag that is set when my DataCallBack method is invoked, so if the server responds, the callback is invoked, it sets the flag to true and thus the while exits and the next command is send.
Of course this is not how I intend to leave the code, this is just for testing and to see if it works, cause later I will have to add another condition to the while, a timeout condition, in case the server doesn’t respond at all.
Now, my problem is that my application, the client, is not firing the callback method, and thus it just cycles infinitely; I think the reason for not firing the callback is because the application is busy in the while cycle, in fact if I remove the cycle, the callback is fired, but this doesn’t makes sense to me because isn’t the callback method supposed to be running on a different thread (isn’t that the purpose of CFRunLoopRun()?) and because it is running in a different thread it shouldn’t matter that the main thread be in a cycle or am I completely misunderstanding how this works?
Also, I tried not using a while cycle, but a Sleep() function, but it is the same, no callback is fired.
Do you have any idea why this may be happening or how can I accomplish this,
Thanks.
Well I think that in deed my data Callback wont be called if the main thread is busy or blocked, so what I did was to leave the Callback method on the main thread and put my send method in another thread, it worked pretty well actually, however I’m still wandering if there would be another way, but for now it does what I need so I’m going to stick to it.