Inter Process Communication & Data Transport


Detailed Description

TnFOX provides a lightweight but powerful IPC framework based around message passing. It has been designed primarily with efficiency in mind - not only in terms of execution, but especially in terms of maintainence and extensibility. The IPC framework can use any FX::QIODeviceS eg; FX::QPipe, FX::QBlkSocket, FX::QLocalPipe or FX::QSSLDevice and via threads can provide full portable asynchronous i/o (ie; you can send a message, go do something else and get notified when its acknowledgement returns).

Messages can be of any size though generally they are unsuited for very large blocks of data (consider using a FX::QMemMap if machine-local). If you are streaming over an external connection (socket) then you'd usually want to chop them up into lots of smaller messages. For maximum flexibility there are broadcast type messages (one way) and synchronous messages (send and wait for acknowledgement message). Both outbound and acknowledgement messages can contain arbitrary C++ objects of any kind so long as they are serialisable using FX::FXStream. Endian translation is automatically performed where necessary. Out-of-order sequences are supported as are multiple independent transactions via one IPC channel (eg; by multiple threads). The data can be CRC checked for unreliable connections and GZip compressed for very slow ones.

As you might be guessing by now, the IPC framework was designed as a generic solution for almost every conceivable IPC need. You could just as easily implement a maximum efficiency windowed file transfer protocol as a simple ping-type broadcast. The upcoming Tn library will use the exact same framework for kernel/client communication, data stream implementation, distributed processing and inter-kernel communication. All these applications require quite different configurations of messaging protocol - this IPC framework makes it all quite easy whilst maintaining maximum speed.

While only a subset of CORBA's functionality is provided directly here, these classes along with the rest of TnFOX make it easy to build a CORBA-like system whilst remaining much more efficient and easier to use. Indeed, Tn does precisely this and benchmarks have shown a roughly 20-50% improvement over CORBA.

Implementation:

TnFOX uses a rather unconventional mechanism of defining IPC messages - this has resulted from lessons learned during my previous attempt in Tornado which while it worked, it began to become a maintainence headache as it grew (think large switch() statements). This solution is far more flexible and was inspired by a conversation with Marshall Cline (my thanks to him).

An IPC message registry defines a namespace of unique messages for a particular IPC channel. Both ends of the IPC channel must use a broadly compatible mapping of message C++ types to unique 32 bit integers. However to allow for one end to be much newer than the other, the namespace is not contiguous but is broken up into chunks of fixed start which are denoted by FX::FXIPCMsgChunk. All messages are versioned, so you can even maintain the unique message code whilst appending to the format.

When you construct a FXIPCMsgChunk, you enter the mapping of codes to types and deendianisation routine into the registry where it can be used to correctly identify, unpack and debug received messages. The unique code of each message within the chunk is determined at compile-time and it is very easy to add new messages with minimal recompiling. Destroying a FXIPCMsgChunk removes it from the registry - you can use this to implement security by literally removing the ability for certain functionality to be called. The main intention though was that DLLs could be loaded in which extend the messaging namespace and unloaded again.

All FX::FXIPCMsgRegistry's include by default the FX::FXIPCMsgChunkStandard chunk. This includes the following messages:

These messages are partially acted upon internally by FX::FXIPCChannel, usually sufficiently that you don't need to do anything yourself. See FX::FXIPCChannel for implementation notes for that class.

Usage:

To define a chunk you must follow the following pattern:

typedef FXIPCMsgChunkCodeAlloc<base of chunk, true> MyChunkBegin;
struct FXIPCMsg_MyMsg1 : public FXIPCMsg
{
   typedef FXIPCMsgChunkCodeAlloc<MyChunkBegin::code, hasAck> id;
   typedef FXIPCMsgRegister<id, FXIPCMsg_MyMsg1> regtype;
   int foo;
   FXIPCMsg_MyMsg1(int _foo) : FXIPCMsg(id::code), foo(_foo) { }
   void   endianise(FXStream &ds) const { ds << foo; }
   void deendianise(FXStream &ds)       { ds >> foo; }
};
struct FXIPCMsg_MyMsg2 : public FXIPCMsg
{
   typedef FXIPCMsgChunkCodeAlloc<FXIPCMsg_MyMsg1::id::nextcode, hasAck> id;
   typedef FXIPCMsgRegister<id, FXIPCMsg_MyMsg2> regtype;
...
typedef FXIPCMsgChunk<Generic::TL::create<
      FXIPCMsg_MyMsg1::regtype,
      FXIPCMsg_MyMsg2::regtype,
      ...
   >::value> MyMsgChunk;
While it's a bit of a mouthful, copy & paste makes it easy enough. Trust me, it's better than an enum of all type codes as the list breaks one hundred long!

More advanced usage:

The IPC framework can also tunnel messages across an IPC channel bridge ie; you send a message, the remote end receives it and resends it down another IPC channel all whilst ensuring that message acks route themselves backwards. If you want to do this, please ask on the mailing list for advice as it seemed too complex to document in detail for most users. On the other hand, it is quite straightforward if you think about it for a while. Tn's kernel implements precisely this mechanism to link together components running in disparate processes.

Using the IPC framework asynchronously is demonstrated by FX::TnFXSQLDB_ipc and the example code in the Tn directory inside the test suite.

Example code:

If you want some examples of usage, see the source for FX::TnFXSQLDBServer and FX::TnFXSQLDB_ipc. Also see TestIPC and TestSQLDB in the test suite.


Classes

struct  FX::FXIPCMsg
 A base IPC message. More...
class  FX::FXIPCMsgRegistry
 A registry of known IPC messages for a particular IPC channel. More...
class  FX::FXIPCMsgChunk< msgtypelist >
 A chunk within an IPC message registry. More...
struct  FX::FXIPCMsgRegister< codealloc, msgtype >
 Actual implementation of registering a message with the registry. More...
struct  FX::FXIPCMsg_Disconnect
 Received when the other end of the IPC channel disconnects. More...
struct  FX::FXIPCMsg_Unhandled
 Received when a message with an ack was not handled. More...
struct  FX::FXIPCMsg_ErrorOccurred
 Received when an exception was thrown by the other end of the IPC channel. More...
class  FX::FXIPCChannel
 Base class for an IPC channel over an arbitrary FX::QIODeviceS. More...


(C) 2002-2008 Niall Douglas. Some parts (C) to assorted authors.
Generated on Fri Jun 13 21:55:18 2008 for TnFOX by doxygen v1.5.6