我是Erlang的新手。我需要在Erlang中写一个RFC6455(websocket)的实现作为服务器,我写的所有可以用HTTP 101响应,我认为接受头是好的,因为我尝试用RFC6455的例子和维基百科的例子计算,结果是一样的。当我在浏览器运行事件中发送HTTP 101以及websocket和服务器中的错误时,我不会关闭套接字但我看到套接字已关闭。我有这段代码:
edumserver.erl
:
-module(edumserver).
-export([start/0]).
start() ->
ssl:start(),
crypto:start(),
edumhttpsserver:start(8883).
edumhttpsserver.erl
:
-module(edumhttpsserver).
-export([start/1]).
-define(RESP_404, <<"HTTP/1.1 404 Not Found
Server: eDum
Connection: Close
">>).
-define(RESP_200, <<"HTTP/1.1 200 OK
Server: eDum
Connection: Close
Content-type: ">>).
start(Puerto) ->
spawn(fun() -> edum_https_init(Puerto) end).
edum_https_init(Puerto) ->
Op = [{certfile,"priv/server.crt"},
{keyfile, "priv/server.key"},
{reuseaddr, true}, {active, false}, {packet, http}],
{ok, Socket} = ssl:listen(Puerto, Op),
edum_https_bucle(Socket).
edum_https_bucle(Socket) ->
{ok, SockCli} = ssl:transport_accept(Socket),
Pid = spawn(fun() -> edum_https_cliente(SockCli, []) end),
ssl:controlling_process(SockCli, Pid),
ssl:setopts(SockCli, [{active, true}]),
edum_https_bucle(Socket).
edum_https_cliente(Socket, Estado) ->
receive
{ssl, Socket, {http_request, Metodo, {abs_path, Ruta}, _}} ->
edum_https_cliente(Socket, Estado ++ [
{method, Metodo}, {path, Ruta}, {secure, true}
]);
{ssl, Socket, {http_header, _, Clave, _, Valor}} ->
edum_https_cliente(Socket, Estado ++ [{Clave, Valor}]);
{ssl, Socket, http_eoh} ->
io:format("Estado: ~p~n", [Estado]),
case proplists:get_value('Upgrade', Estado) of
"websocket" ->
edumwebsocketserver:edum_websocket_cliente(Socket, Estado);
_ ->
Respuesta = edum_https_send_file(Estado),
ssl:send(Socket, Respuesta),
ssl:close(Socket)
end;
{ssl_closed, Socket} ->
ssl:close(Socket);
{ssl, _, {http_error, Msg}} ->
io:format("Error HTTP: ~s~n", [Msg]);
Any ->
io:format("No reconocido ~p~n", [Any]),
ssl:close(Socket)
end.
edum_https_send_file(Peticion) ->
"/" ++ Ruta = proplists:get_value(path, Peticion, "/"),
{ok, CWD} = file:get_cwd(),
JRuta = filename:join(CWD, "priv/html"),
RRuta = filename:join(JRuta, Ruta),
case file:read_file(RRuta) of
{ok, Contenido} ->
Peso = list_to_binary(
io_lib:format("~p", [byte_size(Contenido)])
),
Tipo = edum_https_tipomime(Ruta),
<<
?RESP_200/binary, Tipo/binary,
"\nContent-lenght: ", Peso/binary,
"\r\n\r\n", Contenido/binary
>>;
{error, _} ->
?RESP_404
end.
edum_https_tipomime(Archivo) ->
case filename:extension(string:to_lower(Archivo)) of
".htm" -> <<"text/html">>;
".html" -> <<"text/html">>;
".js" -> <<"application/javascript">>;
".css" -> <<"text/css">>;
_ -> <<"text/plain">>
end.
edumwebsocketserver.erl
:
-module(edumwebsocketserver).
-export([edum_websocket_cliente/2]).
-define(RESP_101, <<"HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: ">>).
-define(WS_UUID, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").
edum_websocket_cliente(Socket, Estado) ->
WSClave = proplists:get_value("Sec-Websocket-Key", Estado),
WSAceptar = base64:encode(crypto:sha(WSClave ++ ?WS_UUID)),
Respuesta = <<?RESP_101/binary, WSAceptar/binary,"\r\n\r\n">>,
ssl:setopts(Socket, [{keepalive, true}]),
ssl:send(Socket, Respuesta),
edum_websocket_cliente_bucle(Socket).
edum_websocket_cliente_bucle(Socket) ->
EstadoSocket = ssl:connection_info(Socket),
io:format("WS ~p ~p~n", [self(), EstadoSocket]),
case EstadoSocket of
{error, Razon} -> ssl:close(Socket), exit(Razon);
_ -> ok
end,
receive
{ssl_closed, Socket} ->
ssl:close(Socket);
Any ->
io:format("WS: ~p~n", [Any])
after 5000 ->
io:format("Nada~n")
end,
edum_websocket_cliente_bucle(Socket).
在行edum_websocket_cliente_bucle(Socket)
中的函数io:format("WS ~p ~p~n", [self(), EstadoSocket])
中,我首先看好套接字,然后在下一个递归调用中看起来错误:{error,closed}
但是我没有关闭,也不明白为什么关闭,我用以下方法接受标题:
WSAceptar = base64:encode(crypto:sha(WSClave ++ ?WS_UUID)),
我用这个例子测试:
具体而言,如上例所示,| Sec-WebSocket-Key |头 字段的值为“dGhlIHNhbXBsZSBub25jZQ ==”,服务器会 将字符串“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”连接起来 字符串 “dGhlIHNhbXBsZSBub25jZQ == 258EAFA5-E914-47DA-95CA-C5AB0DC85B11”。该 然后服务器将获取此的SHA-1哈希值,给出值0xb3 0x7a 0x4f 0x2c 0xc0 0x62 0x4f 0x16 0x90 0xf6 0x46 0x06 0xcf 0x38 0x59 0x45 0xb2 0xbe 0xc4 0xea。然后对该值进行base64编码(参见 [RFC4648]的第4节),给出了值 “s3pPLMBiTxaQ9kYGzzhZRbK + XOO =”。然后将回显此值 | Sec-WebSocket-Accept |标题字段。
和
GET / mychat HTTP / 1.1主机:server.example.com升级:websocket 连接:升级Sec-WebSocket-Key:x3JJHMbDL1EzLkh9GBhXDw == Sec-WebSocket-Protocol:chat Sec-WebSocket-Version:13来源: http://example.com
HTTP / 1.1 101切换协议升级:websocket连接: 升级Sec-WebSocket-Accept:HSmrc0sMlYUkAGmm5OPpG2HaGWk = Sec-WebSocket-Protocol:chat
错误是什么?我是Erlang的新手。在chrome控制台中说出这个错误:“状态行不以CRLF结束”。
答案 0 :(得分:0)