[erlang-questions] web sockets almost working ....

317 views
Skip to first unread message

Joe Armstrong

unread,
Dec 10, 2009, 5:21:18 AM12/10/09
to Erlang
Very exciting - web sockets is partially working - this is very very
very exciting

But I can't get past the handshake ...

<aside>
If we can get this working we can junk ajax, comet etc and do pure
socket bi-directional
stuff as the great ones intended. Erlang will then fit *beautifully*
with the broswer
code and we can start writing some great applications
</aside>

This posting

http://blog.chromium.org/2009/12/web-sockets-now-available-in-google.html

Got me pretty excited - I happen to have the latest chrome browser as
so a little test was in order ...

The handshake is described in

http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-55#page-22

So I set up a local web server on port 2246 that serves up this page

<body>
<script>
alert("hello");
if ("WebSocket" in window) {
var ws = new WebSocket("ws://localhost:1234");

ws.onopen = function() {
// Web Socket is connected. You can send data by send() method.
ws.send("hello from the browser");
};

ws.onmessage = function (evt)
{
var received_msg = evt.data; alert("yes");
};

ws.onclose = function()
{
alert("closed");
};
} else {
alert("sad");
};

</script>
</body>


Then I have a server on port 1234 using this code

-module(local_server).
-compile(export_all).

start() ->
{ok, Listen} = gen_tcp:listen(1234, [{packet,0},
{reuseaddr,true},
{active, true}]),
spawn(fun() -> par_connect(Listen) end).

par_connect(Listen) ->
{ok, Socket} = gen_tcp:accept(Listen),
spawn(fun() -> par_connect(Listen) end),
wait(Socket).

wait(Socket) ->
receive
{tcp, Socket, Data} ->
io:format("received:~p~n",[Data]),
Msg = prefix() ++
"WebSocket-Origin: http://localhost:2246\r\n" ++
"WebSocket-Location: ws://localhost:1234\r\n\r\n",
gen_tcp:send(Socket, Msg),
loop(Socket);
Any ->
io:format("Received:~p~n",[Any]),
wait(Socket)
end.

prefix() ->
"HTTP/1.1 101 Web Socket Protocol Handshake\r\nUpgrade:
WebSocket\r\nConnection: Upgrade\r\n".

loop(Socket) ->
receive
{tcp, Socket, Data} ->
io:format("received:~p~n",[Data]),
loop(Socket);
Any ->
io:format("Received:~p~n",[Any]),
loop(Socket)
end.

It's beginning to work but now the handshake fails.

Very exciting stuff.

Be the first to get this working and tell us how

/Joe

________________________________________________________________
erlang-questions mailing list. See http://www.erlang.org/faq.html
erlang-questions (at) erlang.org

Antoine Koener

unread,
Dec 10, 2009, 7:13:30 AM12/10/09
to Joe Armstrong, Erlang
Hi Joe,

io:format("received:~p~n",[Data]),
> Msg = prefix() ++
> "WebSocket-Origin: http://localhost:2246\r\n" ++
> "WebSocket-Location: ws://localhost:1234\r\n\r\n",
> gen_tcp:send(Socket, Msg),
>
>

May be use a full URL instead of


"WebSocket-Location: ws://localhost:1234\r\n\r\n",

i.e.
"WebSocket-Location:
ws://localhost:1234/path/to/your/script\r\n\r\n",
?

I can't test at the moment

my christmas cents...

Colm Dougan

unread,
Dec 10, 2009, 7:34:17 AM12/10/09
to Joe Armstrong, Erlang
Joe,

On Thu, Dec 10, 2009 at 10:21 AM, Joe Armstrong <erl...@gmail.com> wrote:
> Very exciting - web sockets is partially working - this is very very
> very exciting
>
> But I can't get past the handshake ...

It appears to make a difference if you add a trailing slash after
WebSocket-Location, i.e. :

"WebSocket-Location: ws://localhost:1234/\r\n\r\n",

Now I get :

Eshell V5.7.4 (abort with ^G)
1> local_server:start().
<0.33.0>
2> received:"GET / HTTP/1.1\r\nUpgrade: WebSocket\r\nConnection:
Upgrade\r\nHost: localhost:1234\r\nOrigin:
http://localhost:2246\r\n\r\n"
2> received:[0,104,101,108,108,111,32,102,114,111,109,32,116,104,101,32,98,114,
111,119,115,101,114,255]

Colm

Joe Armstrong

unread,
Dec 10, 2009, 7:56:28 AM12/10/09
to Colm Dougan, Erlang
Thanks now it works beautifully, I've enclosed listings below.

