2017-11-22 17 views
2

websocket 연결을 수신하는 ws_handler가 있습니다.Cowboy Websocket 처리기에서 상태를 업데이트하면 자동으로 충돌이 발생하거나 무시됩니다.

이 프로세스는 로그인 할 때 <<"h으로 시작하는 입력을 기다립니다.

는 그러므로 기본 웹 소켓 상태 (현재 PID에 대한 참조 스폰) 플레이어 프로세스 ID, 및 발신 메세지 '< < "turn1">>

websocket_handle({text, <<"h", Name/binary>>}, State) -> 
    {ok, PID} = player:go(self(), <<"profiledata", Name/binary>>), 
    erlang:start_timer(1000, self(), <<"Hello!">>), 
    {reply, {text, <<"You joined, ", Name/binary>>}, {State, PID, <<"turn1">>}}; 

I 절약 이 별도의 플레이어 프로세스에서 데이터 흐름을 제어하려면 내 websocket 처리기에서 메시지를 검색하여 Outbox 요소를 통해 클라이언트에 전달해야합니다.

websocket_info(myscreenupdate, State = {St,P, _}) -> 
    {reply, {text, <<"My screen update">>}, {St, P, <<"turn2">>}}; 
:
websocket_handle({text, <<"myscreen">>}, S = {_, P, _}) -> 
    gen_server:call(P, myscreen), 
    {ok, S}; 

및 player.erl에서

,
handle_call(myscreen, _, {WS, Profile, Cab}) -> 
    gen_server:cast(WS, myscreenupdate), 
    {reply, ok, {WS, Profile, Cab}}; 

돌아 가기 ws_handler에서 나는이 전화를받을 것으로 예상 :

그래서 나는 수동으로 메시지를 트리거하기 위해이에 추가

그러나 내 브라우저에서 출력되는 websocket은대신에 turn1을 계속 인쇄합니다..

gen_server:callplayer.erl에 시도했는데 시간 초과 오류가 발생합니다. 나는 ws_handlerwebsocket_handle{reply 튜플가 웹 소켓에 회신하도록되어 있기 때문이라고 생각합니다 ..하지만이 사실이라면, 나는 데이터의 업데이트가 기대 :

websocket_info(myscreenupdate, State = {St,P, _}) -> 
    {reply, {text, <<"My screen update">>}, {St, P, <<"turn2">>}}; 

그래서 난 여기서 무슨 일이 일어나고 있는지 불확실합니다.

플레이어 프로세스에서 상태를 업데이트 한 다음 내 websocket 처리기에서 해당 상태를 검색하여 연결에 보내는 방법은 무엇입니까?

ws_handler.erl: 

-module(ws_handler). 

-export([init/2]). 
-export([websocket_init/1]). 
-export([websocket_handle/2]). 
-export([websocket_info/2]). 

init(Req, Opts) -> 
    {cowboy_websocket, Req, Opts}. 

websocket_init(State) -> 
    {ok, State}. 

websocket_handle({text, <<"h", Name/binary>>}, State) -> 
    {ok, PID} = player:go(self(), <<"profiledata", Name/binary>>), 
    erlang:start_timer(1000, self(), <<"Hello!">>), 
    {reply, {text, <<"You joined, ", Name/binary>>}, {State, PID, <<"turn1">>}}; 

websocket_handle({text, <<"myscreen">>}, S = {_, P, _}) -> 
    gen_server:call(P, myscreen), 
    {ok, S}; 

websocket_handle({text, <<"auth", Auth/binary>>}, S = {_St, P, _}) -> 
    case s:s(P, Auth) of 
    {ok, Valid} -> {reply, {text, << "Authorized">>}, S}; 
    _ -> {reply, {text, <<"Error">>}, S} 
    end; 
websocket_handle({text, Msg}, S = {_St, P, Outbox}) -> 
    {reply, {text, Outbox}, S}; 
websocket_handle(_Data, State) -> 
    {ok, State}. 

websocket_info(myscreenupdate, State = {St,P, _}) -> 
    {reply, {text, <<"My screen update">>}, {St, P, <<"turn2">>}}; 

websocket_info({timeout, _Ref, _Ignored}, State = {_, P, Outbox}) -> 
    erlang:start_timer(1000, self(), <<"This is ignored">>), 
    Msg = Outbox, 
    {reply, {text, Msg}, State}; 
websocket_info(_Info, State) -> 
    {ok, State}. 

player.erl : 문제는 그 카우보이의 websocket_info/2 핸들러는 동등의, 얼랑 내장 된 메시지 연산자 !를 사용 (또는하여 웹 소켓 과정에 보낸 메시지를받을 것입니다

-module(player). 
-compile(export_all). 

handle_call(myscreen, _, {WS, Profile, Cab}) -> 
    gen_server:cast(WS, myscreenupdate), 
    {reply, ok, {WS, Profile, Cab}}; 
handle_call(get_profile, _, State = {_WSPID, Profile, _}) -> 
    {reply, Profile, State}. 

init([WSPID, Profile]) -> 
    {ok, {WSPID, Profile, null}}; 
init([WSPID, Profile, CabinetPID]) -> 
    {ok, {WSPID, Profile, CabinetPID}}. 

go(WSPID, Profile, CabinetPID) -> 
    gen_server:start_link(?MODULE, [WSPID, Profile, CabinetPID], []). 
go(WSPID, Profile) -> 
    gen_server:start_link(?MODULE, [WSPID, Profile], []). 
+0

https://github.com/7stud/Programming-Erlang-Exercises-Solutions-Answers/blob/master/Chapter%2018/simple_example에 도움이되는 것이 있다면 여기를 참조하십시오.md – 7stud

답변

1

erlang:send/{2,3} 기능).

그래서 당신은 수행해야합니다

WS ! myscreenupdate

대신

gen_server:cast(WS, myscreenupdate)

의 당신이 인정 된 메시지가 아닙니다 이후 메시지가 아마도 카우보이 메시지 루프에 의해 삭제됩니다 gen_server:cast를 사용하는 경우. gen_server:call을 사용하면 교착 상태가됩니다.

+0

유효한 답변입니다. 통찰력에 감사 드리며 감사드립니다. – quantumpotato