Come utilizzare Python e di Google buffer protocollo per deserializzare i dati inviati attraverso il protocollo TCP

StackOverflow https://stackoverflow.com/questions/2038083

  •  19-09-2019
  •  | 
  •  

Domanda

Sto cercando di scrivere un'applicazione che utilizza i buffer di protocollo di Google per deserializzare i dati (inviati da un'altra applicazione che utilizza i buffer di protocollo) su una connessione TCP. Il problema è che sembra come se i buffer di protocollo in Python possono deserializzare solo i dati da una stringa. Dal momento che il protocollo TCP non avere confini dei messaggi ben definiti e uno dei messaggi che sto cercando di ricevere ha un campo ripetuto, non voglio sapere la quantità di dati per cercare di ricevere prima infine passando la stringa da deserializzato.

Ci sono delle buone pratiche per fare questo in Python?

È stato utile?

Soluzione

Non basta scrivere i dati serializzati al socket. Prima di inviare un campo di dimensione fissa contenente la lunghezza dell'oggetto serializzato.

Il lato di invio è grosso modo:

socket.write(struct.pack("H", len(data))    #send a two-byte size field
socket.write(data)

E il lato recv'ing diventa qualcosa di simile a:

dataToRead = struct.unpack("H", socket.read(2))[0]    
data = socket.read(dataToRead)

Questo è un modello di progettazione comune per la programmazione socket. La maggior parte dei disegni estendono la struttura over-the-wire per includere un campo di tipo così, in modo che il lato ricevente diventa qualcosa di simile a:

type = socket.read(1)                                 # get the type of msg
dataToRead = struct.unpack("H", socket.read(2))[0]    # get the len of the msg
data = socket.read(dataToRead)                        # read the msg

if TYPE_FOO == type:
    handleFoo(data)

elif TYPE_BAR == type:
    handleBar(data)

else:
    raise UnknownTypeException(type)

Si finisce con un formato di messaggio di over-the-wire che assomiglia a:

struct {
     unsigned char type;
     unsigned short length;
     void *data;
}

Questo fa un lavoro ragionevole di a prova di futuro il protocollo filo contro esigenze impreviste. E 'un Tipo-Lunghezza-Valore protocollo , che troverai ancora e ancora e di nuovo nel protocolli di rete.

Altri suggerimenti

per espandere (del tutto corretto) la risposta di JJ, la biblioteca protobuf ha alcun modo per capire quanto tempo i messaggi sono da soli, o di capire che tipo di oggetto è essere protobuf inviato*. Così l'altra applicazione che è l'invio di voi dati deve essere già facendo qualcosa di simile.

Quando ho dovuto fare questo, ho realizzato una tabella di ricerca:

messageLookup={0:foobar_pb2.MessageFoo,1:foobar_pb2.MessageBar,2:foobar_pb2.MessageBaz}

... e ha fatto in sostanza quello che J.J. ha fatto, ma ho avuto anche una funzione di supporto:

    def parseMessage(self,msgType,stringMessage):
        msgClass=messageLookup[msgType]
        message=msgClass()
        message.ParseFromString(stringMessage)
        return message

... che ho chiamato per trasformare la stringa in un oggetto protobuf.

(*) penso che sia possibile aggirare questo incapsulando messaggi specifici all'interno di un messaggio contenitore

Un altro aspetto da considerare (anche se per un caso più semplice) è dove si utilizza una singola connessione TCP per un singolo messaggio. In questo caso, fino a quando si sa che cosa il messaggio di attesa è (o utilizzare Tipi dell'Unione per determinare il tipo di messaggio in fase di esecuzione), è possibile utilizzare la connessione TCP aperta come la 'start' delimitatore, e la connessione stretta evento come delimitatore finale. Questo ha il vantaggio che riceverai l'intero messaggio velocemente (mentre in altri casi il flusso TCP può essere tenuto per un certo tempo, ritardando il ricevimento del vostro intero messaggio). Se si esegue questa operazione, non è necessario alcun esplicito inquadratura in-band, come la durata degli atti di connessione TCP come un telaio stesso.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top