Frage

Dies ist eine Art Zweig von mir andere Frage. Lesen Sie es, wenn Sie möchten, aber es ist nicht notwendig.

Grundsätzlich wurde mir klar, dass ich (a) die Paketlänge zuerst lesen und genau so viele Bytes lesen muss oder (b) einen Paketlänge lesen muss oder (b) einen Paketlängenlimiter verwenden muss, um effektiv C#zu verwenden. Meine Frage ist, sind eine dieser diese in Protokollpuffern vorhanden? Ich habe sie noch nicht benutzt, aber die Dokumentation zu betreten, scheint es nicht so, als ob es einen Länge -Header oder einen Trennzeichen gibt.

Wenn nicht, was soll ich tun? Sollte ich die Nachricht einfach erstellen und sie dann mit dem Länge -Header/EOP -Abgrenzer des Länge oder des Länge?

War es hilfreich?

Lösung

Sie müssen die Größe oder den Endmarker in Ihr Protokoll einbeziehen. Nichts ist in Stream -basierte Sockets (TCP/IP) integriert, außer dass ein unbestimmter Strom von Oktetten willkürlich in separate Pakete unterteilt wird (und Pakete können auch während des Transports verschüttet werden).

Ein einfacher Ansatz wäre, dass jede "Nachricht" einen Header mit fester Größen -Header enthält, sowohl eine Protokollversion als auch eine Nutzlastgröße und alle anderen festen Daten enthalten. Dann der Nachrichteninhalt (Nutzlast).

Optional kann eine Meldung Fußzeile (feste Größe) mit einer Prüfsumme oder sogar einer kryptografischen Signatur hinzugefügt werden (abhängig von Ihren Zuverlässigkeits-/Sicherheitsanforderungen).

Wenn Sie die Nutzlastgröße kennen, können Sie weiterhin eine Reihe von Bytes lesen, die für den Rest der Nachricht ausreichen (und wenn eine Lektüre mit weniger abgeschlossen ist, lesen Sie eine weitere Lektüre für die verbleibenden Bytes, bis die gesamte Nachricht empfangen wurde).

Ein Endmeldungsindikator funktioniert auch, aber Sie müssen definieren, wie Sie mit Ihrer Nachricht umgehen, die dieselbe Oktettsequenz enthält ...

Andere Tipps

Entschuldigung, dass Sie spät auf der Party angekommen sind. Ich bin der Autor von Protobuf-Net, einem der C# -Implementierungen. Für die Netzwerknutzung sollten Sie die Methoden [de] serializeWithLengthPrefix" berücksichtigen. Auf diese Weise wird automatisch die für Sie verarbeitet. Es gibt Beispiele in der Quelle.

Ich werde in einem alten Beitrag nicht auf große Details eingehen, aber wenn Sie mehr wissen möchten, fügen Sie einen Kommentar hinzu und ich werde mich bei Ihnen melden.

Ich stimme Matt zu, dass ein Header besser als eine Fußzeile für Protokollpuffer ist, aus dem Hauptgrund, dass PB ein binäres Protokoll problematisch ist, eine Fußzeile zu finden, die auch keine gültige Nachrichtensequenz wäre. Viele Fußzeile -basierte Protokolle (typischerweise EOL) funktionieren, da sich der Nachrichteninhalt in einem definierten Bereich befindet (typischerweise 0x20 - 0x7f ASCII).

Ein nützlicher Ansatz besteht darin, dass der Code mit niedrigster Ebene nur Puffer aus dem Socket lesen und sie einer Rahmenschicht präsentiert, die vollständige Nachrichten zusammenbringt und sich an die Teiler erinnert (ich präsentiere einen asynchronen Ansatz dafür (mit dem CCR) hier, wenn auch für ein Linienprotokoll).

Für die Konsistenz können Sie Ihre Nachricht immer als PB-Nachricht mit drei Feldern definieren: eine feste Stelle als Länge, einen Enum als Typ und eine Byte-Sequenz, die die tatsächlichen Daten enthält. Dies hält Ihr gesamtes Netzwerkprotokoll transparent.

TCP/IP sowie UDP enthalten Pakete einen Hinweis auf ihre Größe. Das IP -Header Enthält ein 16-Bit-Feld, das die Länge des IP-Headers angibt und Daten in Bytes. Das TCP -Header Enthält ein 4-Bit-Feld, das die Größe des TCP-Headers in 32-Bit-Wörtern angibt. Das UDP -Header Enthält ein 16-Bit-Feld, das die Länge des UDP-Headers angibt und Daten in Bytes.

Hier ist das Ding.

Verwenden Sie die Standard-Steckdosen in Windows, unabhängig davon, ob Sie das system.net.sockets Namespace in C# oder das native Winsock-Material in Win32 verwenden, nie die IP/TCP/UDP-Header. Diese Header werden abgezogen, so dass das, was Sie beim Lesen der Socket erhalten, die tatsächliche Nutzlast ist, dh die gesendeten Daten.

Das typische Muster von allem, was ich je gesehen und mit Steckdosen getan habe, besteht darin, dass Sie einen Header auf Anwendungsebene definieren, der den Daten vorausgeht, die Sie senden möchten. Zumindest sollte dieser Header die zu folgende Größe der Daten enthalten. Auf diese Weise können Sie jede "Nachricht" in ihrer Gesamtheit lesen, ohne dass Sie sich über ihre Größe erraten müssen. Sie können so schick werden, wie Sie damit möchten, z. B. Synchronisierungsmuster, CRCs, Version, Art der Nachricht usw., aber die Größe der "Nachricht" ist alles Ja wirklich brauchen.

Und für das, was es wert ist, würde ich vorschlagen, einen Header anstelle eines Trennzeichens zu verwenden. Ich bin mir nicht sicher, ob der EOP -Trennzeichen einen signifikanten Nachteil hat, aber der Header ist der Ansatz, den die meisten IP -Protokolle, die ich gesehen habe, verwendet. Außerdem erscheint es mir intuitiver, eine Nachricht von Anfang an zu verarbeiten, anstatt zu warten, bis ein Muster in meinem Stream angezeigt wird, um anzuzeigen, dass meine Nachricht vollständig ist.

Bearbeiten: Ich bin gerade erst das Google Protocol Puffer -Projekt bewusst. Soweit ich das beurteilen kann, handelt es sich um ein Binär-Serialisierungs-/De-Serialisierungsschema für WCF (ich bin sicher, das ist eine grobe Unvereinbarkeit). Wenn Sie WCF verwenden, müssen Sie sich keine Sorgen über die Größe der gesendeten Nachrichten machen Pufferdokumentation. Bei Steckdosen wird das Wissen, die Größe zu kennen, jedoch enorm hilft, wie oben erläutert. Ich vermute, dass Sie Ihre Daten mithilfe der Protokollpuffer serialisieren und dann auf den Anwendungsheader hindern, den Sie vor dem Senden erstellen. Auf der Empfangsseite ziehen Sie den Kopfball ab und de-serialisieren den Rest der Nachricht.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top