For a good read in internet protocols: http://www.cisco.com/univercd/cc/td/doc/cisintwk/ito\_doc/ip.htm
TCP tries to be a universal solution, and it works, but it's not as efficient as a custom protocol. The packets are larger and the protocol strict, which isn't a bad thing, but it's not the best thing for some people.
If you can come up with your own relay scheme and then implement an error checking routine, along with interpolation for missed and predicted packets, then it's most likely going to have less overhead than TCP. The problem is in designing a robust protocol that can not only flag errors and failures, but compensate for temporary glitches and corrupted data.
It all depends on how much data you're trying to send, and at what rate. And for error correction, you're probably going to want to send packets in triplicate, so as to be able to check the accuracy of transmission. If you have small amounts of data, or a slow rate of communication, TCP will work just fine, and it's a proven, stable format. If you have lots and lots of data or a very high send rate, a custom protocol is ideal.
A possible solution is to have a simple thread set up that listens for a boolean packet every .5 seconds, and sends a boolean every .5 seconds. If true, the connection is live, and the thread pops out it's own "true" flag to the other client. If missed, it sends itself a "false" packet and initiates the interpolation algorithm. Then, it's up to you to decide how long a "missed" connection will be allowed before the "connection broken" flag is thrown, and ends the session.
In any case, a relay is the solution to your problem. Bounce small amounts of data back and forth between clients and make a listener thread that reacts to any changes to do what you want the program to do.