
uWebSockets: Scalable WebSocket server library for Node.js and C++11 - alexhultman
https://github.com/alexhultman/uWebSockets
======
alexhultman
I want to thank all people involved in making this open source project
possible. Things are by far not set in stone and this library has only been in
development for about 2 months now.

We are working with SocketCluster to make µWS default in version 5, and I have
gotten a lot of help from a lot of people during these months.

Thanks for support, I will be accepting PR's and receiving issues that we need
to fix before making any kind of official stable release.

Also, try to ignore the hateful comments - these commenters build their cases
on thin air, and if you _actually_ do find anything you want to change - I
will accept PR's that can be shown to improve the library.

------
Matthias247
Hey there. Just wrote down a few things that came to my mind after seeing
this. Don't see it as criticism, but as a few hints/remarks what has to be
covered by a websocket (or any other protocol) implementation. Imho the high
performance part isn't too hard to achieve and shouldn't be the highest rated.
The important thing is that such a server should be rock solid in
implementation, otherwise it's worthless.

Some things that you should answer if you are offering this as a C++ websocket
library, and which are currently not covered in the header file:

    
    
        - Whats the threading model of the library?
        - Will server.run() start a singlethreaded eventloop (I guess so from taking a supershort peek into the code and seeing libuv) and everything is running inside there or will it start multiple worker threads?
        - Based on the last question, from which thread[s] are the other callbacks called.
        - If multiple threads are used, is the library threadsafe for sending messages from other threads
        - Is it integratable in other eventloops? Most applications already have a mainloop or something like this, libraries which only work with their own mainloop are not very useful. Normally applications also have to deal with other application logic besides responding to websocket messages.
    

Besides that a few general questions that you should be able to answer for a
websocket implementation:

    
    
        - What's the sending behavior of socket.send?
        - Will it block until all data was sent? This can cause problems with slow receivers in singlethreaded environments.
        - Will it copy all data and buffer it internally until it can be sent? This provides no means for backpressure and slow receivers (or non-receivers) can exhaust the servers memory.
        - Does it handle connection close properly? This is unfortunatly not too easy in websockets.
        - And are there timers in place for force closing the connection if the shutdown sequence is not completed properly? Or if the initial handshake is not completed in a given timeframe?
        - Does ist handle control frames? And will it merge control frames (PONGs) if multiple are queued before they are sent? And will it stop sending them after close connection is initiated?

~~~
alexhultman
The server is async, so there is no blocking functions exposed.

It passes all Autobahn tests, meaning it properly handles close frames & pings
etc.

Timers are used to force close connections. The C++ HTTP server does not
currently time out, but the Node.js HTTP server does, so this is one issue
that needs to be fixed, yes.

~~~
Matthias247
Just looked at the code. You seem to queue everything and therefore never
block. That can be OK for some use-cases, but you don't provide any kind of
backpressure due to that in the send command. It will get problematic in case
of slow receivers. And in node it will break the stream semantics. E.g. if
someone pipes 1Gb of messages into your socket (or sends them if
WriteableStream is not supported) he will think that they have been sent
immediatly and won't know that the data is buffered on lower layer. If you
pipe a fast source into a slow receiver it will break over time - which is
exactly the thing that node streams actually try to avoid.

And another thing I saw there: Your SHORT_SEND optimization looks broken, as
there does not seem to be tracked if the buffer is already used by another
message that is still queued for sending. So short messages can corrupt each
other.

~~~
alexhultman
I can assure you, the short send optimization is not broken.

~~~
Matthias247
Ok, the buffer seems tob be copied it in the queuing code if it needs to be
queued. That's fine.

But it would have been helpful to point to that code lines instead of only
"assuring".

