Il processo di invio e ricezione di un messaggio differisce tra gli standard TCP e WebSocket. Di seguito, spieghiamo questo processo in dettaglio per entrambi i tipi di connessioni.
Per inviare un messaggio tramite una connessione TCP, fai quanto segue:
Cambia il messaggio Protobuf in un array di byte (usando la codifica Protobuf) utilizzando l'SDK ufficiale di Google Protocol Buffer per il linguaggio di programmazione scelto.
Ottieni la lunghezza dell'array creato durante il passo 1. Crea un nuovo array di byte da questo intero. Inverti il nuovo array di byte.
Concatena il nuovo array di byte e l'array di byte contenente il messaggio Protobuf originale.
Invia l'array concatenato allo stream di connessione.
Gli esempi seguenti dimostrano come questi passaggi vengono eseguiti negli SDK Open API ufficiali.
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)
Esempio Python
Usando Twisted, l'esempio Python esegue quasi le stesse operazioni di quello C#. Il client.send(request) può essere spiegato come segue.
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
Per inviare il messaggio, l'SDK Python utilizza il metodo Protocol.transport.write().
Tutti gli SDK Open API si basano sull'esecuzione asincrona, il che significa che non attendono l'arrivo dei messaggi ma, invece, reagiscono ai messaggi che arrivano dinamicamente. Di conseguenza, la ricezione di un messaggio viene tipicamente effettuata tramite gestori di eventi
Per leggere un messaggio, dovrai eseguire una sequenza di azioni che inverte i passaggi richiesti per l'invio di un messaggio.
Ricevi i primi quattro byte di un array di byte (ricorda, denotano la lunghezza del messaggio). Inverti questi quattro byte e cambiali in un intero.
Leggi X quantità di byte da uno stream dove X è l'intero che hai ottenuto durante il passo 1.
Usa l'SDK Google Protobuf per deserializzare il messaggio in un ProtoMessage valido.
Usa il campo payloadType dell'oggetto ProtoMessage per trovare il suo tipo effettivo. Tramite l'SDK Google Protobuf, cambia il ProtoMessage in un oggetto del tipo ProtoOA... necessario.
Gli snippet di codice seguenti dimostrano come gli SDK Open API ufficiali affrontano la lettura dei messaggi.
_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);}
Esempio Python
Nell'esempio Python, tutte le operazioni con i byte sulla ricezione dei messaggi sono gestite dal metodo dataReceived() come mostrato di seguito.
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)
Per inviare un messaggio su una connessione WebSocket, esegui le seguenti azioni:
Serializza il messaggio in qualsiasi formato dati adatto (ad esempio, una stringa).
Aggiungi il messaggio serializzato alla tua coda di invio.
Gli esempi seguenti dimostrano come queste azioni vengono eseguite negli SDK Open API ufficiali.
L'SDK C# utilizza la classe WebsocketClient che fa parte del pacchetto Websocket.Client. Come mostrato di seguito, il metodo WebsocketClient.Send() funziona come segue.
Per ricevere un messaggio su una connessione WebSocket, fai quanto segue:
Recupera i dati ricevuti dal backend di cTrader.
Deserializza i dati in un messaggio Protobuf valido.
Per un'illustrazione di come questo viene fatto negli SDK Open API ufficiali, vedi gli snippet seguenti.
Per ricevere messaggi, un WebsocketClient deve essere sottoscritto a una funzione di callback che gestisce ciò che il client fa all'accettazione di un nuovo messaggio.
Prima di sottoscriversi, l'SDK .NET analizza il messaggio in un messaggio Protobuf. Le sottoscrizioni necessarie vengono aggiunte nel corpo del callback ConnectWebSocket().