2009-02-25 6 views
6

Questo è un tipo di filiale del mio other question. Leggilo se vuoi, ma non è necessario.Come rilevare quando un messaggio di protocollo buffer viene ricevuto completamente?

Fondamentalmente, ho capito che al fine di utilizzare efficacemente BeginReceive() C# s 'su grandi messaggi, devo (a) leggere la lunghezza del pacchetto prima, quindi leggere esattamente quel numero di byte o (b) utilizzare un end-of -ilimitatore del pacchetto. La mia domanda è, sono entrambi presenti nei buffer di protocollo? Non li ho ancora usati, ma esaminando la documentazione non sembra che ci sia un'intestazione di lunghezza o un delimitatore.

In caso negativo, cosa devo fare? Dovrei semplicemente creare il messaggio quindi prefisso/suffisso con l'intestazione lunghezza/delimitatore EOP?

risposta

14

È necessario includere la dimensione o il marcatore di fine nel protocollo. Nulla è integrato in socket basati su stream (TCP/IP) diversi dal supportare un flusso indefinito di ottetti suddivisi arbitrariamente in pacchetti separati (e anche i pacchetti possono essere versati in transito).

Un approccio semplice sarebbe che ogni "messaggio" avesse un'intestazione di dimensione fissa, includendo sia una versione di protocollo che una dimensione di carico utile e qualsiasi altro dato fisso. Quindi il contenuto del messaggio (payload).

È possibile aggiungere un footer di messaggi (dimensione fissa) con un checksum o anche una firma crittografica (in base ai requisiti di affidabilità/sicurezza).

Conoscere la dimensione del carico utile consente di continuare a leggere un numero di byte che sarà sufficiente per il resto del messaggio (e se una lettura viene completata con meno, facendo un'altra lettura per i restanti byte fino a quando non viene ricevuto l'intero messaggio).

Avere un indicatore di messaggio di fine funziona anche, ma è necessario definire come gestire il vostro messaggio contenente la stessa sequenza ottetto ...

1

TCP/IP, così come UDP, i pacchetti includono qualche riferimento alla loro dimensione . Lo IP header contiene un campo a 16 bit che specifica la lunghezza dell'intestazione IP e in byte. Lo TCP header contiene un campo a 4 bit che specifica la dimensione dell'intestazione TCP nelle parole a 32 bit. Lo UDP header contiene un campo a 16 bit che specifica la lunghezza dell'intestazione UDP e in byte.

Ecco la cosa.

Utilizzando i socket standard run-of-the-mill in Windows, sia che si utilizzi lo spazio dei nomi System.Net.Sockets in C# o la roba Winsock nativa in Win32, non si vedono mai le intestazioni IP/TCP/UDP . Queste intestazioni vengono eliminate in modo tale che ciò che ottieni quando leggi il socket è il carico utile effettivo, cioè i dati inviati.

Lo schema tipico di tutto ciò che ho visto e fatto utilizzando i socket è che si definisce un'intestazione a livello di applicazione che precede i dati che si desidera inviare. Come minimo, questa intestazione dovrebbe includere la dimensione dei dati da seguire. Questo ti permetterà di leggere ogni "messaggio" nella sua interezza senza dover indovinare la sua dimensione. Puoi avere la fantasia che desideri con esso, ad es. Modelli di sincronizzazione, CRC, versione, tipo di messaggio, ecc., Ma la dimensione del "messaggio" è tutta che hai bisogno di .

E per quello che vale, suggerirei di utilizzare un'intestazione anziché un delimitatore di fine pacchetto. Non sono sicuro se ci sia uno svantaggio significativo per il delimitatore EOP, ma l'intestazione è l'approccio utilizzato dalla maggior parte dei protocolli IP che ho visto.Inoltre, mi sembra più intuitivo elaborare un messaggio dall'inizio piuttosto che attendere che alcuni pattern appaiano nel mio stream per indicare che il mio messaggio è completo.

EDIT: Mi sono appena reso conto del progetto Buffers del protocollo Google. Da quello che posso dire, è uno schema di serializzazione/de-serializzazione binaria per WCF (sono sicuro che sia una grossolana semplificazione). Se si sta utilizzando WCF, non è necessario preoccuparsi della dimensione dei messaggi inviati perché l'impianto idraulico WCF si occupa di ciò dietro le quinte, il che probabilmente è il motivo per cui non è stato trovato nulla correlato alla lunghezza del messaggio nel protocollo Documentazione dei buffer Tuttavia, nel caso di prese, conoscere le dimensioni aiuterà enormemente come discusso sopra. La mia ipotesi è che serializziate i vostri dati usando i Protocol Buffers e poi virate su qualunque intestazione dell'applicazione vi venga in mente prima di inviarli. Sul lato ricevente, si estrae l'intestazione e quindi deserializzare il resto del messaggio.

+0

Se si intende protobuf-net, no non è solo per WCF; ci sono esempi di prese nel progetto. –

3

Sono d'accordo con Matt sul fatto che un'intestazione sia migliore di un footer per i Protocol Buffers, per il motivo principale che, poiché PB è un protocollo binario, è problematico creare un footer che non sia anche una sequenza di messaggi valida. Molti protocolli basati su piè di pagina (in genere EOL) funzionano perché il contenuto del messaggio si trova in un intervallo definito (in genere 0x20 - 0x7F ASCII).

Un approccio utile consiste nell'avere il codice di livello più basso in grado di leggere i buffer fuori dal socket e presentarli a un livello di frame che assembla messaggi completi e ricorda quelli parziali (presento un approccio asincrono a questo (utilizzando il CCR) here, anche se per un protocollo di linea).

Per coerenza, è sempre possibile definire il messaggio come messaggio PB con tre campi: un fisso-int come lunghezza, un enum come tipo e una sequenza di byte che contiene i dati effettivi. Ciò mantiene trasparente l'intero protocollo di rete.

6

Ci scusiamo per l'arrivo in ritardo alla festa. Sono l'autore di protobuf-net, una delle implementazioni di C#. Per l'utilizzo della rete, dovresti considerare i metodi "[De] SerializeWithLengthPrefix" - in questo modo, gestirà automaticamente le lunghezze per te. Ci sono esempi nella fonte.

Non entrerò nei dettagli di un vecchio post, ma se volete saperne di più, aggiungete un commento e tornerò da voi.

Problemi correlati