erlang gen_tcp 实现 websocket支持写一个demo
以下是一个简单的 Erlang demo,用于实现 WebSocket 支持:
-module(websocket).
-export([start/0]).
start() ->
{ok, Listen} = gen_tcp:listen(8080, [{active, false}, {reuseaddr, true}]),
loop(Listen).
loop(Listen) ->
{ok, Socket} = gen_tcp:accept(Listen),
spawn(fun() -> handle(Socket) end),
loop(Listen).
handle(Socket) ->
{ok, Request} = gen_tcp:recv(Socket, 0),
{_, Headers, _} = httpd:parse_request(Request),
case lists:member({'Upgrade', 'websocket'}, Headers) of
true ->
Key = get_key(Headers),
Response = build_response(Key),
gen_tcp:send(Socket, Response),
loop(Socket);
false ->
gen_tcp:close(Socket)
end.
loop(Socket) ->
{ok, Data} = gen_tcp:recv(Socket, 0),
case Data of
[<<129:8, Length:7, Mask:1>>|Payload] ->
PayloadData = unmask(Payload, Mask),
handle_message(Socket, PayloadData),
loop(Socket);
_ ->
gen_tcp:close(Socket)
end.
get_key(Headers) ->
{_, Key} = lists:keyfind('Sec-WebSocket-Key', 1, Headers),
sha1_base64(Key ++ "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").
build_response(Key) ->
Response = << "HTTP/1.1 101 Switching Protocols\r\n">>,
Response = << Response/binary, "Upgrade: websocket\r\n">>,
Response = << Response/binary, "Connection: Upgrade\r\n">>,
Response = << Response/binary, "Sec-WebSocket-Accept: ">>,
Response = << Response/binary, Key/binary>>,
Response = << Response/binary, "\r\n\r\n">>,
Response.
unmask(Payload, Mask) ->
unmask(Payload, Mask, 0, []).
unmask([], _, _, Acc) ->
lists:reverse(Acc);
unmask([Byte|Tail], Mask, Index, Acc) ->
MaskByte = element((Index rem 4) + 1, Mask),
Unmasked = Byte bxor MaskByte,
unmask(Tail, Mask, Index + 1, [Unmasked|Acc]).
handle_message(Socket, Payload) ->
io:format("~s~n", [Payload]),
gen_tcp:send(Socket, <<131:8, 5:1, "hello">>).
这个 demo 实现了一个简单的 WebSocket 服务器,监听本地 8080 端口。当一个新的连接到达时,它会检查是否是 WebSocket 请求。如果是,它会构建一个响应,表示升级到 WebSocket。一旦连接成功升级,它就会进入一个循环,接收和处理消息。在这个 demo 中,它只是简单地将接收到的消息打印到控制台,并回复一个固定的消息。
原文地址: https://www.cveoy.top/t/topic/bkly 著作权归作者所有。请勿转载和采集!