TsgcWebTransportSession

TsgcWebTransportSession repräsentiert eine WebTransport-Sitzung und besitzt die Streams, die darin über eine einzige HTTP/3-QUIC-Verbindung multiplext werden.

Einführung

Eine WebTransport-Sitzung wird durch eine Extended CONNECT-Anfrage (RFC 9220) aufgebaut, die :protocol = webtransport trägt. TsgcWebTransportSession ist das Objekt, das sie repräsentiert, sobald der Handshake erfolgreich war. Es ist in der Unit sgcWebTransport deklariert und ist eine einfache Klasse, keine Komponente: Sie legen es nicht auf einem Formular ab und Sie erzeugen es nicht selbst. Es erreicht Sie auf eine von zwei Arten:

In beiden Fällen gehört die Sitzung der Sitzungsregistrierung der Verbindung, die sie freigibt. Geben Sie sie nicht selbst frei. Auf dem Client gibt das Freigeben von TsgcHTTP3Client jede von ihm geöffnete Sitzung frei, und jede Sitzung gibt ihre Streams frei.

Die Sitzung multiplext beliebig viele TsgcWebTransportStream-Objekte. Öffnen Sie einen mit OpenStream; Streams, die der Peer öffnet, treffen über OnStream ein. Die Sitzung selbst besitzt keine Lese- oder Schreibmethode für Anwendungsdaten: Die gesamte Payload wird über Streams übertragen.

Sitzungsidentität

SessionId ist die QUIC-Stream-ID der Extended-CONNECT-Anfrage, die die Sitzung erstellt hat. Sie verankert die gesamte Sitzung auf der Leitung: Jedem WebTransport-Stream, der darin geöffnet wird, wird varint(0x54) oder varint(0x41) gefolgt von varint(SessionId) vorangestellt, so weiß die empfangende Seite, zu welcher Sitzung ein neuer QUIC-Stream gehört. QuarterStreamId ist dieselbe Identität in der kompakten Form, die die Datagramm-Schicht verwendet, SessionId div 4.

Nur Streams

Die Sitzung stellt SendDatagram und OnDatagram bereit, aber kein ausgeliefertes Backend kann ein Datagramm übertragen: SendDatagram löst TsgcQUICException aus, statt Ihre Payload stillschweigend zu verlieren, und OnDatagram wird nie ausgelöst. Siehe WebTransport für die vollständige Erklärung. Bauen Sie Ihr Protokoll auf Streams auf.

Referenz

Wichtige Eigenschaften

NameBeschreibung
SessionIdQUIC-Stream-ID der Extended-CONNECT-Anfrage, die diese Sitzung aufgebaut hat.
QuarterStreamIdSessionId div 4, die Sitzungsidentität, wie sie in WebTransport-Datagrammen kodiert ist.
StreamCountAnzahl der aktuell auf dieser Sitzung geöffneten Streams.
DatagramsSupportedOb der an diese Sitzung gebundene Transport wirklich ein Datagramm auf die Leitung legen kann. False bei jedem ausgelieferten Transport.

Wichtige Methoden

NameBeschreibung
OpenStreamÖffnet einen neuen ausgehenden Stream, bidirektional oder unidirektional, und sendet dessen WebTransport-Header.
FindStreamByIdGibt den Stream mit der angegebenen QUIC-Stream-ID zurück oder nil.
CloseSchließt die offenen Streams der Sitzung und löst OnClose aus. Die QUIC-Verbindung wird dabei nicht abgebaut.
SendDatagramSendet ein WebTransport-Datagramm. Löst im Auslieferungszustand eine TsgcQUICException aus, da kein Transport eines übertragen kann.

Wichtige Ereignisse

NameBeschreibung
OnStreamWird ausgelöst, wenn der Peer einen neuen Stream innerhalb dieser Sitzung öffnet.
OnCloseWird ausgelöst, wenn Close für diese Sitzung aufgerufen wird.
OnDatagramWürde ein eingehendes Datagramm liefern. Wird in der ausgelieferten Version nie ausgelöst.

Vollständiges Beispiel