------
justsaysmthng
In
[https://github.com/alexhultman/uWebSockets/blob/master/src/u...](https://github.com/alexhultman/uWebSockets/blob/master/src/uWS.cpp)

What's the deal with

delete [] (char *) head;

where `head` is of type `struct Message` ? Is this some kind of performance
trick ?... Otherwise it looks kind of suspicious..

~~~
hendzen
yeah - the C++ bits were clearly written by someone who doesn't know the
language well. I'd be careful about using this code in production.

EDIT: Specifically I'm referring to the usage of raw pointers, unchecked
pointer arithmetic, goto for flow control and raw new/delete calls. The author
says they have run tests under valgrind, but that doesn't say anything unless
the inputs were malicious. Ideally it should be compiled with ASAN and run
under something like afl-fuzz.

Also - why do you take a libuv dependency - then use uv_poll_t directly with
raw send/recv calls instead of using uv's provided TCP primitives?

~~~
alexhultman
1\. It has been compiled with ASAN. 2\. What you suggest would blow the memory
footprint 16x.

Thanks for giving your infinite enlightenment, after looking at my code for 10
minutes. I guess your 10 minutes of reading the code is infinitely much more
valuable than my 3 months work on it?

Get over yourself.

~~~
smt88
Humility and a collaborative attitude are really important to get the best
results.

When people attack your code, it isn't an attack on you. It makes your code
better. It's one of the downsides to releasing any opinionated project (and
many good projects are opinionated).

For my part, I won't use software written by someone who doesn't either refute
criticism or use it to improve code, and I'm not satisfied you're doing either
of those.

~~~
alexhultman
According to logic, this quote "yeah - the C++ bits were clearly written by
someone who doesn't know the language well. I'd be careful about using this
code in production." _is_ a personal attack. I get offended by this,
personally. When I get offended, personally, I answer how ever I see fit.

Thank you, you will be missed. I don't know what to do without you.

~~~
dang
Welcome to Hacker News; I'm a moderator here.

The comment that provoked you was rude and dismissive and the sort of thing we
ask people not to post. That said, the guidelines here ask you to remain civil
even when someone else is uncivil and/or wrong. That's an important rule that
we all have to abide by—though it's a challenge, especially when one's own
work is being discussed—because otherwise the discussion quality will rapidly
deteriorate.

So please either make substantive neutral replies if you can, or don't post
anything until you can.

------
msim
It's code like this that gives C++ a bad reputation. It's not modern in any
sense. Compiling it with my default warning level in clang gives 482 warnings!
Here's a summary:

    
    
      warning: cast from '...' to '...' increases required alignment from 1 to X [-Wcast-align]
      warning: declaration shadows a field of '...' [-Wshadow]
      warning: declaration shadows a local variable [-Wshadow]
      warning: implicit conversion changes signedness: '...' to '...' [-Wsign-conversion]
      warning: implicit conversion loses integer precision: '...' to '...' [-Wconversion]
      warning: implicit conversion loses integer precision: '...' to '...' [-Wshorten-64-to-32]
      warning: macro name is a reserved identifier [-Wreserved-id-macro]
      warning: no previous prototype for function '...' [-Wmissing-prototypes]
      warning: operand of ? changes signedness: 'int' to 'char' [-Wsign-conversion]
      warning: unused parameter '...' [-Wunused-parameter]
      warning: use of old-style cast [-Wold-style-cast]
    

Use with caution!

~~~
alexhultman
So you enabled pedantic warning level, and you got a bunch of pedantic
nonsense warnings.

There is a reason for these not to be enabled by default.

* Unused parameter -> rly? Who gives a damn? * Use of old style cast -> Well I'm old style, get over it. * No previous prototype declaration -> Again, I do this if I want to. * Shadows field -> who cares? No me. * Cast increases required alignment -> Well, obviously the perf cost is not an issue here. * Etc, etc, etc

These are _pedantic_ warnings. However, this is an open source prject and you
are free to send me PR's whenever you want.

~~~
msim
It's funny that you don't mention the warnings that can be security
vulnerabilities, like integer precision/signedness.

The code screams security vulnerability and I'm not only talking about the
warnings.

~~~
vvanders
Yep, I seem to recall there was one in MySQL a while back that just involved a
simple int->char conversion where the overflow would trigger a match due to a
random seed that was involved in the password path.

I'm a big fan of Wall Werror with pragma for specific sections where you must
work around the warnings. Does a great job of catching issues with
contributions.

