O processo de enviar e receber uma mensagem difere entre os padrões TCP e WebSocket. Abaixo, explicamos este processo em detalhe para ambos os tipos de ligações.
Para enviar uma mensagem via ligação TCP, faça o seguinte:
Transforme a mensagem Protobuf num array de bytes (usando a codificação Protobuf) utilizando o SDK oficial do Google Protocol Buffer para a sua linguagem de programação escolhida.
Obtenha o comprimento do array criado durante o passo 1. Crie um novo array de bytes a partir deste integer. Inverta o novo array de bytes.
Concatene o novo array de bytes e o array de bytes contendo a mensagem Protobuf original.
Envie o array concatenado para o stream de ligação.
Os exemplos abaixo demonstram como estes passos são executados nos SDKs oficiais da Open API.
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)
Exemplo Python
Usando Twisted, o exemplo Python executa praticamente as mesmas operações que o C#. O client.send(request) pode ser explicado da seguinte forma.
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
Para enviar a mensagem, o SDK Python utiliza o método Protocol.transport.write().
Todos os SDKs da Open API dependem de execução assíncrona, o que significa que não aguardam a chegada de mensagens mas, em vez disso, reagem a mensagens que chegam dinamicamente. Como resultado, a receção de uma mensagem é normalmente feita através de gestores de eventos
Para ler uma mensagem, terá de executar uma sequência de ações que inverte os passos necessários para enviar uma mensagem.
Receba os primeiros quatro bytes de uma matriz de bytes (lembre-se, eles indicam o comprimento da mensagem). Inverta estes quatro bytes e converta-os num número inteiro.
Leia X bytes de um fluxo onde X é o número inteiro que obteve durante o passo 1.
Utilize o SDK Google Protobuf para desserializar a mensagem numa ProtoMessage válida.
Utilize o campo payloadType do objeto ProtoMessage para encontrar o seu tipo real. Através do SDK Google Protobuf, converta a ProtoMessage num objeto do tipo ProtoOA... necessário.
Os excertos de código abaixo demonstram como os SDKs oficiais da Open API abordam a leitura de mensagens.
_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);}
Exemplo Python
No exemplo Python, todas as operações com bytes na receção de mensagens são geridas pelo método dataReceived() como mostrado abaixo.
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)
Para enviar uma mensagem através de uma ligação WebSocket, execute as seguintes ações:
Serialize a mensagem em qualquer formato de dados adequado (por exemplo, uma string).
Adicione a mensagem serializada à sua fila de envio.
Os exemplos abaixo demonstram como estas ações são executadas nos SDKs oficiais da Open API.
O SDK C# utiliza a classe WebsocketClient que faz parte do pacote Websocket.Client. Como mostrado abaixo, o método WebsocketClient.Send() funciona da seguinte forma.
Para receber uma mensagem através de uma ligação WebSocket, faça o seguinte:
Recupere os dados recebidos do backend do cTrader.
Desserialize os dados numa mensagem Protobuf válida.
Para uma ilustração de como isto é feito nos SDKs oficiais da Open API, veja os excertos abaixo.
Para receber mensagens, um WebsocketClient precisa de estar subscrito a uma função de callback que gere o que o cliente faz ao aceitar uma nova mensagem.
Antes de subscrever, o SDK .NET analisa a mensagem numa mensagem Protobuf. As subscrições necessárias são adicionadas no corpo do callback ConnectWebSocket().