2013-03-12 42 views
1

我是Erlang中的新成员。我需要在Erlang中编写一个作为服务器的RFC6455(websocket)的实现,我写的所有代码都可以用HTTP 101响应,并且我认为接受头文件很好,因为我尝试用RFC6455的示例进行计算,并且结果相同。当我在浏览器中发送HTTP 101事件onsror websocket和服务器时,我不关闭套接字,但我看到该套接字已关闭。我有这样的代码:Erlang套接字中的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}

但我不接近,不明白为什么近,我calc下接受头:

WSAceptar = base64:encode(crypto:sha(WSClave ++ ?WS_UUID)), 

那我这个例子测试:

Concretely, if as in the example above, the |Sec-WebSocket-Key| header field had the value "dGhlIHNhbXBsZSBub25jZQ==", the server would concatenate the string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" to form the string "dGhlIHNhbXBsZSBub25jZQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11". The server would then take the SHA-1 hash of this, giving the value 0xb3 0x7a 0x4f 0x2c 0xc0 0x62 0x4f 0x16 0x90 0xf6 0x46 0x06 0xcf 0x38 0x59 0x45 0xb2 0xbe 0xc4 0xea. This value is then base64-encoded (see Section 4 of [RFC4648]), to give the value "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=". This value would then be echoed in the |Sec-WebSocket-Accept| header field.

和:

GET /mychat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Protocol: chat Sec-WebSocket-Version: 13 Origin: http://example.com

HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat

什么错误?我是Erlang的新人。在铬控制台中说这个错误:“状态行不以CRLF结束”。

回答

0

我解决了。只在第一行添加回复\ r \ n。