Le processus d'envoi et de réception d'un message diffère entre les normes TCP et WebSocket. Ci-dessous, nous expliquons ce processus en détail pour les deux types de connexions.
Pour envoyer un message via une connexion TCP, procédez comme suit :
Transformez le message Protobuf en un tableau d'octets (en utilisant l'encodage Protobuf) en utilisant le SDK officiel Google Protocol Buffer pour le langage de programmation de votre choix.
Obtenez la longueur du tableau créé à l'étape 1. Créez un nouveau tableau d'octets à partir de cet entier. Inversez le nouveau tableau d'octets.
Concaténez le nouveau tableau d'octets et le tableau d'octets contenant le message Protobuf original.
Envoyez le tableau concaténé au flux de connexion.
Les exemples ci-dessous montrent comment ces étapes sont effectuées dans les SDK officiels de l'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)
Exemple Python
En utilisant Twisted, l'exemple Python effectue presque les mêmes opérations que celui en C#. Le client.send(request) peut être expliqué comme suit.
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
Pour envoyer le message, le SDK Python utilise la méthode Protocol.transport.write().
Tous les SDK Open API reposent sur une exécution asynchrone, ce qui signifie qu'ils n'attendent pas l'arrivée des messages mais, au contraire, réagissent aux messages arrivant dynamiquement. Par conséquent, la réception d'un message se fait généralement via des gestionnaires d'événements
Pour lire un message, vous devrez effectuer une séquence d'actions qui inverse les étapes requises pour envoyer un message.
Recevez les quatre premiers octets d'un tableau d'octets (rappelez-vous, ils indiquent la longueur du message). Inversez ces quatre octets et transformez-les en un entier.
Lisez X octets à partir d'un flux où X est l'entier que vous avez obtenu à l'étape 1.
Utilisez le SDK Google Protobuf pour désérialiser le message en un ProtoMessage valide.
Utilisez le champ payloadType de l'objet ProtoMessage pour trouver son type réel. Via le SDK Google Protobuf, transformez le ProtoMessage en un objet du type ProtoOA... nécessaire.
Les extraits de code ci-dessous montrent comment les SDK officiels de l'Open API abordent la lecture des 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);}
Exemple Python
Dans l'exemple Python, toutes les opérations avec les octets lors de la réception des messages sont gérées par la méthode dataReceived() comme montré ci-dessous.
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)
Pour envoyer un message via une connexion WebSocket, effectuez les actions suivantes :
Sérialisez le message dans n'importe quel format de données approprié (par exemple, une chaîne).
Ajoutez le message sérialisé à votre file d'attente d'envoi.
Les exemples ci-dessous montrent comment ces actions sont effectuées dans les SDK officiels de l'Open API.
Le SDK C# utilise la classe WebsocketClient qui fait partie du package Websocket.Client. Comme montré ci-dessous, la méthode WebsocketClient.Send() fonctionne comme suit.
Pour recevoir un message via une connexion WebSocket, procédez comme suit :
Récupérez les données reçues de l'arrière-plan de cTrader.
Désérialisez les données en un message Protobuf valide.
Pour une illustration de la façon dont cela est fait dans les SDK officiels de l'Open API, voir les extraits ci-dessous.
Pour recevoir des messages, un WebsocketClient doit être abonné à une fonction de callback qui gère ce que le client fait lors de l'acceptation d'un nouveau message.
Avant de s'abonner, le SDK .NET analyse le message en un message Protobuf. Les abonnements nécessaires sont ajoutés dans le corps du callback ConnectWebSocket().