TsgcWebTransportStream › Properties › Unidirectional

Unidirectional Property

True when the stream carries data one way only, False when both sides can write.

Syntax

property Unidirectional: Boolean read FUnidirectional;

Type

Boolean (bool in C++Builder and C#).

Default

Fixed at construction. For a stream you opened, it is the aUnidirectional argument you passed to Session.OpenStream. For a peer-opened stream, it is what the peer's stream header said: True after a 0x54 header, False after 0x41.

Remarks

Read-only. A stream's direction is decided when it is opened and cannot change: QUIC encodes it in the stream id itself, and WebTransport encodes it again in the stream header. Choose it by the argument you pass to OpenStream.

ValueHeaderWho may writeGood for
False (bidirectional)varint(0x41) + varint(SessionId)Both sidesRequest and response, echo, any exchange where you expect an answer on the same stream.
True (unidirectional)varint(0x54) + varint(SessionId)The opener onlyFire-and-forget: telemetry, log shipping, notifications, one-way media.

The property is per-object, not per-peer. This is the subtlety worth internalising. Unidirectional = True on a stream you opened means you can write and the peer cannot. The same flag on a stream you received through OnStream means the opposite for you: the peer writes, and your copy is receive-only. So Unidirectional alone does not tell you whether you may write; you also need to know which side opened it. In practice that is easy, because the two cases arrive through different routes: streams from OpenStream are yours to write, streams from OnStream are the peer's.

Writing to the wrong end fails quietly. Calling WriteData on the receiving end of a unidirectional stream raises no error. The HTTP/3 client and server bind a per-stream writer only to peer-opened bidirectional streams, so a peer-opened unidirectional stream keeps the session-level fallback writer and your bytes go somewhere unhelpful. Guard the echo path with if not aStream.Unidirectional then, as the shipping demos do.

Note that a unidirectional stream is not more efficient than a bidirectional one. Use it because your data genuinely flows one way, which makes the intent explicit and saves the peer from waiting for a reply channel that will never carry anything.

Example


// Opening: the argument decides the direction
FBidi := FSession.OpenStream(False);   // we can write, peer can answer
FBidi.OnData := OnStreamData;
FBidi.WriteData('request');

FTelemetry := FSession.OpenStream(True);   // we can write, peer only reads
FTelemetry.WriteData('telemetry: started');

// Receiving: the flag says what the PEER opened, so check before answering
procedure TfrmServer.OnWTStream(Sender: TObject;
  const aStream: TsgcWebTransportStream);
begin
  aStream.OnData := OnWTStreamData;
  if aStream.Unidirectional then
    memoLog.Lines.Add('peer opened a receive-only stream; we cannot answer on it')
  else
    memoLog.Lines.Add('peer opened a bidi stream; we can echo on it');
end;

procedure TfrmServer.OnWTStreamData(Sender: TObject; const aData: TBytes);
var
  oStream: TsgcWebTransportStream;
begin
  oStream := TsgcWebTransportStream(Sender);
  // Guard the echo: writing to a peer-opened unidirectional stream does
  // nothing useful and reports no error
  if not oStream.Unidirectional then
    oStream.WriteData(aData);
end;

Back to Properties