Hi all,
a few of you have been posting on the forums with question on how to connect to a server using TCP/IP. Connecting to a server enables you to send messages to other clients in real-time, talk to a chat server, read your email or call procedures on a remote web server. It can also allow you to sync one or more clients by sending timing information, although admittedly a UDP message would be more suitable for this than TCP.
Server
Of course, what you can do is up to you and depends on the kind of server you are connecting to. Explaining how to write your own server is beyond the scope of this post, because it isn't related to Cinder. To point you into the right direction, though, I strongly recommend writing your server in
Java using JBoss Netty. This will allow you to create an extremely versatile, stable and efficient server in a couple of minutes (provided you have some experience with Java).
Client
I will focus on the client-side of things in the sample. Using Boost's ASIO library, which comes with Cinder, it isn't difficult to create a socket connection to a server. It is explained in the comments of the source code.
You can find the source code here:
The sample
It's a pretty boring sample, but what it does do is give you a working TcpClient class with heartbeat timer and auto-reconnect. The heartbeat can be used to keep the connection alive; most servers break the connection if no messages are sent over a period of time. The heartbeat can send some message every few seconds to let the server know the application is still running. The protocol I normally use sends a "PING" message, to which the server responds with a "PONG".
The sample resolves the url of and connects to the GMail server, then waits for the heartbeat timer to kick in. Instead of a heartbeat, it will send a "QUIT" message. The server will then break the connection. That's when the auto-reconnect timer starts, which will try to reconnect to the server after a few seconds. This process is repeated until you quit the application.

Thread issues
Most samples that come with Boost ASIO use the IoService's run() method to process the connection's messages. This method takes over your thread and blocks it until the connection is closed. Not suitable at all for a Cinder application.
At first, I tried to remedy this by creating a separate thread to run the IoService in. I misunderstood the way the callback functions are called, thinking it would be in a thread-safe way. It wasn't. Even usingci::app::console() in one of your callbacks could crash your application.
The solution is to not use run(), but repeatedly call poll() instead. The IoService thus runs on the main thread, but provided you don't send 50 megs of data every second, you should hardly notice it.
Regex
In order for this sample to work in Cinder, make sure you add -DBOOST_REGEX_NO_LIB to your project settings. Otherwise Asio tries to link to the Boost regex lib, which isn't included with Cinder.
Hopefully you find it a useful sample. Let me know what you think.
- Paul