------
kapouer
I'm already using it on a socket.io production server. Super-stable for days,
and noticeably less cpu / memory usage. Great open source software !

~~~
alexhultman
Yep, thanks for being one of the first adopters :)

Like mentioned, it works as an optional engine in Socket.IO, Primus &
SocketCluser (in which it will be default in version 5).

No code change, swap when you feel lucky :P

~~~
toomim
I want to use it with SockJS. Do you have any plans or interest in that?

------
samsonradu
I'm currently using the `ws` library for a custom live-streaming solution
(broadcasting binary data) and the memory/CPU usage is indeed not small for a
handful of clients. What does `uws` bring new (technically) to the table?

~~~
alexhultman
There is nothing new brought to the table, feature wise. Same old ws
interface, you keep your current code unchanged.

Swap require('ws') with require('uws') and see how it works for your code,
report any issues if you need them fixed.

Well, of course there is a 20-30x perf boost, 10-40x memory improvement
compared to ws (as the benchmark table shows).

~~~
samsonradu
Yes, I've seen the very simple integration, I'll definitely give it a try. I
was actually curious how you've achieved that performance boost?

~~~
alexhultman
I get this question quite often, here is a good start:
[https://github.com/alexhultman/uWebSockets/issues/56](https://github.com/alexhultman/uWebSockets/issues/56)

~~~
samsonradu
Cool, hope it's ok for others to read

[https://www.reddit.com/r/cpp/comments/4ccpsa/%C2%B5websocket...](https://www.reddit.com/r/cpp/comments/4ccpsa/%C2%B5websockets_highly_scalable_c11_websocket_server/)

~~~
alexhultman
[https://www.youtube.com/watch?v=fN1WBgS9u_E](https://www.youtube.com/watch?v=fN1WBgS9u_E)

------
moron4hire
You say you support Windows, but when I try to use it, it gives me an error

    
    
         Error: Compilation of µWebSockets has failed and there is no pre-compiled binary available for your system. Please install a supported C++ compiler and reinstall the module 'uws'.
    

A) Which are the supported compilers?

B) This issue makes it seem like that wouldn't matter, anyway?
[https://github.com/alexhultman/uWebSockets/issues/72](https://github.com/alexhultman/uWebSockets/issues/72)

------
jondubois
uWebSockets is bundled as part of SocketCluster
[http://socketcluster.io/](http://socketcluster.io/) and we plan to make it
the default in SC v5. We got a massive speedup! Highly recommended.

~~~
alexhultman
Yes, Socket.IO really need to step up their game if they are going to have
this kind of marketing:

"FEATURING THE FASTEST AND MOST RELIABLE REAL-TIME ENGINE"

Never mind the fact that one libuv tcp stream consumes more memory than one
entire WebSocket in µWS...

------
est
Anything similar in Python?

Currently using pypy+tornado-sockjs. Works OK.

~~~
e12e
Maybe uvloop?

"Uvloop: Fast Python networking"
[https://news.ycombinator.com/item?id=11625585](https://news.ycombinator.com/item?id=11625585)

Maybe paired with Growler: "Growler: Asyncio Micro-Framework in Python"
[https://news.ycombinator.com/item?id=11632181](https://news.ycombinator.com/item?id=11632181)

"Simple websocket server with uvloop.":
[https://gist.github.com/kracekumar/daf10b3be3191a78b037c0c79...](https://gist.github.com/kracekumar/daf10b3be3191a78b037c0c79667c26c)

~~~
alexhultman
No offence, but I don't think you fully grasp the situation here. This is an
_extremely_ optimized fully native server written with low-level CPU
awareness. You can absolutely not, in any possible way, write this in Python.

~~~
barkingdog
I can understand that you might be a bit frustrated right now, because perhaps
that level of performance in pure python may literally be difficult to
impossible in this case. But, the question the person was asking was a very
reasonable one -- something along the lines of "I'm using this solution in
python right now, and I'd like more performance -- what are my options?"

It seems like you not only misunderstand the question, but felt the need to
question their intelligence and give a rude, vague, and overall unhelpful
answer. As a piece of communication, it is overall useless to everyone
involved. Please be mindful of the way you come across. There's no need to
insult, dismiss and disrespect others. It only takes a single moment, and
saves time and energy for both you and them. You could rephrase like "No. You
can approach this to a level of <percentage_of_perf>, but it will be hard to
pass that point, due to the way the library is written." If you did that,
you'd add some very valuable information to the conversation with little
effort. It would be a win win for everyone.

Beyond that, assuming your benchmarks are accurate, this seems like a prime
library for someone to write a python wrapper for! There's autobahn-twisted
right now, but I'm not sure how well it performs in comparison.

~~~
alexhultman
Toss a coin and it will land on someones holy ground..

My intentions were not to harm, that was why I said "no offence, but". I
cannot more than explain myself. Sorry if I offended anyone (despite
explicitly saying "no offence"). Someone should probably censor me, like, a
lot.

~~~
barkingdog
You've written what potentially appears to be a promising library. Great! In
fact, it seems so promising that people are trying to find the equivalent in
the language of their choice. Even better! Why not encourage them to write a
wrapper for your fine library in their language of choice? Not everyone uses
Node, after all. Maybe that person asking for equivalents in Python would've
written a binding if you told them "Hey, you could try to do this in pure
python but because of the relative performance of my library, you might want
to consider writing a binding to µws."

I doubt you are trying to harm anyone. But you're not being very helpful. You
say that you've "landed on someone's holy ground" but there is a very low
chance that is going on. They probably just want to get a job done, and they
want to figure out if your tool's a good fit. All it takes is a little bit
more thought before you type out a response.

I'm not telling you to censor yourself. I'm telling you to stop worrying about
explaining yourself, and start thinking about being more helpful. I'm telling
you to do it, because it will make things easier for you. You might have
written the library, but other people are going to be the ones who use it.
They're going to ask you questions, and you're going to think some of those
questions are stupid. It's okay. But if you try to be helpful to them even if
you think their questions are stupid, you'll spend far less time writing
defensive comments on HN, and far more time watching adoption for your library
grow, which I assume is something you may want.

Best of luck!

~~~
alexhultman
Thanks, I can certainly help people with questions if they need help in
writing a Python wrapper. I think that would be a good solution but it would
need to integrate seamlessly with the rest of their app. Posting on GitHub
would be a good start in this, or Gitter.

------
dhendo
I'm assuming it's not a straight swap for the `websocket` package?
[https://github.com/theturtle32/WebSocket-
Node](https://github.com/theturtle32/WebSocket-Node)

~~~
alexhultman
Nope, only ws <-> uws :(

~~~
dhendo
Fair enough. It is probably not a huge rewrite to give it a try.

------
meir_yanovich
What is the main difference between libwebsockets and this ?

can it be embedded in to libuv? in C

~~~
alexhultman
You can create a C binding and it does integrate with libuv.

libwebsockets is targeting the embedded world with a smaller code footprint
(libc vs libstdc++). libwebsockets performs very good in memory and CPU time.

------
throwaway2016a
This looks awesome. Can I use this with Meteor? If there is any app that would
benefit from websocket optimizations it's Meteor.

~~~
alexhultman
I don't think so but Meatier
([https://github.com/mattkrick/meatier](https://github.com/mattkrick/meatier))
should receive uws as default engine since it build on SC, you could look into
that but honestly I don't understand this project at all :P

~~~
throwaway2016a
Not sure it it helps but it looks like it uses Faye-Websockets

[https://github.com/faye/faye-websocket-node](https://github.com/faye/faye-
websocket-node)

I don't know enough about the inner workings to be able to tell if it's
compatible. Any Speeding up of meteor would be HUGE news.

------
lpinca
The project is young but looks promising.

------
zkhalique
Why is your username green?

~~~
Svenskunganka
New users have a green username. Not sure when it goes away.

You can find posts by green users here:
[https://news.ycombinator.com/noobstories](https://news.ycombinator.com/noobstories)

