TsgcWebTransportStream › Methods › WriteData

WriteData Method

Writes application bytes to the stream. Two overloads: raw bytes, or a string encoded as UTF-8.

Syntax

WriteData(const aData: TBytes) TBytes overload

procedure WriteData(const aData: TBytes); overload;

Parameters

NameTypeDescription
aDataconst TBytesApplication payload, written unchanged. Nothing is added or interpreted, so this is the overload for binary protocols and for data you have already encoded.

WriteData(const aData: string) string overload

procedure WriteData(const aData: string); overload;

Parameters

NameTypeDescription
aDataconst stringText, encoded to UTF-8 and then written. There is no byte-order mark, no terminator and no length prefix: exactly the UTF-8 bytes of the string.

Remarks

Both overloads hand the bytes to the stream's writer, OnWriteBytes, which the transport bound to the backing QUIC stream. The WebTransport stream header was already written by OpenStream, so what you pass here is pure application payload. The string overload is a convenience over the byte one: it encodes to UTF-8 and calls the same path.

This is a byte stream, not a message queue. The single most important thing to know about WriteData. QUIC gives you an ordered stream of bytes with no record boundaries, so there is no guarantee that one WriteData becomes one OnData at the far end. Two writes may coalesce into one read, and one write may be split across several. If your protocol has messages, frame them: length prefix, delimiter, or fixed-size records. Short test strings usually arrive whole, which is exactly why this bites later, under load, rather than during development.

It reports nothing. No return value, no exception on failure, and no delivery confirmation. Writing to a stream whose QUIC stream failed to open, or to the receiving end of a unidirectional stream, silently goes nowhere. QUIC guarantees reliable, ordered delivery within a stream once the bytes are accepted, but if you need to know the peer processed something, your protocol must say so.

Check the direction before writing. You may write to any stream you opened, and to a peer-opened bidirectional stream, where the transport binds a writer back to the peer's QUIC stream. A peer-opened unidirectional stream is receive-only at your end: writing to it does nothing useful and reports no error. Guard your echo path with if not aStream.Unidirectional.

Writing after Close is not blocked. Close only sets a flag and raises OnClose, so a later WriteData still reaches the writer. Do not rely on that.

Threading. The write path holds no lock of its own, so serialise your own writes to a given stream. Different streams write to different QUIC streams and do not contend.

.NET difference. When no writer is bound, the managed WriteData silently discards the data, and the source says so explicitly. The behaviour matches Delphi in effect; only the mechanism differs.

Example


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;

Back to Methods