erlang实现websocket简单示例
2014-04-17 09:16
846 查看
本示例仅支持文本消息
基于websocket版本13
由于joe armstrong的例子:
http://armstrongonsoftware.blogspot.com/2009/12/comet-is-dead-long-live-websockets.html 已经过时,不符合现在的websocket标准,于是改写了一下
还参考了cowboy的代码:
https://github.com/extend/cowboy
websocket标准参考: http://blog.csdn.net/fenglibing/article/details/6852497
后端代码:
-module(local_server). -export([start/0]). start() -> F = fun interact/2, spawn(fun() -> start(F, 0) end). start(F, State0) -> {ok, Listen} = gen_tcp:listen(8000, [{packet,raw}, {reuseaddr,true}, {active, true}]), par_connect(Listen, F, State0). par_connect(Listen, F, State0) -> case gen_tcp:accept(Listen) of {ok, Socket} -> spawn(fun() -> par_connect(Listen, F, State0) end), wait(Socket, F, State0); {error, closed} -> {ok, Listen2} = gen_tcp:listen(8000, [{packet,raw}, {reuseaddr,true}, {active, true}]), par_connect(Listen2, F, State0) end. wait(Socket, F, State0) -> receive {tcp, Socket, Data} -> Key = list_to_binary(lists:last(string:tokens(hd(lists:filter(fun(S) -> lists:prefix("Sec-WebSocket-Key:", S) end, string:tokens(Data, "\r\n"))), ": "))), Challenge = base64:encode(crypto:sha(<< Key/binary, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" >>)), Handshake = ["HTTP/1.1 101 Switching Protocols\r\n", "connection: Upgrade\r\n", "upgrade: websocket\r\n", "sec-websocket-accept: ", Challenge, "\r\n", "\r\n",<<>>], gen_tcp:send(Socket, Handshake), send_data(Socket, "Hello, my world"), S = self(), Pid = spawn_link(fun() -> F(S, State0) end), loop(Socket, Pid); _Any -> wait(Socket, F, State0) end. loop(Socket, Pid) -> receive {tcp, Socket, Data} -> Text = websocket_data(Data), case Text =/= <<>> of true -> Pid ! {browser, self(), ["You said: ", Text]}; false -> ok end, loop(Socket, Pid); {tcp_closed, Socket} -> ok; {send, Data} -> send_data(Socket, Data), loop(Socket, Pid); _Any -> loop(Socket, Pid) end. interact(Browser, State) -> receive {browser, Browser, Str} -> Browser ! {send, Str}, interact(Browser, State) after 1000 -> Browser ! {send, "clock ! tick " ++ integer_to_list(State)}, interact(Browser, State+1) end. %% 仅处理长度为125以内的文本消息 websocket_data(Data) when is_list(Data) -> websocket_data(list_to_binary(Data)); websocket_data(<< 1:1, 0:3, 1:4, 1:1, Len:7, MaskKey:32, Rest/bits >>) when Len < 126 -> <<End:Len/binary, _/bits>> = Rest, Text = websocket_unmask(End, MaskKey, <<>>), Text; websocket_data(_) -> <<>>. %% 由于Browser发过来的数据都是mask的,所以需要unmask websocket_unmask(<<>>, _, Unmasked) -> Unmasked; websocket_unmask(<< O:32, Rest/bits >>, MaskKey, Acc) -> T = O bxor MaskKey, websocket_unmask(Rest, MaskKey, << Acc/binary, T:32 >>); websocket_unmask(<< O:24 >>, MaskKey, Acc) -> << MaskKey2:24, _:8 >> = << MaskKey:32 >>, T = O bxor MaskKey2, << Acc/binary, T:24 >>; websocket_unmask(<< O:16 >>, MaskKey, Acc) -> << MaskKey2:16, _:16 >> = << MaskKey:32 >>, T = O bxor MaskKey2, << Acc/binary, T:16 >>; websocket_unmask(<< O:8 >>, MaskKey, Acc) -> << MaskKey2:8, _:24 >> = << MaskKey:32 >>, T = O bxor MaskKey2, << Acc/binary, T:8 >>. %% 发送文本给Client send_data(Socket, Payload) -> Len = iolist_size(Payload), BinLen = payload_length_to_binary(Len), gen_tcp:send(Socket, [<< 1:1, 0:3, 1:4, 0:1, BinLen/bits >>, Payload]). payload_length_to_binary(N) -> case N of N when N =< 125 -> << N:7 >>; N when N =< 16#ffff -> << 126:7, N:16 >>; N when N =< 16#7fffffffffffffff -> << 127:7, N:64 >> end.
前端使用js发送websocket请求
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Websocket client</title> <script src="jquery.min.js"></script> <script type="text/javascript"> var websocket; $(document).ready(init); function init() { if(!("WebSocket" in window)){ $('#status').append('<p><span style="color: red;">websockets are not supported </span></p>'); $("#navigation").hide(); } else { $('#status').append('<p><span style="color: green;">websockets are supported </span></p>'); connect(); }; $("#connected").hide(); $("#content").hide(); }; function connect() { showScreen('<span style="color: red;">CONNECTING </span>'); wsHost = $("#server").val() websocket = new WebSocket(wsHost); showScreen('<b>Connecting to: ' + wsHost + '</b>'); websocket.onopen = function(evt) { onOpen(evt) }; websocket.onclose = function(evt) { onClose(evt) }; websocket.onmessage = function(evt) { onMessage(evt) }; websocket.onerror = function(evt) { onError(evt) }; }; function disconnect() { websocket.close(); }; function toggle_connection(){ if(websocket.readyState == websocket.OPEN){ disconnect(); } else { connect(); }; }; function sendTxt() { if(websocket.readyState == websocket.OPEN){ txt = $("#send_txt").val(); websocket.send(txt); showScreen('sending: ' + txt); } else { showScreen('websocket is not connected'); }; }; function onOpen(evt) { showScreen('<span style="color: green;">CONNECTED </span>'); $("#connected").fadeIn('slow'); $("#content").fadeIn('slow'); }; function onClose(evt) { showScreen('<span style="color: red;">DISCONNECTED </span>'); }; function onMessage(evt) { showScreen('<span style="color: blue;">RESPONSE: ' + evt.data+ '</span>'); }; function onError(evt) { showScreen('<span style="color: red;">ERROR: ' + evt.data+ '</span>'); }; function showScreen(txt) { $('#output').prepend('<p>' + txt + '</p>'); }; function clearScreen() { $('#output').html(""); }; </script> </head> <body> <div id="header"> <h1>Websocket client</h1> <div id="status"></div> </div> <div id="navigation"> <p id="connecting"> <input type='text' id="server" value="ws://localhost:8000/websocket"></input> <button type="button" onclick="toggle_connection()">connection</button> </p> <div id="connected"> <p> <input type='text' id="send_txt" value=></input> <button type="button" onclick="sendTxt();">send</button> </p> </div> <div id="content"> <button id="clear" onclick="clearScreen()" >Clear text</button> <div id="output"></div> </div> </div> </body> </html>
附件(内含上文代码及jquery和erlang编译后的beam文件)下载地址:
http://files.cnblogs.com/suex/websocket_demo.zip
在解压后的文件夹中启动erlang shell, 执行local_server:start()即可启动服务端,
此时打开index.html即可看到文首的截图效果
相关文章推荐
- erlang实现websocket简单示例
- NodeJS简单实现WebSocket功能示例
- 用vue的双向绑定简单实现一个todo-list的示例代码
- 基于Java实现的一层简单人工神经网络算法示例
- C#实现数据库事务处理的简单示例代码
- C#实现COM:简单示例
- python实现数据库查询的简单示例
- jQuery简单实现彩色云标签效果示例
- SkylineGlobe 6.5 如何实现简单多边形的动态绘制 C#示例代码
- Skinned Mesh原理解析和一个最简单的实现示例
- 爬虫简单示例,用httpClient4.2.1实现(转载)
- PHP简单实现数字分页功能示例
- JS简单实现父子窗口传值功能示例【未使用iframe框架】
- 一个简单的 iBatis 实现——完整示例
- HTML5 WebSocket(Client) + JavaWeb(Server) 实现简单的聊天室功能
- Python爬虫实现简单的爬取有道翻译功能示例
- jQuery实现简单的网页换肤效果示例
- 原生websocket简单实现即时通信功能-注解方式
- websocket实现简单聊天程序
- 使用Java实现希尔排序算法的简单示例