- Notifications
You must be signed in to change notification settings - Fork5
6.MessageProtocol
Considering a client/ server model, where a type is serialized and sent over the network. In order to infer what the bytes represent on receiving end,we need to have some sort of metadata about the message.
PureProtoClientclient=newPureProtoClient();client.Connect("127.0.0.1",11234);client.SendAsync(newSampleMessage(){sample="Yo! Mr White"});server.BytesReceived+=(clientId,bytes,offset,count)=>{// What did I receive??};
Because of this, I have implemented an envelope class which acts as a metadata/header/carrier on top of an optional payload. Intention here is to be reusable on all network systems and serialization strategies.The message envelope looks as follows:
publicclassMessageEnvelope:IMessageEnvelope{publicboolIsInternal{get;set;}publicDateTimeTimeStamp{get;set;}publicGuidMessageId{get;set;}publicstringHeader{get;set;}publicGuidFrom{get;set;}publicGuidTo{get;set;}publicDictionary<string,string>KeyValuePairs{get;set;}}
Where any of the properties can be null/default and they wont be considered on serialization. You only send what you wrote different than default values.
Core network system identifies each session with a GUID.This Guid is also represents a ClientId for the server side of the TCP systems. in P2P systems such as Relay P2P or Room server this Guid identifies PeerId .Hence theFrom andTo properties represens from peer to another peer on P2P cases.
MessageId is used for async calls likeMessageEnvelope response = await SendMessageAndWaitResponse(..., timeoutMs:10000)when such method is called, a MessageId is automatically assigned.Once the receiving end receives a message with aMessageId that is notGuid.Empty sends a reply message with sameMessageId, it will be caught by the sender will become the async response. There is no built in reply, its up to the developer how to filter such messages.
Note that when such async call is active/pending socket is not blocked, you can send as many messages as you want parallelly in between.
Payload is essentially an index for some bytes.

MessageEnvelopeenvelope=newMessageEnvelope(){Header="ImageTransfer",Payload=bytes,};// For byte segments, there is no extra copy here.envelope.SetPayload(Buffer,offset,count);
when sent through a network system this bytes will reach to its destination atomically.
considering a method such as client.SendAsyncMessage(messageEnvelope, innerMessage); The inner message will be serialized as byte payload.Receiving end is responsible to deserialize from the information provided by the message envelope.
OnMessageReceived(envelope){SomeDataClassinnerMesssage=envelope.UnpackPayload<SomeDataClass>()}
You can acces payload region by using.Payload,.PayloadOffset and.PayloadCount properties of message envelope
- MessageEnvelope and some internal messages are serialized statically with efficient binary encoding. SeeSerializationBenchmarks
- On receiving end, payload bytes are volatile. If the execution leaves the stack, bytes may be overwritten by next message. If you intend to store payload, either copy manually or call LockBytes() method of the message envelope.Unpacking / deserializing a message is safe since it inheritly does a copy.
- Using message envelope without an inner message for simple information transfer or raw data transfer is way more efficient (3x) and reccomended.