TsgcWebTransportStream › Methoden › WriteData
Schreibt Anwendungsbytes in den Stream. Zwei Überladungen: rohe Bytes oder eine als UTF-8 kodierte Zeichenfolge.
procedure WriteData(const aData: TBytes); overload;
| Name | Typ | Beschreibung |
|---|---|---|
aData | const TBytes | Anwendungs-Payload, unverändert geschrieben. Es wird nichts hinzugefügt und nichts interpretiert, dies ist also die Überladung für Binärprotokolle und für Daten, die Sie bereits codiert haben. |
procedure WriteData(const aData: string); overload;
| Name | Typ | Beschreibung |
|---|---|---|
aData | const string | Text, der nach UTF-8 kodiert und anschließend geschrieben wird. Es gibt keine Byte Order Mark, keinen Terminator und kein Längenpräfix: genau die UTF-8-Bytes der Zeichenfolge. |
Beide Überladungen übergeben die Bytes an den Writer des Streams, OnWriteBytes, den der Transport an den zugrunde liegenden QUIC-Stream gebunden hat. Der WebTransport-Stream-Header wurde bereits von OpenStream geschrieben, was Sie hier übergeben, ist also reine Anwendungs-Payload. Die String-Überladung ist eine Vereinfachung gegenüber der Byte-Variante: Sie kodiert nach UTF-8 und ruft denselben Pfad auf.
Dies ist ein Byte-Stream, keine Nachrichten-Warteschlange. Das ist das Wichtigste, was Sie über WriteData wissen müssen. QUIC liefert Ihnen einen geordneten Bytestrom ohne Satzgrenzen, es gibt also keine Garantie, dass ein WriteData am anderen Ende zu einem OnData wird. Zwei Schreibvorgänge können zu einem Lesevorgang zusammenfallen, und ein Schreibvorgang kann auf mehrere aufgeteilt werden. Wenn Ihr Protokoll Nachrichten kennt, rahmen Sie diese ein: Längenpräfix, Trennzeichen oder Datensätze fester Größe. Kurze Testzeichenfolgen kommen meist vollständig an, genau deshalb zeigt sich das Problem erst später unter Last und nicht während der Entwicklung.
Es meldet nichts. Kein Rückgabewert, keine Ausnahme bei einem Fehlschlag und keine Zustellbestätigung. Ein Schreibvorgang auf einen Stream, dessen QUIC-Stream nicht geöffnet werden konnte, oder auf das empfangende Ende eines unidirektionalen Streams verläuft stillschweigend im Nichts. QUIC garantiert innerhalb eines Streams eine zuverlässige, geordnete Zustellung, sobald die Bytes angenommen wurden, aber wenn Sie wissen müssen, dass der Peer etwas verarbeitet hat, muss Ihr Protokoll das ausdrücken.
Prüfen Sie vor dem Schreiben die Richtung. Sie dürfen auf jeden von Ihnen geöffneten Stream schreiben sowie auf einen vom Peer geöffneten bidirektionalen Stream, bei dem der Transport einen Writer zurück an den QUIC-Stream des Peers bindet. Ein vom Peer geöffneter unidirektionaler Stream ist auf Ihrer Seite nur zum Empfangen: Ein Schreibvorgang darauf bewirkt nichts Sinnvolles und meldet keinen Fehler. Sichern Sie Ihren Echo-Pfad mit if not aStream.Unidirectional ab.
Das Schreiben nach Close wird nicht blockiert. Close setzt nur ein Flag und löst OnClose aus, sodass ein späteres WriteData den Writer weiterhin erreicht. Verlassen Sie sich nicht darauf.
Threading. Der Schreibpfad hält keine eigene Sperre, serialisieren Sie daher Ihre eigenen Schreibvorgänge auf einem bestimmten Stream. Unterschiedliche Streams schreiben auf unterschiedliche QUIC-Streams und konkurrieren nicht miteinander.
.NET-Unterschied. Wenn kein Writer gebunden ist, verwirft das verwaltete WriteData die Daten stillschweigend, und der Quellcode sagt das ausdrücklich. Das Verhalten entspricht im Ergebnis dem von Delphi; nur der Mechanismus unterscheidet sich.
var
oStream: TsgcWebTransportStream;
vRaw: TBytes;
begin
oStream := oSession.OpenStream(False);
oStream.OnData := OnStreamData; // assign BEFORE writing
// Text: encoded to UTF-8 for you, with no framing added
oStream.WriteData('Hello WebTransport');
// Binary: written byte for byte
vRaw := TEncoding.UTF8.GetBytes('{"action":"ping"}');
oStream.WriteData(vRaw);
end;
// Framing: because OnData does NOT preserve message boundaries, a real
// protocol prefixes each message with its length and reassembles on receipt.
procedure TfrmClient.SendMessage(const aStream: TsgcWebTransportStream;
const aMsg: string);
var
vBody, vFrame: TBytes;
vLen: Integer;
begin
vBody := TEncoding.UTF8.GetBytes(aMsg);
vLen := Length(vBody);
SetLength(vFrame, 4 + vLen);
vFrame[0] := Byte(vLen shr 24);
vFrame[1] := Byte(vLen shr 16);
vFrame[2] := Byte(vLen shr 8);
vFrame[3] := Byte(vLen);
if vLen > 0 then
Move(vBody[0], vFrame[4], vLen);
aStream.WriteData(vFrame);
end;