This document outlines the data that is exchanged between the Client and Service. In this document:
- Client is what makes the remote procedure calls e.g. Octopus Server.
- Service is what executes the methods e.g. Tentacle.
When invoking a remote method in both polling and listening mode, the Client
and Service
go through three stages.
A TCP connection is established and both Service and client identify themselves, through a series of control messages. The control messages sent vary depending on if listening or polling mode is used.
Now that the connections are established, the Service will wait for requests from the Client. In both polling and listening the following steps are repeated in order:
- The Client sends a
Request
message containing the method to execute, its parameters and 0 or more data streams. - The Service executes the method and sends the result in a
Response
message containing the result and 0 or more data streams. - The Service and Client exchange
NEXT
andPROCEED
control messages. The direction of these message differes depending on if the service is in polling or listening mode.
The steps are repeated for both Listening and Polling mode until either Client or Service begins the Ending a connection stage.
The final stage can be entered by either the Client or Service terminating the TCP connection or sending a END
control message. Once this stage is reached no more requests will be processed in the current TCP connection.
In listening mode the Client will keep and pool connections for subsequent RPC calls. In this mode the "pooled connection" is tested by sending and recieving control messages before sending the Request message. If the control messages can not be exchanaged a new connection is made.
- Identification:
- Client identifies itself as
MX-CLIENT 1.0
- Service identifies itself as
MX-SERVER 1.0
- Client identifies itself as
- Message exchange:
- The Client sends a
Request
message containing the method to execute, its parameters and 0 or more data streams. - The Service executes the method and sends the result in a
Response
message containing the result and 0 or more data streams. - The Client places the TCP connection into the pool
- The Service waits for a control message.
- The Client sends a
- Connection re-use: When the Client wants to make a new RPC call:
- A connection is removed from the pool and tested by:
- The Client sends a
NEXT
control message. - The Service responds witha
PROCEED
control message.
- The Client sends a
- If the client is unable to send
NEXT
or recieve thePROCEED
control message, the TCP connection is clossed and a new one created following the process from step1.Identification
. - If the client recieves
PROCEED
the RPC call is made with this TCP connection starting at step2.Message exchange
.
- A connection is removed from the pool and tested by:
In Polling mode the Service initiates the connection and does a long poll to the Client for Requests. In this mode only a single TCP connection exists at any one time, unlike in listening mode where connections are created as required. This means that in polling mode, only one RPC call can be made at a time.
To make RPC calls the steps are:
- Identification:
- Service identifies itself as
MX-SUBSCRIBER 1.0
- Client identifies itself as
MX-SERVER 1.0
- Service identifies itself as
- Message exchange:
- The Client sends a
Request
message containing the method to execute, its parameters and 0 or more data streams. - The Service executes the method and sends the result in a
Response
message containing the result and 0 or more data streams.
- The Client sends a
- Connection re-use:
- The Service sends a
NEXT
control message. - The Client responds with a
PROCEED
control message. - The Service Waits for a Request message. If waiting times out the connection is closed and recreated starting again from step
1.Identification
. - When the Client makes a new RPC call the same TCP connection is re-used and the process starts again at step
2.Message exchange
.
- The Service sends a
Under polling mode, unlike listening, the Client will periodically send a no-op NUL Request to the Service to keep the TCP connection alive. This avoids a timeout occuring in step 3.3
.
The message format is always a Zipped BSON representation of either the Request or Response message, followed by zero or more DataStreams. A DataStream
represents data that should not be serialized as part of a message, for example a file to be transferred. They can be sent in either a request or a response. DataStream
s are transferred as raw bytes in the TCP stream (i.e. they are not compressed) and are sent sequentially after the compressed BSON of the request/response. Each DataStream
has a unique GUID which is referenced in the request/response so that it can be used by calling code.
Below is an example of the Request and Response messages when making a simple RPC with Halibut.
For a RPC call made with
public interface ISample
{
public string SayHello(string message, DataStream theData);
}
public class HelloMessageData
{
public DataStream TheData { get; set; }
}
// Example call
var data = "This message is being sent to the tentacle as a data stream".ToUtf8();
var response = echo.SayHello("Alice", DataStream.FromBytes(data));
The resulting Request
The resulting response
Halibut's protocol was inspired by JSON-RPC, read its history here.
- Protocol Fixture Which documents the protocol in test.
- Diagrams src