File: README.md
:closed_lock_with_key: Optimized security
Being meticulously optimized for speed and memory footprint, µWebSockets is fast enough to do encrypted TLS 1.3 messaging quicker than most alternative servers can do even unencrypted, cleartext messaging3.
Furthermore, we partake in Google's OSS-Fuzz with a ~95% daily fuzzing coverage4 with no sanitizer issues. LGTM scores us flawless A+ from having zero CodeQL alerts and we compile with pedantic warning levels.
:arrow_forward: Rapid scripting
µWebSockets is written entirely in C & C++ but has a seamless integration for Node.js backends. This allows for rapid scripting of powerful apps, using widespread competence. See µWebSockets.js.
:crossed_swords: Battle proven
We've been fully standards compliant with a perfect Autobahn|Testsuite score since 20162. µWebSockets powers many of the biggest crypto exchanges in the world, handling trade volumes of multiple billions of USD every day. If you trade crypto, chances are you do so via µWebSockets.
:battery: Batteries included
Designed around a convenient URL router with wildcard & parameter support - paired with efficient pub/sub features for WebSockets. µWebSockets should be the obvious, complete starting point for any real-time web project with high demands.
Start building your Http & WebSocket apps in no time; read the user manual and see examples. You can browse our TypeDoc for a quick overview.
/* One app per thread; spawn as many as you have CPU-cores and let uWS share the listening port */
uWS::SSLApp({
/* These are the most common options, fullchain and key. See uSockets for more options. */
.cert_file_name = "cert.pem",
.key_file_name = "key.pem"
}).get("/hello/:name", [](auto *res, auto *req) {
/* You can efficiently stream huge files too */
res->writeStatus("200 OK")
->writeHeader("Content-Type", "text/html; charset=utf-8")
->write("<h1>Hello ")
->write(req->getParameter("name"))
->end("!</h1>");
}).ws("/*", {
/* Just a few of the available handlers */
.open = [](auto *ws) {
ws->subscribe("oh_interesting_subject");
},
.message = [](auto *ws, std::string_view message, uWS::OpCode opCode) {
ws->send(message, opCode);
}
}).listen(9001, [](auto *listenSocket) {
if (listenSocket) {
std::cout << "Listening on port " << 9001 << std::endl;
} else {
std::cout << "Failed to load certs or to bind to port" << std::endl;
}
}).run();:briefcase: Commercially supported
uNetworking AB is a Swedish consulting & contracting company dealing with anything related to µWebSockets; development, support and customer success.
Don't hesitate sending a mail if you're building something large, in need of advice or having other business inquiries in mind. We'll figure out what's best for both parties and make sure you're not falling into common pitfalls.
Special thanks to BitMEX, Bitfinex, Google, Coinbase, Bitwyre, AppDrag and deepstreamHub for allowing the project itself to thrive on GitHub since 2016 - this project would not be possible without these beautiful companies.
:wrench: Customizable architecture
µWebSockets builds on µSockets, a foundation library implementing eventing, networking and cryptography in three different layers. Every layer has multiple implementations and you control the compiled composition with flags. There are currently five event-loop integrations; libuv, ASIO, GCD and raw epoll/kqueue.
In a nutshell:
WITH_WOLFSSL=1 WITH_LIBUV=1 make examplesbuilds examples utilizing WolfSSL and libuvWITH_OPENSSL=1 make examplesbuilds examples utilizing OpenSSL and the native kernel
See µSockets for an up-to-date list of flags and a more detailed explanation.
:handshake: Permissively licensed
Intellectual property, all rights reserved.
Where such explicit notice is given, source code is licensed Apache License 2.0 which is a permissive OSI-approved license with very few limitations. Modified "forks" should be of nothing but licensed source code, and be made available under another product name. If you're uncertain about any of this, please ask before assuming.
File: benchmarks/README.md
More recent benchmarks
It was a while ago this page was written (and it needs updating), so here are the most recent benchmarks against the top competition we know of:
| v20 | v21 |
|---|---|
Benchmark-driven development
Making decisions based on scientific benchmarking while you develop can guide you to create very efficient solutions if you have the dicipline to follow through. µWebSockets performs with 98% the theoretical maximum for any user space Linux process [this was written before io_uring was added to Linux] - if anything would ever be faster, it would only be so by less than 2%. We know of no such project.
| Http | WebSockets |
|---|---|
Because of the big lead in cleartext performance, it's actually possible to enable TLS 1.3 encryption in µWebSockets and still beat most of the competition in an unfair cleartext-vs-encrypted run. Performance retention of TLS 1.3 encryption with µWebSockets is about 60%, so you do the math.
All of this is possible thanks to extensive benchmarking of many discarded prototypes & designs during development. The very first thing done in this project was to benchmark the Linux kernel against itself, to get a clear idea of expected maximum performance and thus a performance budget on this platform.
From that point every line of code was benchmarked against the budget and thrown away if it failed the vision. Today µWebSockets does WebSocket messaging without any significant overhead, making it very unlikely to ever be outperformed.
Of course, memory usage has always been a big factor in this. The name µWebSockets is meant to signify "small WebSockets" and comes from the memory optimizations made throughout. Holding many WebSockets should not require lots of RAM.
If you're looking for a performant solution, look no further.
Common benchmarking mistakes
It is very common, extremely common in fact, that people try and benchmark µWebSockets using a scripted Node.js client such as autocannon, ws, or anything similar. It might seem like an okay method but it really isn't. µWebSockets is 12x faster than Node.js, so trying to stress µWebSockets using Node.js is almost impossible. Maybe if you have a 16-core CPU and dedicate 15 cores to Node.js and 1 core to µWebSockets.
So whatever you do, it is of greatest importance that you actually do check and make sure that µWebSockets is being stressed to 100% CPU-time before noting the result. If it isn't, then you're not really benchmarking µWebSockets - you're benchmarking your client, trying to stress µWebSockets! Please don't make this mistake.
Why "hello world" benchmarking?
Contrary to popular belief, "hello world benchmarks" are the most accurate and realistic gauges of performance for the kind of applications µWebSockets is designed for:
- IO-gaming (latency)
- Signalling (memory overhead)
- Trading (latency)
- Finance (latency)
- Chatting (memory overhead)
- Notifications (memory overhead)
Most business applications of the above mentioned categories are implemented without a central on-disk DB, blocking or severely limiting hot-path performance. As such, web IO becomes a significant part of overall bottleneck, if not the only bottleneck. Message echoing of around 1-16 kB or even as small as 512 bytes is a good test of the overall server plumbing (receive -> timeout clear -> emit to app -> timeout set -> send) for these applications.
Of course, if you build an app that absolutely must have an on-disk SQL DB central to all hot-paths, then µWebSockets is not the right tool for your app. Keep in mind that, finding a case where µWebSockets makes no difference, does not mean µWebSockets never makes a difference.
A note on starvation due to über bloated test clients (Autocannon)
uWS is 13x faster than Fastify. Read that again. 1300% faster. So when you benchmark uWS using the Fastify-written Autocannon (made by the author of Fastify), it shouldn't surprise a brain capable of critical thinking, that uWS will be heavily under performing when tested with Autocannon.
In fact, uWS will be so starved of work when benchmarked with the bloated and slow Autocannon that, in fact, it will go to sleep mode, wait for Autocannon to do its bloated run, wake up, do some minor work, go to sleep because Autocannon is so slow it cannot saturate uWS, then wake up again. This constant idling/wakeup that a near-0% stressed uWS process has to do, actually ends up performing worse even than Fastify benchmarked with Autocannon.
That's right - Autocannon is the bottleneck, but since Autocannon is so fundamentally slow and cannot saturate uWS with work, it causes uWS to not only be bottlenecked by Autocannon in wall clock time (and thus the benchmark is nonsense), but it actually performs worse in wall clock time, since we have this constant idle/non-idle switching going on since uWS process is close to 0% CPU-time utilization. uWS is literally so fast that it has to go to sleep when being tested with Autocannon. 🥱
In other words, if Fastify is 13x slower than uWS, maybe you shouldn't trust its author when it comes to performance testing software. It kind of goes without saying that, incompetence should not be trusted.
To benchmark uWS, you have to use a highly optimized C client like uSockets http_load_test client. You can, absolutely not, benchmark uWS using a JavaScript client.
File: examples/README.md
Examples
Make sure to also check out the JavaScript examples, the TypeDoc documentation browser and the Discussions tab here on GitHub. Much of what is true for the Node.js addon is true also for the C++ library.
File: fuzzing/README.md
Fuzz-testing of various parsers, mocked examples and system libraries
A secure web server must be capable of receiving mass amount of malicious input without misbehaving or performing illegal actions, such as stepping outside of a memory block or otherwise spilling the beans.
Continuous fuzzing under various sanitizers is done as part of the [Google OSS-Fuzz](https://github.com/google/oss-fuzz#oss-fuzz---continuous-fuzzing-for-open-source-software) project:
- UndefinedBehaviorSanitizer
- AddressSanitizer
- MemorySanitizer
Overall coverage is about 95% for both uSockets and uWebSockets, all source code included
- No defects or outstanding bugs
- No timeouts, OOM, crashes or other issues
- Transparent reporting of found issues: https://bugs.chromium.org/p/oss-fuzz/issues/list?q=label%3AProj-uwebsockets&can=1
Currently the following parts are individually fuzzed:
- WebSocket handshake generator
- WebSocket message parser
- WebSocket extensions parser & negotiator
- WebSocket permessage-deflate compression/inflation helper
- Http parser (with and without Proxy Protocol v2)
- Http method/url router
- Pub/sub "topic tree"
While some targets are entire (mocked) example apps
- libEpollFuzzer mocks the kernel syscalls and allows to cover a lot of uSockets source code.
- A mock implementation of uSockets allows to cover a lot of the inbetween logic of uWebSockets.