
Websocketd - mmcclure
http://websocketd.com/
======
jchw
This is the second or third "it's CGI again" thing I've seen in the past year.
While these things are cool and definitely have their place, it's still worth
noting that process per connection scales fairly poorly, simply because
processes and forking are relatively expensive, and therefore it's _probably_
unwise to deploy something like this in production anymore. It is what it is,
I suppose.

~~~
geocar
The myth that fork is expensive is pervasive, and speaking to the ways that it
is true†, well: performance is relative.

fork() only takes around 8ms on my Linux machine and I can get 100,000
posix_spawn() per second there with 100MB RSS.

That's "fast enough" for a large number of applications.

†: fork() is a lot slower (over 20x) on Windows

~~~
inglor
8ms per fork means you can only accept 125 connections per second. (per core)

That means it's only viable for connections where the connection is very long
lived and messages are very sparse (because context switches).

~~~
nabla9
If you use websocket for short lived connections, you are doing something
wrong.

\--

Meta observation:

Maybe this is the bane of smartphone era and small screens, but the context of
the discussion seems to disappear instantly.

Subject: websockets > forking processes > .. aaand the websocket context is
lost and we are talking generally about forks in web applications with growing
thread.

~~~
angusp
> If you use websocket for short lived connections, you are doing something
> wrong.

Pretty-much true, but I remember a funny story from Dropbox where their
websocket service couldn't come back up after a crash because their normal
users trying to re-open super long lived connections all at once was well-
beyond the capacity of the system

------
Matthias247
Doesn’t this have an impedance mismatch? Stdin/out are stream based. Websocket
is message based. There is no guarantee you can transmit the content of a
single WebSocket message inside a single os read or write call. Unless you
expect that on both sides messages might be fragmented across multiple calls
and callbacks. But I don’t see the docs mentioning that.

~~~
mdavidn
Newlines. Each line written to STDOUT is sent as one frame, and each frame
received is read from STDIN followed by a synthetic newline. The FAQ explains
how to escape multiline messages (or binary data, presumably).

[https://github.com/joewalnes/websocketd/wiki/FAQ#how-can-
i-s...](https://github.com/joewalnes/websocketd/wiki/FAQ#how-can-i-send-
multiple-line-messages)

~~~
Matthias247
Ah thanks that makes sense. I didn't see it when I glimpsed over the site.

That should provides reliable framing on both sides. But as shown in the
linked it page it also comes with the downside of not being able to send raw
websocket messages which contain a new line - so it's not possible to port
existing applications from other websocket servers to this one without having
to change communication.

~~~
function_seven
I don't understand why the daemon needs to client to escape newlines in the
message. Can't it handle that before feeding the message to STDIN?

For example, my browser sends:

    
    
        This is line one...
        ...and this is line two
    

as a string ("This is line one...\n...and this is line two") and the
websocketd receives that, and passes along

    
    
        This is line one...\\n...andthis is line two\n
    

to the STDIN.

It knows that the message is one thing, so the newlines aren't the same as the
end of message, right?

It'd also be nice to use EOF as the indicator to flush STDOUT to the client,
so the program can also emit newlines without needing to escape them first.

All that being said, this is nifty. I think I can use this for some low-volume
ideas I have on an internal app. The newline handling isn't a problem because
I'm not replacing anything that already exists.

~~~
masklinn
> It'd also be nice to use EOF as the indicator to flush STDOUT to the client,
> so the program can also emit newlines without needing to escape them first.

EOF is not an actual control code though (and is implementation dependent).
However there are control codes for message framing e.g. ETB, ETX, EOT (often
used as terminal EOF), FF (form feed / page break), RS/GS/FS

~~~
function_seven
> EOF is not an actual control code though

You're right. I think I have to relearn that periodically :)

