El proceso de enviar y recibir un mensaje difiere entre los estándares TCP y WebSocket. A continuación, explicamos este proceso en detalle para ambos tipos de conexiones.
Para enviar un mensaje a través de una conexión TCP, haga lo siguiente:
Cambie el mensaje Protobuf a una matriz de bytes (usando la codificación Protobuf) utilizando el SDK oficial de Google Protocol Buffer para su lenguaje de programación elegido.
Obtenga la longitud de la matriz creada durante el paso 1. Cree una nueva matriz de bytes a partir de este entero. Invierta la nueva matriz de bytes.
Concatene la nueva matriz de bytes y la matriz de bytes que contiene el mensaje Protobuf original.
Envíe la matriz concatenada al flujo de conexión.
Los ejemplos a continuación demuestran cómo se realizan estos pasos en los SDK oficiales de 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)
Ejemplo de Python
Usando Twisted, el ejemplo de Python realiza prácticamente las mismas operaciones que el de C#. El client.send(request) se puede explicar de la siguiente manera.
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 el mensaje, el SDK de Python utiliza el método Protocol.transport.write().
Todos los SDK de Open API se basan en la ejecución asíncrona, lo que significa que no esperan a que lleguen los mensajes, sino que reaccionan a los mensajes que llegan dinámicamente. Como resultado, la recepción de un mensaje se realiza normalmente a través de controladores de eventos
Para leer un mensaje, deberá realizar una secuencia de acciones que invierta los pasos necesarios para enviar un mensaje.
Reciba los primeros cuatro bytes de una matriz de bytes (recuerde, indican la longitud del mensaje). Invierta estos cuatro bytes y conviértalos en un número entero.
Lea X cantidad de bytes de un flujo donde X es el número entero que obtuvo durante el paso 1.
Utilice el SDK de Google Protobuf para deserializar el mensaje en un ProtoMessage válido.
Utilice el campo payloadType del objeto ProtoMessage para encontrar su tipo real. A través del SDK de Google Protobuf, cambie el ProtoMessage a un objeto del tipo ProtoOA... necesario.
Los fragmentos de código a continuación demuestran cómo los SDK oficiales de Open API abordan la lectura de mensajes.
_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);}
Ejemplo de Python
En el ejemplo de Python, todas las operaciones con bytes al recibir mensajes son manejadas por el método dataReceived() como se muestra a continuación.
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 un mensaje a través de una conexión WebSocket, realice las siguientes acciones:
Serialice el mensaje en cualquier formato de datos adecuado (por ejemplo, una cadena).
Agregue el mensaje serializado a su cola de envío.
Los ejemplos a continuación demuestran cómo se realizan estas acciones en los SDK oficiales de Open API.
El SDK de C# utiliza la clase WebsocketClient que es parte del paquete Websocket.Client. Como se muestra a continuación, el método WebsocketClient.Send() funciona de la siguiente manera.
Para recibir un mensaje a través de una conexión WebSocket, haga lo siguiente:
Recupere los datos recibidos del backend de cTrader.
Deserialice los datos en un mensaje Protobuf válido.
Para ver una ilustración de cómo se hace esto en los SDK oficiales de Open API, vea los fragmentos a continuación.
Para recibir mensajes, un WebsocketClient necesita estar suscrito a una función de devolución de llamada que maneje lo que hace el cliente al aceptar un nuevo mensaje.
Antes de suscribirse, el SDK de .NET analiza el mensaje en un mensaje Protobuf. Las suscripciones necesarias se agregan en el cuerpo de la devolución de llamada ConnectWebSocket().