First reflection - this is amazing - the overhead is tiny and there is
no parsing
headers etc. The erlang just had to send

[0] ... bytes .. [255] and it ended up in the browser.

This will kill Ajax, keep-alive connections etc, now all google has to
do is ship
the parse trees of HTML pages instead of *text* and browsers can skip parsing
and concentrate on rendering and stuff will go fast ...

Now somebody just has to be the first to implement
http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-65
in Erlang

/Joe

The web page is now:


<body>
<script>
alert("hello");
if ("WebSocket" in window) {
var ws = new WebSocket("ws://localhost:1234");

ws.onopen = function() {
// Web Socket is connected. You can send data by send() method.
ws.send("hello from the browser");
};

ws.onmessage = function (evt)
{

var data = evt.data; alert(data);
};

ws.onclose = function()
{
alert("closed");
};
} else {
alert("sad");
};

</script>
</body>

And the erlang is:

-module(local_server).
-compile(export_all).

start() ->
{ok, Listen} = gen_tcp:listen(1234, [{packet,0},
{reuseaddr,true},
{active, true}]),
spawn(fun() -> par_connect(Listen) end).

par_connect(Listen) ->
{ok, Socket} = gen_tcp:accept(Listen),
spawn(fun() -> par_connect(Listen) end),
wait(Socket).

wait(Socket) ->
receive
{tcp, Socket, Data} ->
io:format("received:~p~n",[Data]),
Msg = prefix() ++

"WebSocket-Origin: http://localhost:2246\r\n" ++


"WebSocket-Location: ws://localhost:1234/\r\n\r\n",

gen_tcp:send(Socket, Msg),
loop(Socket);
Any ->
io:format("Received:~p~n",[Any]),
wait(Socket)
end.

prefix() ->
"HTTP/1.1 101 Web Socket Protocol Handshake\r\nUpgrade:
WebSocket\r\nConnection: Upgrade\r\n".

loop(Socket) ->
receive
{tcp, Socket, Data} ->

Data1 = unframe(Data),
io:format("received:~p~n",[Data1]),
gen_tcp:send(Socket, [0] ++ "hello from erlang" ++ [255]),


loop(Socket);
Any ->
io:format("Received:~p~n",[Any]),
loop(Socket)
end.

unframe([0|T]) -> unframe1(T).

unframe1([255]) -> [];
unframe1([H|T]) -> [H|unframe1(T)].

Johann Höchtl

unread,
Dec 10, 2009, 8:21:58 AM12/10/09
to erlang-q...@erlang.org

On Dec 10, 1:56 pm, Joe Armstrong <erl...@gmail.com> wrote:
> Thanks now it works beautifully, I've enclosed listings below.
>
> First reflection - this is amazing - the overhead is tiny and there is
> no parsing
> headers etc. The erlang just had to send
>
> [0] ... bytes .. [255] and it ended up in the browser.
>
> This will kill Ajax, keep-alive connections etc, now all google has to
> do is ship
> the parse trees of HTML pages instead of *text* and browsers can skip parsing
> and concentrate on rendering and stuff will go fast ...
>

This is incredibly awsome! I am sure this will inevitably change the
way we think about the web, clouds, the whole client-server
architecture in general within a short timespan.

Johann

Joe Armstrong

unread,
Dec 10, 2009, 8:32:23 AM12/10/09
to Jayson Vantuyl, Colm Dougan, Erlang
On Thu, Dec 10, 2009 at 2:19 PM, Jayson Vantuyl <jvan...@engineyard.com> wrote:
> I don't know if I'd call that an AJAX killer just yet.  Particularly, until IE has a usable implementation.

But I think it will kill ajax and comet and all that crap. Ajax is
painful if you only want to send very small amounts of data, you still
have to spend all your time
parsing the http headers. Comet and long-poll etc will die since they
are totally
unecessary.

What I hope will happen that Google will pre-empt some action in firefox and
this will push Microsoft into action - I can't understand why this has
taken so long
after all it's merely a question of *removing* code from the browser
and giving access to the low-level socket interface.

It will make applications symmetric - anything that involved pushing data to
the client was tricky hence the horrific workarounds that comet and
long-poll involved - now things like chat in the browser become
symmetric push/pull applications.

About time say I - I've waited years for this.

/Joe