Ein vollständiger Client-Roundtrip gegen einen WebTransport-Echo-Server: verbinden, einen bidirektionalen Stream öffnen, schreiben, das Echo über OnData lesen, dann schließen. Die QUIC-Verbindung ist nicht-blockierend, daher pumpt ein Timer sie mit WebTransportProcessEvents; ohne diese Pumpe werden nie Daten gelesen.


unit FWebTransportClient;

interface

uses
  Classes, SysUtils, Forms, StdCtrls, ExtCtrls,
  // sgc
  sgcHTTP, sgcHTTP3_Classes, sgcHTTP3_Types, sgcWebTransport;

type
  TfrmClient = class(TForm)
    memoLog: TMemo;
    tmrPump: TTimer;
    btnConnect: TButton;
    btnClose: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnConnectClick(Sender: TObject);
    procedure btnCloseClick(Sender: TObject);
    procedure tmrPumpTimer(Sender: TObject);
  private
    FClient: TsgcHTTP3Client;
    FSession: TsgcWebTransportSession;
    FStream: TsgcWebTransportStream;
    procedure OnStreamData(Sender: TObject; const aData: TBytes);
    procedure OnStreamClose(Sender: TObject);
    procedure OnSessionClose(Sender: TObject);
  end;

implementation

{$R *.dfm}

procedure TfrmClient.FormCreate(Sender: TObject);
begin
  FClient := TsgcHTTP3Client.Create(nil);
  FClient.TLSOptions.VerifyCertificate := False;   // self-signed test cert
  FClient.ConnectTimeout := 10000;
  FClient.UserAgent := 'sgcWebSockets/WebTransportClient';

  tmrPump.Interval := 50;
  tmrPump.Enabled := False;
end;

procedure TfrmClient.FormDestroy(Sender: TObject);
begin
  tmrPump.Enabled := False;
  // FSession is owned by FClient.WebTransportSessions and FStream is owned by
  // the session, so freeing the client releases both.
  FClient.Free;
end;

procedure TfrmClient.btnConnectClick(Sender: TObject);
begin
  // Opens a dedicated QUIC connection and performs the Extended CONNECT
  // (:protocol=webtransport). Returns nil when the server rejects the session
  // or does not support WebTransport.
  FSession := FClient.WebTransportConnect('https://127.0.0.1:4433/echo');
  if not Assigned(FSession) then
  begin
    memoLog.Lines.Add('WebTransport connect failed. ServerSupportsWebTransport=' +
      BoolToStr(FClient.ServerSupportsWebTransport, True));
    Exit;
  end;

  memoLog.Lines.Add('session established: id=' + IntToStr(FSession.SessionId));
  FSession.OnClose := OnSessionClose;

  // False = bidirectional, so the server can answer on the same stream.
  FStream := FSession.OpenStream(False);
  FStream.OnData := OnStreamData;
  FStream.OnClose := OnStreamClose;
  memoLog.Lines.Add('bidi stream opened: id=' + IntToStr(FStream.StreamId));

  // Start pumping BEFORE writing, so the echo cannot be missed.
  tmrPump.Enabled := True;

  FStream.WriteData('Hello WebTransport');   // UTF-8 encoded for you
  memoLog.Lines.Add('sent: Hello WebTransport');
end;

procedure TfrmClient.tmrPumpTimer(Sender: TObject);
begin
  // Reads peer packets and harvests peer-opened streams. Nothing arrives
  // without this call.
  FClient.WebTransportProcessEvents;
end;

procedure TfrmClient.OnStreamData(Sender: TObject; const aData: TBytes);
var
  oStream: TsgcWebTransportStream;
begin
  oStream := TsgcWebTransportStream(Sender);
  memoLog.Lines.Add('echo on stream ' + IntToStr(oStream.StreamId) + ': ' +
    TEncoding.UTF8.GetString(aData));
end;

procedure TfrmClient.OnStreamClose(Sender: TObject);
begin
  memoLog.Lines.Add('stream closed');
end;

procedure TfrmClient.OnSessionClose(Sender: TObject);
begin
  memoLog.Lines.Add('session closed');
end;

procedure TfrmClient.btnCloseClick(Sender: TObject);
begin
  tmrPump.Enabled := False;
  if Assigned(FStream) then
    FStream.Close;     // fires OnStreamClose
  if Assigned(FSession) then
    FSession.Close;    // fires OnSessionClose
end;

end.

Anforderungen