Tuesday, December 8, 2009

Queued Reads & Writes

Custom network programming has always been a bit tedious. I'm not referring to the simple stuff like doing a HTTP request. I'm referring to actually working with a TCP socket, and implementing some protocol. The protocols themselves are often straight-forward, and easy enough to understand. But when it comes time to write it, that darn socket keeps getting in the way and complicating your code.

A concrete example is always helpful.

Say you're implementing some client or server, and you need to send a response over your socket. The response starts with some kind of message header (which maybe specifies the length of the response and some other attributes) and then has the message body. Seems simple enough, right? Now let's say there's even a bunch of existing code that will help generate the response body and the response header. Something like this:
- (NSData *)responseBody;
- (NSData *)responseHeaderForBody:(NSData *)body;

Looks like the code is almost done! Let's write the method now:
- (void)sendResponse
{
NSData *body = [self responseBody];
NSData *head = [self responseHeaderForBody:body];
// But wait!
// I can only do one write at a time!
}

Why is this a problem at all? We simply write:
socket.write(head);
socket.write(body);

This would work...IF we were using a blocking socket. However, asynchronous sockets are more commonly used, for obvious reasons. Using an asynchronous socket, the second write(the body) can't begin until the first(the head) has completed. There are two simple ways to get around this problem.

One possibility is to store the body until the head has been sent, and then write the body. This would likely involve setting flags, and generally writing a bunch of code to make sure the body is written at the proper time. The extra code to overcome this problem is not hard to write, but complicates the otherwise simple and straight forward method.

Alternatively, the head and body can be merged together before the write. Again, this is not complicated, but tedious and requires extra memory allocation.

Furthermore, what happens the next time this problem arises? These kinds of workarounds clutter up code, which makes it easier to introduce bugs. If you're writing a big complicated networking class, the last thing you want is more code clutter! Wouldn't it be nice if you could write to the socket on YOUR terms? That is, when YOU are ready to write data and not when IT is ready to accept it!? Wouldn't it be great if the asynchronous socket handled the problem, leaving the custom networking code cleaner and easier to debug?

Good news! You're in luck! Because CocoaAsyncSocket does queued writes for you automatically! So you can write your code like this:
- (void)sendResponse
{
NSData *body = [self responseBody];
NSData *head = [self responseHeaderForBody:body];

[asyncSocket writeData:head];
[asyncSocket writeData:body];
}

Both write methods return immediately, and the writes will happen in the background. The AsyncSocket will automatically queue the operations, and write them in order.

Of course, it also supports queued read operations. It doesn't stop there, AsyncSocket can queue a disconnect after reads and/or writes are complete. And if you're working with secure sockets, AsyncSocket even lets you queue an upgrade of the socket to SSL/TLS.

Check out the CocoaAsyncSocket Google Code page for more information. The code is open source, compatible with Mac and iPhone, and in the public domain so it can be used in any project.

7 comments:

Nic Wilson said...

Off topic conversation..

Has Mojo development now ceased? none of the links work and I was hoping for a windows release for my company machine

AK said...

off topic conversation as well...
I use mojo extensively and I had a suggestion but I don't use outlook so I couldn't just email it. I think you should be able to browse and look for a song across everyone library on your network. Just a suggestion. Anyways thank you for a great product.

Jawxies said...

...and another off topic comment : when will we get our Mojo back ? :)

I see that the website's been unavailable for a couple of months now. I've got a whole bunch of people I'm eager to share my music with but who can't download the client binary :(

Anonymous said...

it's sad, but I think Mojo is dead...

R.I.P. Mojo...

Anonymous said...

Is mojo dead?

Anonymous said...

it's dead!
otherwise Robbie or Luke would place a statement...

too sad...

Anonymous said...

I miss my Mojo