TsgcWebTransportStream › Ereignisse › OnWriteBytes
Transport-Hook. Der rohe Writer des Streams: jedes Byte, das der Stream sendet, läuft auf dem Weg zum zugrunde liegenden QUIC-Stream durch ihn hindurch.
property OnWriteBytes: TsgcWebTransportWriteEvent read FOnWriteBytes write FOnWriteBytes;
// event type
TsgcWebTransportWriteEvent = procedure(Sender: TObject;
const aData: TBytes) of object;
// handler signature
procedure MyWriteBytes(Sender: TObject; const aData: TBytes);
| Name | Typ | Beschreibung |
|---|---|---|
Sender | TObject | Der TsgcWebTransportStream, der schreibt. Anders als der Writer auf Sitzungsebene identifiziert dieser den Stream, was es dem Handler ermöglicht, den richtigen QUIC-Stream anzusprechen. Casten Sie ihn und lesen Sie StreamId. |
aData | const TBytes | Die exakten Bytes, die auf den QUIC-Stream geschrieben werden sollen. Schreiben Sie sie wortgetreu: kein Framing hinzuzufügen, nichts zu interpretieren. Dies ist entweder der WebTransport-Stream-Header beim ersten Aufruf oder Anwendungs-Payload aus WriteData. |
Wird von der Sitzung auf einen Fallback-Writer gesetzt, der über das OnWriteData auf Sitzungsebene läuft. Der Transport ersetzt ihn innerhalb von OnOpenStream durch einen Writer pro Stream, oder direkt nach AddIncomingStream bei einem vom Peer geöffneten bidirektionalen Stream.
Weisen Sie dies nicht aus Anwendungscode zu. Es handelt sich um einen Transport-Hook, der nur deshalb als Ereigniseigenschaft deklariert ist, weil eine einfache Pascal-Klasse auf diese Weise einen Callback entgegennimmt. Er ist auf jedem Stream, den Sie erreichen können, bereits zugewiesen, und ihn zu überschreiben zerstört den Stream: Ihre Bytes gehen dorthin, wohin Ihr Handler sie sendet, und das ist nicht der QUIC-Stream, den der Peer liest. Verwenden Sie WriteData, um Daten zu senden. Diese Seite existiert für Autoren eigener Transporte.
Alles, was der Stream sendet, läuft hier hindurch, einschließlich des WebTransport-Stream-Headers. OpenStream löst OnOpenStream aus, damit der Transport diesen Hook binden kann, und schreibt erst dann varint(0x54|0x41) + varint(SessionId), was beim frisch gebundenen Writer landet. Anwendungsbytes folgen bei späteren Aufrufen. Der Handler kann die beiden nicht unterscheiden und muss es auch nicht: Schreiben Sie unverändert, was auch immer ankommt.
Dies ist der Hook, der Streams unabhängig macht. Das sitzungsweite OnWriteData erhält ein Byte-Array und die Sitzung, ohne erkennen zu können, von welchem Stream die Bytes stammen, es kann daher nur in einen gemeinsamen Stream schreiben. OnWriteBytes erhält den Stream als Sender, sodass der Handler den passenden QUIC-Stream ermitteln und dorthin schreiben kann. Genau das gibt jedem WebTransport-Stream seinen eigenen QUIC-Stream und damit die Freiheit von Head-of-Line-Blocking, die WebTransport bieten soll.
Welche Streams einen echten Writer erhalten. Der HTTP/3-Client und -Server binden einen Writer pro Stream an Streams, die lokal über OpenStream geöffnet wurden, sowie an vom Peer geöffnete bidirektionale Streams, sodass ein Echo aus OnData auf demselben QUIC-Stream antwortet. Vom Peer geöffnete unidirektionale Streams dienen nur dem Empfang und behalten den Fallback-Writer: In einen solchen zu schreiben ist bedeutungslos und meldet keinen Fehler.
Ein robuster Handler ermittelt den QUIC-Stream anhand von StreamId und greift auf den Standard-Stream der Verbindung zurück, wenn das nicht möglich ist. Genau so verfährt der Writer der Bibliothek selbst, anstatt eine Ausnahme auszulösen.
Dieses Member ist derzeit nur in der Delphi/C++Builder-Implementierung verfügbar. Die .NET-Klasse besitzt eine entsprechende Eigenschaft internal WriteBytesHook, die aus Anwendungscode nicht zuweisbar ist. Dort ist sie ein einfaches Action<byte[]>, sodass der Delegat seinen QUIC-Stream einschließt, anstatt den Stream als Sender zu erhalten, und wenn er null ist, verwirft das verwaltete WriteData die Daten stillschweigend.
// What a custom QUIC transport assigns. This mirrors the library's own
// TsgcHTTP3Client_Base.DoWebTransportStreamWriteBytes. Applications call
// WriteData and never touch this.
procedure TMyTransport.DoOpenStream(Sender: TObject;
const aStream: TsgcWebTransportStream);
var
oQStream: TsgcSSLQUICStream;
begin
oQStream := GetQUICComponent.OpenStream(FHost, FPort, aStream.Unidirectional);
if Assigned(oQStream) then
begin
aStream.StreamId := oQStream.StreamId;
aStream.OnWriteBytes := DoStreamWriteBytes; // bind the per-stream writer
end;
end;
procedure TMyTransport.DoStreamWriteBytes(Sender: TObject; const aData: TBytes);
var
oWTStream: TsgcWebTransportStream;
oQStream: TsgcSSLQUICStream;
begin
// Sender identifies the stream, which is what makes this writer targeted
if not (Sender is TsgcWebTransportStream) then
Exit;
oWTStream := TsgcWebTransportStream(Sender);
oQStream := GetQUICComponent.FindStreamById(FHost, FPort, oWTStream.StreamId);
if Assigned(oQStream) then
// Write verbatim: aData is already exactly what belongs on the wire
GetQUICComponent.WriteStreamData(FHost, FPort, oQStream, aData)
else
// No dedicated QUIC stream: degrade to the default stream rather than raise
GetQUICComponent.Write(FHost, FPort, aData);
end;