>
> Also, I find this to be a really odd spec, because the "bytes" part is not "bytes", but it's supposed to be UTF-8.  It seems odd to use binary framing around UTF-8 with something that looks like a web connection and runs over the same ports as HTTP.  It looks to me like AJAX isn't dying, but rather HTTP.  After all, I can't imagine why they would pick UTF-8 unless they wanted to encode header-style data or, surprise, XML!  Even the framing is unfriendly to full, binary protocols.
>
> I, personally, would have preferred an actual framed, byte-level protocol over HTTP-lite.  :(

Yup - they could have sent a variable length header, containing the
length length (N) followed by N bytes - but that would be too easy ...

> --
> Jayson Vantuyl
> kag...@souja.net

Max Lapshin

unread,
Dec 10, 2009, 8:42:11 AM12/10/09
to Joe Armstrong, Jayson Vantuyl, Colm Dougan, Erlang
I don't think, that this technology will kill anything because of many
problems with routers, proxy servers, antiviruses.

Do you know, how antivirus handle endless HTTP stream? It waits
request end, save to disk and check there. This is why
endless-http is dead.

We are using RTMP in our production. It is a statefull binary
protocol. It is 100% unreliable, because lots of corporate proxies
don't allow it. And these proxies will not allow websockets.

ingo.schramm

unread,
Dec 10, 2009, 10:14:13 AM12/10/09
to erlang-q...@erlang.org
Is somebody already doing web sockets in Erlang? I just read the specs
today and thought it could be a good practice to learn more about
Erlang during the last weeks of the year. But I'm doing Erlang for
just a few months now and there might be some senior doing stuff like
this in a day.

Ingo

Rapsey

unread,
Dec 10, 2009, 10:32:59 AM12/10/09
to erlang-q...@erlang.org
Isn't it designed to work through HTTP? It's definitely a much better
solution than what is available for comet.


Sergej

Max Lapshin

unread,
Dec 10, 2009, 10:38:16 AM12/10/09
to Rapsey, erlang-q...@erlang.org
On Thu, Dec 10, 2009 at 6:32 PM, Rapsey <rap...@gmail.com> wrote:
> Isn't it designed to work through HTTP? It's definitely a much better
> solution than what is available for comet.
>

Either I've missed something from documentation, either there is told
about statefull connection.

Tony Arcieri

unread,
Dec 10, 2009, 10:40:27 AM12/10/09
to Max Lapshin, Joe Armstrong, Jayson Vantuyl, Colm Dougan, Erlang
On Thu, Dec 10, 2009 at 6:42 AM, Max Lapshin <max.l...@gmail.com> wrote:

> And these proxies will not allow websockets.
>

With reverse HTTP how do you distinguish websockets from normal HTTP
requests?

--
Tony Arcieri
Medioh! A Kudelski Brand

ingo.schramm

unread,
Dec 10, 2009, 10:41:13 AM12/10/09
to erlang-q...@erlang.org
No. It just has a HTTP handshake. Then it switches and uses a new
protocol: web sockets.

On Dec 10, 4:32 pm, Rapsey <rap...@gmail.com> wrote:
> Isn't it designed to work through HTTP? It's definitely a much better
> solution than what is available for comet.

________________________________________________________________

Dmitry Belyaev

unread,
Dec 10, 2009, 10:51:00 AM12/10/09
to Rapsey, erlang-q...@erlang.org
If this feature worked through HTTP then server side would have to
extract message from HTTP packet. In example shown there was no games
with HTTP.

What about proxy servers, I hope they will be redesigned to let WS work.

Max Lapshin

unread,
Dec 10, 2009, 10:55:36 AM12/10/09
to Dmitry Belyaev, Rapsey, erlang-q...@erlang.org
On Thu, Dec 10, 2009 at 6:51 PM, Dmitry Belyaev <rumata...@nm.ru> wrote:
> If this feature worked through HTTP then server side would have to
> extract message from HTTP packet. In example shown there was no games
> with HTTP.
>
> What about proxy servers, I hope they will be redesigned to let WS work.

Look, from server point of view, there is no difference between comet
and web socket.
Differs only the common time of being connected.

Senthilkumar Peelikkampatti

unread,
Dec 10, 2009, 11:01:27 AM12/10/09
to erlang-q...@erlang.org
Joe,
Thanks for heads up. We are working on websocket and repository
is setup at http://github.com/sendtopms/erlwebsockserver. Initial
target is Mochiweb and we are planning for supporting other app
servers like inet and yaws.

--Senthil

--
Regards,
Senthilkumar Peelikkampatti,
http://pmsenthilkumar.blogspot.com/

Joe Armstrong

unread,
Dec 10, 2009, 11:08:55 AM12/10/09
to Senthilkumar Peelikkampatti, erlang-q...@erlang.org
Brilliant - the race is on - then add a json/erlang term format
abstartionn layer on top
of the raw socket interface.

Another group should do an in-line chat engine

Use a DHT for the users and we could make an infinitly scabale IRC engine :-)

