我正在使用Erlang开发聊天应用程序,我想在创建客户端时存储名称,现在我只是存储Pid。我正在使用Record来存储Value。 我想在客户端发送消息时获取名称,所以我必须从Pid中找到名字。我正在使用erlang 17。
chat_room.erl
-module(chat_room).
-behaviour(gen_server).
-export([start_link/0, enter/2, leave/1, send_message/2, find_user/1]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
code_change/3]).
-define(SERVER, ?MODULE).
-record(state, {clients=[],name}).
%%%=============================================================================
%%% API
%%%=============================================================================
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
enter(Pid, Name) ->
gen_server:cast(?SERVER, {enter, Pid, Name}).
leave(Pid) ->
gen_server:cast(?SERVER, {leave, Pid}).
send_message(Pid, Message) ->
gen_server:cast(?SERVER, {send_message, Pid, Message}).
find_user(Pid) ->
gen_server:cast(?SERVER, {find_user, Pid}).
%%%=============================================================================
%%% gen_server callbacks
%%%=============================================================================
init([]) ->
Dispatch = cowboy_router:compile([
{'_', [
{"/ws", chat_ws_handler, []},
{"/", cowboy_static,
[{directory, {priv_dir, chat, [<<"static">>]}},
{file, <<"index.html">>},
{mimetypes, {fun mimetypes:path_to_mimes/2, default}}]},
{"/static/[...]", cowboy_static,
[{directory, {priv_dir, chat, [<<"static">>]}},
{mimetypes, {fun mimetypes:path_to_mimes/2, default}}]}
]}
]),
cowboy:start_http(chat, 100,
[{port, 8080}],
[{env, [{dispatch, Dispatch}]}]),
{ok, #state{}}.
handle_call(_Request, _From, State) ->
{noreply, State}.
handle_cast({enter, Pid, Name}, State = #state{clients= Clients}) ->
{noreply, State#state{clients = [Pid|Clients],name=Name}};
handle_cast({leave, Pid}, State = #state{clients = Clients}) ->
{noreply, State#state{clients = Clients -- [Pid]}};
handle_cast({find_user, Pid}, State= #state{clients = Clients}) ->
io:format("List: ~p", [State]),
{noreply, State};
handle_cast({send_message, Pid, Message}, State) ->
do_send_message(Pid, Message, State),
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
cowboy:stop_listener(chat).
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%%=============================================================================
%%% Internal functions
%%%=============================================================================
do_send_message(Pid, Message, #state{clients = Clients}) ->
OtherPids = Clients -- [Pid],
lists:foreach(
fun(OtherPid) ->
OtherPid ! {send_message, self(), Message}
end, OtherPids).
如果我使用现有结构,如何从Pid中找到名字?
答案 0 :(得分:0)
使用现有的结构,我猜你要向client-pid发送一条消息,询问它的名字并在那里写一个处理程序来回复。
但让服务器存储名称到pid的映射以及通过名称而不是pid发送消息似乎是明智的。
答案 1 :(得分:0)
我最近自己实施了一个类似的应用程序(https://github.com/huseyinyilmaz/talkybee和后端https://github.com/huseyinyilmaz/publicator)并且我的流程结构是这样的。
[牛仔连接流程] - &gt; [user_processes] - &gt; [room_processes]
因此,如果您使用类似的结构,您可以在用户进程上保存名称(每个用户都有一个进程),当您需要用户名时,您可以询问进程的名称。
要明确:
我希望有所帮助。
答案 2 :(得分:0)
以下是我为enter
和leave
所做的事情。我将find_user
和do_send
作为练习(提示:请参阅列表:keyfind)。
handle_cast({enter, Pid, Name}, State = #state{clients= Clients}) ->
{noreply, State#state{clients = [{Pid, Name} | Clients]}};
handle_cast({leave, Pid}, State = #state{clients = Clients}) ->
{noreply, State#state{clients = lists:keydelete(Pid, 1, Clients)}};