The problem is that for WebRTC to work, you need a signaling-server anyway which would then again run over websockets, SSE or WebTransport. This defeats the purpose of using WebRTC as a replacement for these technologies.
This is dismissive and incorrect. Firstly: websockets, SSE, and webTransport are not required for signaling server, you can use a few http requests/polling instead. Second and most importantly: a WebRTC connected client itself can act as a signaling server. After the bootstrap any client can now be part of your mesh of servers. Services also gain more load balancing, failover and routing capabilities. You may want to reconsider your standing here.
a WebRTC connected client itself can act as a signaling server
I am very curious about WebRTC from a practical perspective. Do you have any good guides, resources, projects, or libraries that discuss the above? More generally, what is the best way to establish real-time connections between browsers these days?
If Web-Transport is specific to HTTP 3, does it not work on earlier versions? That’d be surprising, because for other web APIs, an app author rarely feels if they’ve been proxied with HTTP/1.1 or not.
Like so many of these things, WebTransport is intentionally confusingly named to make it feel like web-tech. It is essentially “just” raw QUIC sockets in the browser, with the requirement that the handshake look like a subset of the HTTP/3 handshake. Beyond that handshake, it doesn’t use anything HTTP-ish or web-ish at all.
WebTransport does indeed require HTTP/3, currently, because it builds on the unique streaming features provided by QUIC, the transport protocol underlying HTTP/3. There is a draft proposal to backport support for WebTransport over HTTP/2, however.
Warning: When not used over HTTP/2, SSE suffers from a limitation to the maximum number of open connections, which can be especially painful when opening multiple tabs, as the limit is per browser and is set to a very low number (6). The issue has been marked as “Won’t fix” in Chrome and Firefox.
SSE suffers from a limitation to the maximum number of open connections,
This is very easy to work around by setting up a wildcard subdomain and attaching a random number each time you open it. So like instead of opening “/sse” you can open like “sse” + Math.random() + “.yourdomain.com/sse”. It is a bit of a pain but not that bad at all.
Every single one of these can be handled by each protocol you proposed. WebRTC + some cryptography would do it with the least burden on the service provider’s infrastructure. When considering ease of implementation though I’d remove WebRTC and swap it for websockets. Everything else fits. This isn’t much of a challenge though, so excuse me.
Unlike traditional polling, where the client repeatedly requests data from the server at regular intervals, long polling establishes a connection to the server that remains open until new data is available. Once the server has new information, it sends the response to the client, and the connection is closed.
This is not true in most situations: Usually, the connection will be kept alive and re-used for subsequent requests, unless you use HTTP/1.0 (unlikely) or either side opts out of it via Connection: close or explicitly closing it (unwise).
Note that this also takes some of the edge off of the statements made on long-polling in the “Latency”, “Throughput”, and “Scalability and Server Load” sections: Connection establishment should have roughly the same impact on server load as it does e.g. for Websockets. The main overhead that remains is the request / response indirection. Batching can somewhat alleviate the penalty on throughput but latency will always be worse than for the other options.
Another option similar to long polling is to reply with Transfer-Encoding: chunked.
Write information to the socket with a separator whenever there is something new to send, read the response bytes from the frontend and cut on the separator.
This uses the same request with no extra round trips as long as the request stays alive, and lets you process the server response byte by byte, instead of waiting for a complete response.
Strictly speaking it requires HTTP 1.1 but seems like Firefox will just accept it with HTTP 1.0 and be lax with the spec. Chrome also “works” but considers the length indicators part of the content, so those will be included in the response bytes that arrive to the callback in JS.
This is dismissive and incorrect. Firstly: websockets, SSE, and webTransport are not required for signaling server, you can use a few http requests/polling instead. Second and most importantly: a WebRTC connected client itself can act as a signaling server. After the bootstrap any client can now be part of your mesh of servers. Services also gain more load balancing, failover and routing capabilities. You may want to reconsider your standing here.
Cool overview on the rest though.
This is just in theory. Do you have any example of anyone doing this in the real world?
None that I want to show off atm, so no. Maybe later this year I’ll be more comfortable.
So you were incorrect because all signaling servers out there use at least one of the 4 technologies.
So? Make your own. ICE doesn’t require much code. To me it seems like you’re confusing bootstrapping and signaling though, maybe start there?
I am very curious about WebRTC from a practical perspective. Do you have any good guides, resources, projects, or libraries that discuss the above? More generally, what is the best way to establish real-time connections between browsers these days?
(https://github.com/paullouisageneau/libdatachannel || https://github.com/webrtc-rs/webrtc) + https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Simple_RTCDataChannel_sample + https://stackoverflow.com/questions/17530197/how-to-do-network-tracking-or-debugging-webrtc-peer-to-peer-connection
you could also try this (https://github.com/WonderInventions/node-webrtc) but the fork is newish and I have not tried it.
I discovered it the hard way when using WebSocket as a maitenance channel for an Android mobile app used by large retailers. Very not pleasant ^^
If Web-Transport is specific to HTTP 3, does it not work on earlier versions? That’d be surprising, because for other web APIs, an app author rarely feels if they’ve been proxied with HTTP/1.1 or not.
Like so many of these things, WebTransport is intentionally confusingly named to make it feel like web-tech. It is essentially “just” raw QUIC sockets in the browser, with the requirement that the handshake look like a subset of the HTTP/3 handshake. Beyond that handshake, it doesn’t use anything HTTP-ish or web-ish at all.
WebTransport does indeed require HTTP/3, currently, because it builds on the unique streaming features provided by QUIC, the transport protocol underlying HTTP/3. There is a draft proposal to backport support for WebTransport over HTTP/2, however.
In my mind there is a clear use-case mapping that is quite trivial, but I’d like this community to challenge it:
Never tried WebTransport, looks promising, let’s see how it scales.
This. Very disappointed that the article does not mention it. https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events
I did a local server (so http/1.1) with livereloading and used
BroadcastChannelas a dirty workaround, to notify more than 6 opened tabs: https://codeberg.org/pfad.fr/devf/src/branch/main/livereload/livereload.js#L11This is very easy to work around by setting up a wildcard subdomain and attaching a random number each time you open it. So like instead of opening “/sse” you can open like “sse” + Math.random() + “.yourdomain.com/sse”. It is a bit of a pain but not that bad at all.
For a website with https, it is very likely that http/2 will be used, so this wildcard workaround is probably not worth the trouble.
Every single one of these can be handled by each protocol you proposed. WebRTC + some cryptography would do it with the least burden on the service provider’s infrastructure. When considering ease of implementation though I’d remove WebRTC and swap it for websockets. Everything else fits. This isn’t much of a challenge though, so excuse me.
This is not true in most situations: Usually, the connection will be kept alive and re-used for subsequent requests, unless you use HTTP/1.0 (unlikely) or either side opts out of it via
Connection: closeor explicitly closing it (unwise).Note that this also takes some of the edge off of the statements made on long-polling in the “Latency”, “Throughput”, and “Scalability and Server Load” sections: Connection establishment should have roughly the same impact on server load as it does e.g. for Websockets. The main overhead that remains is the request / response indirection. Batching can somewhat alleviate the penalty on throughput but latency will always be worse than for the other options.
Another option similar to long polling is to reply with Transfer-Encoding: chunked.
Write information to the socket with a separator whenever there is something new to send, read the response bytes from the frontend and cut on the separator.
This uses the same request with no extra round trips as long as the request stays alive, and lets you process the server response byte by byte, instead of waiting for a complete response.
Strictly speaking it requires HTTP 1.1 but seems like Firefox will just accept it with HTTP 1.0 and be lax with the spec. Chrome also “works” but considers the length indicators part of the content, so those will be included in the response bytes that arrive to the callback in JS.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding#chunked
Some prefer TCP.
Agreed in general but note that the article is about web applications specifically. Those have no way of using raw TCP.