Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

The Proton toolkit is built around the concept of a protocol engine. The idea behind a protocol engine is to capture all the complex details of implementing a given protocol in a way that is as decoupled as possible from OS details such as I/O and threading models, resulting in a highly reusable/embeddable . The result is a highly portable and easily embedded component that provides a full protocol implementation. To see how this works in the general case, it helps to start out with some simple examples of engines and build up to the full model used by Proton.

A common first step in writing networking code is to debug the network I/O portion independently from the rest of the application by using a much simpler protocol than the application will ultimately demand. Often the simple protocol chosen is the echo protocol. Anything sent to an echo server will be copied directly back to the client. The exact details of implementing an echo server might vary depending on what kind of I/O framework you are using, but it's inevitable that somewhere in the heart of an echo server there is some kind of data structure, either implicit or explicit, serving as a byte queue aka a or circular buffer. If you define an abstract interface around this byte queuedata structure, you have something that captures the admittedly trivial semantics of the echo protocol, but is a pure data structure, and therefore doesn't need to interact with the OS at all. We now have the echo engine depicted below. A simple circular buffer or byte queue, but with a slightly fancier title and because the interface is abstract. With this abstract interface, however, we can start tweaking the implementation of our engine independently from the rest of our server.

Gliffy Diagram
sizeL
nameEcho Engine
aligncenter
version2

Now let's try to make this Let's start by making our example do something a little more interesting by adding . We can add a query interface to our engine as depicted below. The I/O portion of our application still views the engine as a pure an ordinary circular buffer, however we can now add more sophisticated logic based on inspecting the stream of bytes that flows through the engine. We could, for example, log exactly how many bytes pass through, or decode some or all of the stream and provide an interface that would allow the application to log the semantic data encoded withinapplication logic that uses the query interface to take action. The exact nature of the query interface depends on the protocol and on the engine internals. A simplistic query interface might just provide a byte count of data passing through, whereas a more sophisticated engine could decode and make available semantic content embedded within the byte stream. While a little bit more capable than a simple echo engine, this kind of engine is still just a simple data structure with some added interrogatives, and so retains the desired decoupling and portability.

Gliffy Diagram
sizeL
nameEcho Engine with Query Interface
aligncenter
version2

This is about as far as we can go with an echo protocol, so lets now Now consider modifying our example to be a simple request/response protocol . Something where every response is a predefined function of each request. As depicted below, with We can provide an engine for this kind of protocol by modifying our simple echo engine to detect requests and replace them with responses. With the transformation function entirely encapsulated inside the engine, the interface presented to the I/O portion of the application is completely identical to our original echo serverengine. However, unlike the echo serverengine, we now have the ability to capture a large larger class of protocols inside this kind of engine, and furthermore as the engine is still essentially a pure data structure (if not quite a simple one anymore) it remains entirely decoupled from aspects of the OS such as I/O and threading.

Gliffy Diagram
sizeL
nameSimple Request-Response Engine
aligncenter
version2

Now just as we did with the echo server, we can also extend the simple request/response scenario with a query interface as depicted below. And as before, our engine is still just a data structure with well defined interfaces that keep it decoupled and portable.

Gliffy Diagram
sizeL
nameSimple Request-Response Engine with Query Interfac
aligncenter
version2

At this point even though we could capture a wide variety of protocols with this class of engine, there are still Despite being able to capture a large class of protocols, the simple request/response engine still has some significant limitations. For example if the response transformation requires accessing a file, as is the case with a classic HTTP implementation, our engine is no longer decoupled from the OS, and could in fact block on file I/O, or suppose in the case of modern HTTP . Also, if the request might is actually be invoking application logic and such as with an RPC protocol or with most modern usage of HTTP, we simply can't pre-define the result within the confines of our library. To accommodate these scenarios, while still keeping the engine as a simple data structure that is entirely decoupled from the OS, we can add a compliment to the query interface that allows the application to control the response as depicted below. Note that in this case, we need to modify our engine a little further to allow the application to control aspects of the response. To do this we add a control interface that can be used in conjunction with the query interface to inspect a request and modify the response.

As we do this we begin to see two distinct facets of the engine emerge. We have the interface presented to the I/O portion of our server still views the engine as which remains identical to our original echo engine, i.e. a simple circular buffer. It . Independent of this we have a higher level API emerging that presents the semantics of the protocol to the part of the server dealing with application logic. As we've seen, the latter interface can evolve and change depending on the nature of the protocol without any impact on the former. The I/O portion of our server need not know what kind of processing happens to the byte stream as it passes through the engine.

Gliffy Diagram
version
sizeL
nameRequest-Response Engine
aligncenter
3

While the above design nicely captures a very general class of protocol, it is still limited to protocols that use only request/response style interactions. The output bytes are always a function of the input bytes, even though the nature of that function may be influenced by the control interface. The final step to a fully general purpose protocol engine is to define the output bytes as a function of both the input bytes and the control interface as depicted below. This allows for fully general protocols whose interactions are not so regimented as request/response.

...

Gliffy Diagram
sizeL
nameGeneral Engine
aligncenter
version3

A further refinement of the general purpose engine is to separate the control interface into a distinct entity with its own lifecycle that . This entity can be bound to a given transport and then unbound. This separation has a number of nice features. For one thing it partitions formalizes the two facets of the engine interface discussed above into a bottom half that can keep a very simple I/O oriented view of the world, and a top half that reflects the high level application interface to the protocol. This separation The distinct lifecycle also permits the control interface to carry state across multiple physical connections, which can allow for a much more sophisticated control entity that can provide a simpler interface to more sophisticated protocols, for example automatically recovering state from a previous connection as is done with HTTP sessions.

Gliffy Diagram
sizeL
nameSeperate Control Interface Lifcycle
aligncenter
version2