------
exabrial
Good time to plug this utility, swiss army knife for websockets:
[https://github.com/vi/websocat](https://github.com/vi/websocat)

Author is extremely nice as well.

------
mholt
Websocketd is neat. It inspired me to make the websocket directive in Caddy:
[https://caddyserver.com/docs/websocket](https://caddyserver.com/docs/websocket)

~~~
PixyMisa
Aha! My first thought was "Why use this instead of Caddy's websocket support?"

Answer: Websocketd came first.

------
FullyFunctional
It looked simple enough, but I was curious about the threading example on
[https://github.com/joewalnes/websocketd/wiki/CPP-Input-
Outpu...](https://github.com/joewalnes/websocketd/wiki/CPP-Input-Output-
Example)

The variable `count` appears to be incremented non-atomically from two
different threads. Is that safe in C++?

~~~
comex
It is unsafe. But it would be safe if these two lines were swapped:

    
    
        count++;
        pthread_mutex_lock(&m);
    

since the reader already holds the mutex while reading `count`.

~~~
justinclift
Do a PR or equivalent?

~~~
saagarjha
Friendly reminder that not everyone is in a position where they can create
pull requests against random projects: they might not have time, or clearance
from their company's legal department, or…

~~~
justinclift
???

Note it was a question. As you mention, not everyone can do so (etc).

~~~
saagarjha
The question looked like "why are aren't you making a PR for this".

------
jasonhansel
Unpopular opinion: AWS lambda is basically equivalent to CGI. The web has come
full circle.

~~~
icebraining
It's closer to FCGI, since Lambda processes aren't restarted for each new
request.

~~~
jasonhansel
Question: why doesn't Amazon just use the standard FCGI interface, then?

~~~
icebraining
Maybe they are; as far as I know, the protocol they use to communicate with
the worker isn't specified, all they say is "implement a function with this
signature, then import our SDK, and it will call your function". This gives
them the flexibility to switch protocols at will, at the cost of having to
implement these SDKs.

That said, building a FCGI "bridge" isn't hard, it's just that nobody cared
enough to do it.

~~~
karl_p
They have specified the lambda runtime.
[https://docs.aws.amazon.com/lambda/latest/dg/runtimes-
api.ht...](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-api.html)

Basically: your instance POSTS to an endpoint to get/reply to requests, one at
a time.

I can't wait until you can specify that a lambda instance can handle a certain
# of requests in parallel. Ex: things just blocked on IO/DB. That would make
better use of your RAM.

------
rileytg
i’ve been using this in production to stream logs to a web console (~2,000
sets of logs distributed across 4 server with about 350 active connections at
a time) and have never had any issues

~~~
hnarn
How do you know that you haven't had any issues?

~~~
perlgeek
Usually you notice issues by the server locking up, the clients reporting
problems, or messages being missing from the log (which you tend to notice
when you search for specific things in the logs).

~~~
hnarn
So how do you know that you're not just getting 80% of "log entry X" just
because you get hits for them every now and then?

~~~
perlgeek
Logging is usually pretty deterministic.

A request might generate log entries a, b1, c or a, b2, c, depending on some
conditions. The exact contents vary by request (otherwise there would be no
need to log them), but the type is always the same.

If you find logs for c without either b1/b2 or a, you know log entries went
missing.

If you have a 20% miss rate with recording your log entries, and you analyze
just 20 log entries, the chance that one of them is missing is already around
98.8%.

If you actually use your logs for anything, it becomes pretty obvious pretty
quickly when they are incomplete.

------
jchook
If you really wanted to follow UNIX philosophy, why not build atop xinetd?

for example... simply accept stdin and stdout as I/O streams by default, but
don't provide a network mechanism.

~~~
masklinn
You can put websocketd behind xinetd. xinetd doesn't talk websocket, so you
still need to "provide a network mechanism" to bridge the incoming connection
and the client's streams.

~~~
cogburnd02
> xinetd doesn't talk websocket

Why not extend xinetd so that it can interact with websockets?

~~~
masklinn
Because the point of xinetd is to spawn other daemons on socket activations.
xinetd handling stuff itself is the exception not the rule (5 service are
internally provided, none of which you want to run: RFC 862 "echo", RFC 863
"Discard", RFC 864 "CHARGEN", RFC 867 "daytime" and RFC 868 "time").

------
loeg
So, all of the same sorts of scaling problems as inetd?

~~~
dpwm
Well, unless it's doing something exceedingly clever, it looks like it will be
launching one process per connection.

For communication servers, this could prove a challenge – you'll probably want
to use some kind of pub-sub architecture. By the time you've gone down that
road, you could've gone down one of the more robust paths.

Still, this looks great for smaller apps. And, it seems a great way to
prototype – especially if your favourite language doesn't have great websocket
support.

~~~
loeg
> Still, this looks great for smaller apps. And, it seems a great way to
> prototype – especially if your favourite language doesn't have great
> websocket support.

Totally agree. inetd is a pretty good model, it just falls down in the face of
thousands of slow, low-computational effort connections tying up gigabytes of
RAM. That and most schedulers seem to struggle with that number of threads.

------
bhargav
Wondering if it would be more "unixy" to use sock files [1] ? I think some
WSGI servers such as Gunicorn [2] support said functionality. I do think there
is a place for websocketd provided you do not use tools like WSGI servers
already.

1:
[https://en.wikipedia.org/wiki/Unix_domain_socket](https://en.wikipedia.org/wiki/Unix_domain_socket)

2:
[http://docs.gunicorn.org/en/stable/deploy.html?highlight=soc...](http://docs.gunicorn.org/en/stable/deploy.html?highlight=sock)

------
bwasti
Reminds me of a little project I did a while back, but instead reading from
stdin like netcat

[https://github.com/bwasti/webpipe](https://github.com/bwasti/webpipe)

------
minhajuddin
This is really useful for building one of utility websites. I used this in one
of my previous companies to tail the logs on our little QA server and push
them via websocktd to an internal web page.

------
joefourier
I'd be interested to know if anybody has used this in production. I've used
Websocketd for quick and dirty prototyping and making things like in-browser
monitoring tools and it was very fast to setup, but a full-fledged library
like Gorilla or uWebsockets seems more practical for real-world applications
with thousands or more simultaneous users.

------
xmichael999
Could this then be used to replace node and this type of mess?
[https://github.com/phoboslab/jsmpeg/blob/master/websocket-
re...](https://github.com/phoboslab/jsmpeg/blob/master/websocket-relay.js)

~~~
bazza451
Code looks reasonable.....

------
gadelat
I've built similar tool, but for HTTP at
[https://github.com/ostrolucky/stdinho](https://github.com/ostrolucky/stdinho)

------
ficklepickle
FYI, the page needs a viewport tag in the head to display properly on mobile:
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>

------
Ericson2314
The unix philosophy is massively overrated because processes are unwieldy in
practice, and support only weak notions of composition even in theory.

------
gruez
is it me, or does the site look really similar to letsencrypt.org? I looked on
both sites and neither say they're using a template.

~~~
mushufasa
FWIW the css template is just some bootstrap stuff, and this for the syntax
highlighter in the code snippets: /*
[http://prismjs.com/download.html?themes=prism-
twilight&langu...](http://prismjs.com/download.html?themes=prism-
twilight&languages=clike+javascript+bash+c+csharp+go+java+php+python+ruby+swift)
_/ /_* * prism.js Twilight theme * Based (more or less) on the Twilight theme
originally of Textmate fame. * @author Remy Bach */

------
iAm25626
Seems useful! Remind me of pushpin.

------
sefrost
Does anyone have any experience using websockets in a serverless architecture?

------
baybal2
>Avoid threading headaches

>Each inbound WebSocket connection runs your program in a dedicated process.

Not the best design decision

~~~
icebraining
The quality of the design depends on the goals. For simplicity, seems like a
great decision.

------
zemo
what if you need two clients to connect to the same process

------
xrobledo84
Or just use cowboy which is written is in erlang and will scale better.

~~~
arama471
Is there any other benefit than scaling better? Because I'm pretty sure 99.9%
of projects never hit the "need to scale more" part, and if they did it
doesn't seem like this would be too difficult to move off of

------
iknowstuff
How do posts like this end up at #2 on the front page with just one comment?
Websocketd doesn't strike me as an particularly popular or well known tool.

~~~
chrisseaton
Well if it was popular or well known why would it be news-worthy?

~~~
tomhoward
Indeed. Discovering interesting new things is one of the main purposes of HN.

------
ziont
CGI 20 years later? can somebody explain what they mean by this

edit: okay this is pretty cool, what use cases is there?

------
kccqzy
So kind of like CGI. Okay.

~~~
pdxandi
That's what they say on their site: "It's like CGI, twenty years later, for
WebSockets"

------
gok
Ok I know the software-today-is-so-bloated trope is overplayed but... "the
UNIX way"?

The compiled Linux x86_64 binary is 7 megabytes. All of System V combined was
not that big.

~~~
dpwm
> Written in Go

I have a fairly simple web-app written in go – no websockets, just net/http. I
just checked and the binary size is 6.8 megabytes.

There's a lot in there. For starters, there's the go runtime. Then there's the
HTTP server.

I suspect there may be ways to improve on the binary size if it mattered so
much. xz gets it down to 2.1MB, suggesting there's some redundancy in there.

~~~
marcrosoft
You can cut your binary size almost in half on Linux by removing debug
information and symbols with:

`go build -ldflags="-s -w"`

~~~
Something1234
I thought it was dangerous to use `strip` on any go binaries, because it would
result in an incorrect program. LDFlags might cause something else but isn't
it the same concept?

------
Walkman
> Each inbound WebSocket connection runs your program in a dedicated process.
> Connections are isolated by process.

I see you and 10,900 other "software developers" get the point of WebSocket.
It's especially "impressive" when you written the whole thing in Go and could
have used goroutines and channels, which could easily handle hundreds of
thousand of connections (maybe millions). Terrible design!

For a long time I thought every software developer must be smart, but a lot of
them don't see the big picture very often.

Why this bothers me so much? You created something that a lot of developers
think is good enough, so less innovation will happen and more and more slow
websites will appear because of tech like this...

~~~
willeh
There are definitely use cases for this, for instance you might have some
command line application that uses standard io. Sure it might be adapted to
have support for web sockets natively, but this of course takes time. And as
the old adage goes time is money.

And sure you might be upset by "slow" websites, but for the small consultancy
productising their scripts, it might make them - dare I say it, a quick buck.
In the end the invisible hand of the market decides how much money is invested
making websites fast and that is what guides the design of the technology
being developed.

Perhaps it is you who fail to see the big picture.

