WebTransport のデータグラム
WebTransport(ブラウザーとサーバーが HTTP/3 の上で双方向にやり取りするための API)のセッションでは、データグラムをやり取りできます。 データグラムは小さなメッセージで、順序の保証も再送もありません。 このページのサーバーは、受け取ったデータグラムを送り元のクライアントへそのまま返します。
コード
#define WIRED_MAIN#include "wired.h"
/* A browser (or any WebTransport client) opened a session on `path`. */static void on_session( void* ctx, wired_wt_session* s, wired_span path, wired_span protocol) { (void)ctx; (void)s; (void)protocol; wired_dprintf(2, "session %.*s\n", WIRED_SPAN_ARG(path));}
/* Echo every datagram back to the session it came from. */static void on_datagram(void* ctx, wired_wt_session* s, wired_span data) { (void)ctx; wired_server_wt_send_datagram_to(s, data);}
int wired_main(int argc, char** argv) { /* The same fixed demo identity as the HTTP/3 hello page. */ static wired_srvboot_demo_keys keys; wired_srvboot_id id; wired_srvboot_demo(&id, &keys, 0x50, "guide-wt"); id.max_datagram_frame_size = 65535; /* WebTransport requires DATAGRAM */
wired_srvrun_opt opt = {0}; opt.incoming_cpu = -1; opt.wt_on_session = on_session; opt.wt_on_datagram = on_datagram;
u16 port = (u16)wired_cliargs_int(argc, argv, "--port", 4433); wired_srvrun_handler h = {0}; wired_srvrun_obs obs = {0}; return wired_server_run_opt(port, &id, h, obs, &opt) ? 0 : 1;}クライアント
package main
import ( "context" "crypto/tls" "fmt" "net/http" "os"
"github.com/quic-go/quic-go" "github.com/quic-go/webtransport-go")
func main() { ctx := context.Background() var conn *quic.Conn // kept so main can close it before exiting d := webtransport.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // self-signed demo cert QUICConfig: &quic.Config{EnableDatagrams: true, EnableStreamResetPartialDelivery: true}, DialAddr: func(ctx context.Context, addr string, t *tls.Config, q *quic.Config) (*quic.Conn, error) { c, err := quic.DialAddrEarly(ctx, addr, t, q) conn = c return c, err }, } rsp, s, err := d.Dial(ctx, os.Args[1]+"/echo", http.Header{}) if err != nil { panic(err) } defer conn.CloseWithError(0, "") fmt.Println("status", rsp.StatusCode)
s.SendDatagram([]byte("ping")) fmt.Printf("sent %q\n", "ping") b, err := s.ReceiveDatagram(ctx) if err != nil { panic(err) } fmt.Printf("recv %q\n", b)}実行結果
$ ./wt-datagram --port 4433session /echoconn closed by peer (CONNECTION_CLOSE)$ go run . https://127.0.0.1:4433status 200sent "ping"recv "ping"wired_server_run_optは、wired_server_runにコールバックを加えたものです。opt.incoming_cpu = -1(「無効」を表す既定値)を設定してから、必要な WebTransport のフックを登録します。id.max_datagram_frame_size = 65535は、QUIC DATAGRAM(再送しないメッセージを運ぶ QUIC の拡張)に対応していることを告知します。 WebTransport のクライアントは、これがないサーバーとは接続しません。 サーバーがデータグラムを一度も送らない場合でも同じです。wt_on_sessionは、受け入れたセッションごとに 1 回、その:pathを引数に呼ばれます。wt_on_datagramは、受信したデータグラムを 1 つずつ渡します。dataが有効なのは、呼び出しのあいだだけです。wired_server_wt_send_datagram_to(s, data)は、1 つのセッションへの返信をキューに積みます(ペイロードはコピーされます)。 チャットのように接続中のすべてのクライアントへ同じデータグラムを送るときは、wired_server_broadcast_datagramかwired_server_broadcast_datagram_ringを使います。 前者は未送信のペイロードを 1 つだけ持ち、次の呼び出しで上書きされます。 後者はキューに積みますが、単一プロセスでしか使えません。- クライアントは QUIC コネクションを保持しておき、終了する前に閉じます。
そのため、サーバーはすぐに
conn closed by peerをログに出します。