/Joe

Senthilkumar Peelikkampatti

unread,
Dec 10, 2009, 11:17:08 AM12/10/09
to Joe Armstrong, erlang-q...@erlang.org
Perfect. Inherent nature of the Erlang (message passing and its
concurrency handling) is perfect fit for Websocket. Json would have
been easy without resorting to json modules if it is available as BIF
in erlang as you suggested earlier somewhere, nontheless it is not big
deal to provide json capability and we will certainly do it.
Thanks Joe.

Senthilkumar Peelikkampatti

unread,
Dec 10, 2009, 11:36:09 AM12/10/09
to Joe Armstrong, erlang-q...@erlang.org
Firefox and Websocket,

Firefox also implemented Websocket but code is still in trunck for
almost an year. It is the first one before chrome implemented but it
the chrome came to market first. Whole history can be found at
https://bugzilla.mozilla.org/show_bug.cgi?id=472529.

Hynek Vychodil

unread,
Dec 10, 2009, 11:39:15 AM12/10/09
to Senthilkumar Peelikkampatti, Joe Armstrong, erlang-q...@erlang.org
I have read it's specification and payload of currently defined frames
must be valid utf-8. It is little bit annoying. I would like fill
frames with BERT or UFB. Implement BERT-RPC or UBF-RPC sounds great
for me. Implementation of BERT or UBF in V8 should be considerable
fast.

On Thu, Dec 10, 2009 at 5:17 PM, Senthilkumar Peelikkampatti

--
--Hynek (Pichi) Vychodil

Analyze your data in minutes. Share your insights instantly. Thrill
your boss. Be a data hero!
Try Good Data now for free: www.gooddata.com

Jarrod Roberson

unread,
Dec 10, 2009, 1:13:55 PM12/10/09
to Hynek Vychodil, Senthilkumar Peelikkampatti, Joe Armstrong, erlang-q...@erlang.org
On Thu, Dec 10, 2009 at 11:39 AM, Hynek Vychodil <hy...@gooddata.com> wrote:
> I have read it's specification and payload of currently defined frames
> must be valid utf-8. It is little bit annoying. I would like fill
> frames with BERT or UFB. Implement BERT-RPC or UBF-RPC sounds great
> for me. Implementation of BERT or UBF in V8 should be considerable
> fast.
>

yeah I wish they would quit redefining new protocols, I try and use
BEEP when ever possible.
It is way more featureful than this new web sockets stuff from a
developers point of view.
It handles most cases and you can transport text or binary or whatever you want.

Per Melin

unread,
Dec 10, 2009, 2:13:52 PM12/10/09
to Erlang, Joe Armstrong
On Thu, Dec 10, 2009 at 2:32 PM, Joe Armstrong <erl...@gmail.com> wrote:
> What I hope will happen that Google will pre-empt some action in firefox and
> this will push Microsoft into action - I can't understand why this has
> taken so long

In the real world site owners are beginning to get their hopes up
about dropping support for IE6, an eight year old browser, soon.
Hopefully we don't have to wait as long as eight years for IE7's
market share to dwindle enough to be ignorable, but I'm not holding my
breath waiting for ajax and comet to be superseded in any practical
setting.

(I have two deployed apps using combinations of forever-frames, long
polling and other HTTP/browser abuses, and it's a disgusting mess.)

Tony Arcieri

unread,
Dec 10, 2009, 4:13:15 PM12/10/09
to Max Lapshin, Dmitry Belyaev, Rapsey, erlang-q...@erlang.org
On Thu, Dec 10, 2009 at 8:55 AM, Max Lapshin <max.l...@gmail.com> wrote:

> Look, from server point of view, there is no difference between comet
> and web socket.
> Differs only the common time of being connected.
>

Comet uses "long polling". The client connects, sends a request, and the
server doesn't respond until an event is occurred. The client socket can
time out, in which case it reconnects. When the client gets a response, it
consumes it and closes the socket. Once the event is processed, the client
makes a new long polling connection to the server.

Websockets let you use RHTTP. The client connects, sends a request to
switch to RHTTP, then becomes an HTTP server. This is a true push model, as
opposed to Comet long polling. The remote can push an unlimited number of
events back to the client via RHTTP, as the client is now acting as a
server. The connection between the client and server is never dropped
unless something goes wrong, as opposed to Comet where the connection is
dropped once per event at a minimum.

Reply all
Reply to author
Forward
0 new messages