I am trying to implement a reliable TCP library that will allow users to select the application protocol or implement their own and simply "connect" them to the client / server.
By protocol, I mean simply the ability to determine how a stream should be enclosed in messages.
I use the built-in asynchronous TCP libraries for the rest of the stack and have developed a client that raises events whenever a connection is established, data is being read or written, or an exception is thrown.
I have two options for implementing the framing protocol. The first one that already works is to extend the client class and override the event received by the data so that it is raised only when a full message is received. (i.e., under the hood, I buffer the raw data from the socket and, based on the protocol, decide when I have the full message, and only then pick up the received data.) This is similar to how the Nito.Asynch Library works.
The problem with this approach is that each new protocol requires a new client implementation. I would prefer the client to support an internal filter stack that can be added or removed.
When data is received on the socket, it is passed to the first filter, which buffers until it decides to send the full message (s) with the deleted header or metadata. Then it is passed to the next filter on the stack, etc. Etc.
Thus, filters can be defined / developed independently of the library and entered into the client based on the configuration (at run time).
To do this, I thought of defining filters as pairs of System.IO.Stream implementations (incoming and outgoing) that are stored inside the client.
Data read from the socket will be written to the lower input stream on the stack. Then, the data read from this stream will be written to the next stream, etc., until the last stream (top of the stack) returns the data, and then will be returned by the client. (My plan was to use the CopyTo () function for Stream).
Data written to the client will be written to the upper outgoing stream and copied onto the stack until the lower outgoing stream is written to the underlying socket.
Obviously, there is a lot to think about, and I'm trying to find the right way to behave like a Stream object. Example: what should I do when someone calls Flush () ...?
Is this a good way to achieve this, or am I reinventing the wheel here again?
Nito.Asynch Library