HTTP/2 is just plain silly, HTTP/3 is a silly idea but implemented correctly.

Neither are particularly useful unless you're a web browser. I'm sticking to HTTP/1.1 myself in all of my code.

From where I’m standing QUIC looks like a good contender for a super-TCP like what SCTP never succeeded at becoming. Except there don’t seem to be any (C) libraries with ease of use and lack of inbuilt opinion approaching TCP sockets. (Happy to be proved wrong on that point!) And of course the lack of TLS-less options (outside MsQuic IIUC?) hurts experimentation severely.

Standard posix sockets are mostly just system calls. The TCP state machine is implemented in the OS kernel.

You can switch to raw socket and do the TCP syn/ack dance on your own but this is mostly done for network testing/pen testing, as there are more overhead involved, not less.

This is mostly because the OS actually controls the send/receive buffers used by the actual network drivers. The userland program just takes care of filling these buffers and the kernel and drivers take care of emptying them (i.e. sending). TCP flow control is handled by the kernel, freeing the app to focus on its data. This abstraction actually works quite well.

There are frameworks for userland network stacks, when you're working in high performance networking and need to avoid any overhead the kernel could introduce. The drawback is you need to implement the entire stack, including the low level driver, otherwise it would be slower than what you can already do with classic sockets.

I referred to sockets as an API design, not to express an opinion on whether you should place your protocol implementations inside or outside the kernel. (Although that’s undeniably an interesting question that by all rights should have been settled by now, but isn’t.)

Even then, I didn’t mean you should reproduce the Berkeley socket API verbatim (ZeroMQ-style); multiple streams per connection does not sound like a particularly good fit to it (although apparently people have managed to cram SCTP in there[1]?). I only meant that with the current mainstream libraries[2,3,4], establishing a QUIC connection and transmitting bytestreams or datagrams over it seems quite a bit more involved than performing the equivalent TCP actions using sockets.

[1] https://datatracker.ietf.org/doc/html/rfc6458

[2] https://quiche.googlesource.com/quiche

[3] https://github.com/microsoft/msquic

[4] https://github.com/litespeedtech/lsquic