I'm in charge of designing an application protocol for a set of in-house, batch-oriented, client-server applications. I'm familiar with IBM LU 6.2 (a.k.a. "Advanced Program-to-Program Communication"), and for the past 15 years have worked in Unix environments.
The client is a batch job that connects to a server process — which, in turn, connects to nine other "sub-server" processes. The client passes a customer transaction record to the server, which distributes different portions of the record to the sub-servers. Each sub-server processes its portion independently and concurrently, and passes some results back to the server which then passes them back to the client.
These are TCP connections, and we decided that, first of all, we'd use newline-terminated ASCII strings (we call these lines) as our Protocol Data Unit. A record is a line that is subdivided into tab-separated fields, and since each process will have its own data requirements, field#1 of every record will contain a record type. This is used as a key into a metadata store to find the field names, in the order they’re expected to appear in the record, in order to know how to interpret the record. For example:
Metadata: NAME=(prefix, first_name, middle_name, last_name, personal_suffix, professional_suffix)
(Here I use '|' to represent the tab character, and '#' to represent newline character)
Very straightforward so far, I think.
But then, new twists arose. The first was that, instead of sending all the data about one transaction in a single [large] record, we'd like to possibly use several records: a NAME record, an ADDRESS record, an EMAIL record, etc. So we invented the block - a series of records, preceded by a “special” BB record and followed by an EB record. The BB record’s first field is, of course, 'BB', and the second field holds the block type. Block type, like record type, is a key into metadata listing the record types (required, or optional) in this block type.
Understandably, each of these ten or so processes, having its own unique data requirements, has led to its own set of record types, enclosed in their own set of block types. That's a lot of metadata, but it isn't really a showstopper.
The next thing requirement that emerged was a special "context-setting" message, to transmit certain configuration variables that would remain constant from transaction to transaction. This gave rise to a new record and block type, as well as a new column in the block metadata that indicated this kind of block was somehow "special".
Then, envisioning circumstances where the "context" could change during the runtime of the client, we lifted the rule that stipulated there could be only one "context" message, at the beginning of a connection. At the same time, we realized there was still a need for a true "initialization" message that could only come once, at the beginning, conveying "session-global" parameters. Thus the INIT block was born, and now there were three flavors of block: session-initialization, context-switching, and normal application data.
Then, how about a connection that isn't for transaction-posting at all, but rather a control session for querying the health of the server, retrieving statistics, changing operational settings? The INIT block’s role became more general, declaring the "mode" of the session, which could now be either "posting", or "control."
We've been trying to wedge all of this into a single-layered application protocol, and it's getting out of hand. Just defining a "special" BB record should have raised a red flag - it's constructed from application-level objects and metadata, but it is not application data - rather, it frames the application data.
I think what has evolved is a 2-layer architecture atop TCP: one layer that simply provides typed containers (blocks and records), and a higher layer that uses those containers for a specific purpose, be it posting, or control, or something else - the true application protocols. However, I'm not well-versed enough in the design of protocols to recognize "patterns" that might be obvious to the pros. I'd appreciate any feedback on how to approach this.
It also seems possible that someone may have written a guide to designing protocols, that addresses these very concerns. I just haven't found it.
And my apologies for the length of this post. I hope none of it was immaterial. My deep thanks for your patience!