The process of sending and receiving a message differs between the TCP and WebSocket standards. Below, we explain this process in detail for both types of connections.
To send a message via a TCP connection, do the following:
Change the Protobuf message to an array of bytes (using the Protobuf encoding) by using the official Google Protocol Buffer SDK for your chosen programming language.
Get the length of the array created during step 1. Create a new byte array from this integer. Reverse the new byte array.
Concatenate the new byte array and the byte array containing the original Protobuf message.
Send the concatenated array to the connection stream.
The examples below demonstrate how these steps are performed in the official Open API SDKs.
client=Client(EndPoints.PROTOBUF_LIVE_HOSTifhostType.lower()=="live"elseEndPoints.PROTOBUF_DEMO_HOST,EndPoints.PROTOBUF_PORT,TcpProtocol)request=ProtoOAApplicationAuthReq()# Can be any messagedeferred=client.send(request)
Python example
Using Twisted, the Python example performs nearly the same operations as the C# one. The client.send(request) can be explained as follows.
123
request=ProtoOAApplicationAuthReq()# Can be any messagerequestAsString=request.SerializeToString()# This method is a part of the Google Protobuf SDKrequestAsInt32String=struct.pack("!H",len(requestAsString))# The message is concatenated with the reversed array
For sending the message, the Python SDK uses the Protocol.transport.write() method.
All Open API SDKs rely on asynchronous execution, meaning that they do not wait for messages to arrive but, instead, react to dynamically arriving messages. As a result, receiving a message is typically done via event handlers
To read a message, you will have to perform a sequence of actions that reverses the steps required for sending a message.
Receive the first four bytes of a byte array (remember, they denote the message length). Reverse these four bytes and change them to an integer.
Read X amount of bytes from a stream where X is the integer you have gotten during step 1.
Use the Google Protobuf SDK to deserialise the message into a valid ProtoMessage.
Use the payloadType field of the ProtoMessage object to find its actual type. Via the Google Protobuf SDK, change the ProtoMessage to an object of the needed ProtoOA... type.
The code snippets below demonstrate how the official Open API SKDs approach reading messages.
_tcpClient=newTcpClient{LingerState=newLingerOption(enable:true,10)};await_tcpClient.ConnectAsync(Host,Port).ConfigureAwait(continueOnCapturedContext:false);SslStream_sslStream=newSslStream(_tcpClient.GetStream(),leaveInnerStreamOpen:false);await_sslStream.AuthenticateAsClientAsync(Host).ConfigureAwait(continueOnCapturedContext:false);privateasyncvoidReadTcp(CancellationTokencancellationToken){byte[]dataLength=newbyte[4];byte[]data=null;try{while(!IsDisposed){intnum=0;do{intcount=dataLength.Length-num;intnum2=num;num=num2+await_sslStream.ReadAsync(dataLength,num,count,cancellationToken).ConfigureAwait(continueOnCapturedContext:false);if(num==0){thrownewInvalidOperationException("Remote host closed the connection");}}while(num<dataLength.Length);intlength=GetLength(dataLength);if(length<=0){continue;}data=ArrayPool<byte>.Shared.Rent(length);num=0;do{intcount2=length-num;intnum2=num;num=num2+await_sslStream.ReadAsync(data,num,count2,cancellationToken).ConfigureAwait(continueOnCapturedContext:false);if(num==0){thrownewInvalidOperationException("Remote host closed the connection");}}while(num<length);ProtoMessageprotoMessage=ProtoMessage.Parser.ParseFrom(data,0,length);ArrayPool<byte>.Shared.Return(data);OnNext(protoMessage);}}catch(ExceptioninnerException){if(data!=null){ArrayPool<byte>.Shared.Return(data);}ReceiveExceptionexception=newReceiveException(innerException);OnError(exception);}}privateintGetLength(byte[]lengthBytes){Span<byte>span=lengthBytes.AsSpan();span.Reverse();returnBitConverter.ToInt32(span);}
Python example
In the Python example, all operations with bytes on receiving messages are handled by the dataReceived() method as shown below.
1 2 3 4 5 6 7 8 910111213141516
defdataReceived(self,recd):""" Convert int prefixed strings into calls to stringReceived. """self.recvd=self.recvd+recdwhilelen(self.recvd)>=self.prefixLengthandnotself.paused:length,=struct.unpack(self.structFormat,self.recvd[:self.prefixLength])iflength>self.MAX_LENGTH:self.lengthLimitExceeded(length)returniflen(self.recvd)<length+self.prefixLength:breakpacket=self.recvd[self.prefixLength:length+self.prefixLength]self.recvd=self.recvd[length+self.prefixLength:]self.stringReceived(packet)
To send a message over a WebSocket connection, perform the following actions:
Serialise the message into any suitable data format (for example, a string).
Add the serialised message to your send queue.
The examples below demonstrate how these actions are performed in the official Open API SDKs.
The C# SDK uses the WebsocketClient class which is a part of the Websocket.Client package. As shown below, the WebsocketClient.Send() method works as follows.
Before subscribing, the .NET SDK parses the message into a Protobuf message. The necessary subscriptions are added in the body of the ConnectWebSocket() callback.