zoukankan      html  css  js  c++  java
  • Erlang 聊天室程序(十一) 主题房间之Supervisor引起的改造

           于由使用了Supervisor来管理当前所有的房间,每个房间都为单独的进程,所以要计对之前的chat_room.erl代码做相应的修改。

           具体包括以下几点:

           1.getPid/0  : 以前是由{local,?Module}房间进程来产生新的客户端进程。这次由于采用simple_one_to_one的启动方式,所以要重新指定客户端进程的产生方式(这里交由大厅来创建)

              所以修改chat_room进程的创建方法,房间名由外部传入,再根据房间名为每个chat_room进程命名。

    start_link(Para)->
        #roominfo{name=Name,type=Type}=Para,
        gen_server:start_link({local,list_to_atom(Name)}, [Para],[]).

             再修改echatServer.erl,启动supervisor后创建大厅子进程

    start()->
        %start supervisor
        room_manager:start_link([]),
        
        %add hall to supervisor
        Para=#roominfo{name="room-hall",type="public"},
        room_manager:startNewRoom(Para),
        
        chat_acceptor:start(3377),
        ok.

           可以看到,这里为大厅指定的进程名为"room-hall",所以下面修改getPid/0

    getPid()->
        Id=id_generator:getnewid(client),
        Pid=gen_server:call(list_to_existing_atom("room-hall"),{getpid,Id}),
        io:format("id generated ~w~n",[Id]),
        #clientinfo{id=Id,pid=Pid}
    .

           2. bindPid/2 : 这次就要指定客户端进程具体要添加到哪个房间中。 同时为了方便后面的操作,我们为chat_room.erl添加两个函数joinRoom/2 和 leaveRoom/2 让客户端通过这两个函数来进入和退出某个房间。

    %joinroom using room-name or room-Pid
    joinRoom(RoomName,ClientInfo) when is_list(RoomName)->
       gen_server:call(list_to_existing_atom(RoomName), {add_clientinfo,ClientInfo})
    ;
    joinRoom(Ref,ClientInfo)->
       gen_server:call(Ref, {add_clientinfo,ClientInfo})
    .

    %leave Room,clean userinfo
    leaveRoom(RoomName,ClientInfo) when is_list(RoomName)->
        gen_server:call(list_to_existing_atom(RoomName), {remove_clientinfo,ClientInfo})
    ;
    leaveRoom(Ref,ClientInfo)->
        gen_server:call(Ref, {remove_clientinfo,ClientInfo})
    .

           在此基础上再修改bindPid/2 (第一次进入房间时默认为进入大厅)

    bindPid(Record,Socket)->    
        io:format("binding socket...~n"),    
        case gen_tcp:controlling_process(Socket, Record#clientinfo.pid) of
            {error,Reason}->
                io:format("binding socket...error~n");
            ok ->
                NewRec =#clientinfo{id=Record#clientinfo.id,socket=Socket,pid=Record#clientinfo.pid},
                %gen_server:call(list_to_existing_atom("room-hall"), {add_clientinfo,NewRec}),
                joinRoom("room-hall",NewRec),
                %then we send info to clientSession to update it's State (Socket info)
                Pid=Record#clientinfo.pid,
                Pid!{bind,Socket},
                io:format("clientBinded~n")
        end
    .

          3.setUserInfo/1 的改造。整个系统中,用户信息可以通过两个地方获取:1用户进程绑定的PID,它是一个gen_server,用户信息保存于State中。2用户信息存在用户所在房间的clientManager管理的ets表中。要更新用户信息,这两个地方就都要更新。

          先修改chat_room.erl部分:

    setUserInfo(RoomName,Message) when is_list(RoomName)->
        gen_server:call(list_to_existing_atom(RoomName), {set_clientinfo,Message})
    ;
    setUserInfo(Ref,Message)->
        gen_server:call(Ref, {set_clientinfo,Message})
    .

         再修改客户端部分,由于所有接受到的消息都是交由message_router路由的,所以修改message_router.erl中的代码:

         Message消息需要在这里被解析为#clientinfo

    routeMessage(Type,Sub,Message,State)->
            #clientinfo{pid=From}=State,
            case Type of
            "msg"->
                    case Sub of
                        "chat"->
                            io:format("message_router:route to chat_room:broadcast:~p~n",[Message]),
                            chat_room:broadCastMsg(Message);                    
                        _Els->
                            io:format("unkonw msssage subject:~p~n",[Sub])
                    end;
            "set"->
                    case Sub of
                        "clientinfo"->
                            #message{content=Info,from=Key}=Message,
                            Rec =util_SetInfoParas:paraElements(Info),
                            From!{setinfo,Rec},
                            chat_room:setUserInfo(Message);

            4.broadCastMsg/1

    %%broad CastMsg to all connected clientSessions
    broadCastMsg(RoomName,Msg) when is_list(RoomName)->
        gen_server:call(list_to_existing_atom(RoomName), {sendmsg,Msg})
    ;
    broadCastMsg(Ref,Msg)->
        gen_server:call(Ref, {sendmsg,Msg})
    .

           5.getMembers/1

    getMembers(RoomName,Message)->
        gen_server:call(list_to_existing_atom(RoomName), {get_member,Message})
    ;
    getMembers(Ref,Message)->
        gen_server:call(Ref, {get_member,Message})
    .

  • 相关阅读:
    C++11新特性
    Qt操作xml
    指针和引用的区别
    QT软件主题切换
    常见的临时变量的生成场景
    QQuickWidget+QML设置背景透明
    idea maven Could not transfer artifact
    Java项目启动时执行指定方法的几种方式
    解决bootstrap-table在切换分页后再次查询报错404问题
    bootstrap:表单必填项*标识,及提交前校验
  • 原文地址:https://www.cnblogs.com/yjl49/p/2424243.html
Copyright © 2011-2022 走看看