2013-03-12 3 views
1

Erlang에서 새로 생겼습니다. 나는 Erlang에서 서버로 RFC6455 (websocket)을 작성해야하는데, HTTP 101로 응답 할 수있는 모든 것을 작성한다. RFC6455의 예제와 위키 피 디아의 예제와 결과를 동일하게 계산하려고하기 때문에 헤더를 받아 들일 수 있다고 생각한다. 브라우저에서 HTTP 101을 보내면 websocket의 onerror 이벤트가 발생하고 서버에서는 소켓을 닫지 않지만 소켓이 닫혀있는 것을 볼 수 있습니다.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 만 추가하십시오.