2013-03-12 68 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。