zoukankan      html  css  js  c++  java
  • Erlang 聊天室程序(十) 主题房间3 创建、关闭和查询

         为了后面的功能,这里先实现主题房间的开启、关闭和查询。这些都是对客户端行为的响应,正常情况下需要管理员权限,由于权限部分还未实现所以这里暂时不考虑。

         先定义消息格式:

         开启:     

          #message{type="set",subject="openroom",content=#roominfo{type="type",name="name"}}

          #message{type="result",subject="openroom",content="succ/failed"}

         关闭:

          #message{type="set",subject="closeroom",content=#roominfo{id="id"}}

          #message{type="result",subject="closeroom",content="succ/failed"}

          查询:

          #message{type="get",subject="roominfo",content="all"}

          #message{type="result",subject="roominfo",content=[#roominfo,#roominfo......]}

         服务器代码:

         修改message_router.erl 对接收到的消息进行解析和路由:

    routeMessage(Type,Sub,Message,State)->
            #clientinfo{pid=From}=State,
            case Type of
            "msg"->
                    ......
            "set"->
                    case Sub of
                        "clientinfo"->
                            ......
                        "openroom"->
                            RoomInfo=util_RoomInfoParas:paraElements(Message),
                            ResultMessage=
                            if 
                                is_record(RoomInfo,roominfo)->
                                    Result=case room_manager:startNewRoom(RoomInfo)of
                                        {fail,room_exists}->
                                            %send failed message to client
                                            #message{type="result",subject="openroom",content="failed name exists"};
                                        {succ,ok}->
                                            #message{type="result",subject="openroom",content="failed name exists"}
                                    end;
                                true->
                                    io:format("illegal RoomInfo subject:~p~n",[RoomInfo]),
                                    %we should return failed message to client
                                    #message{type="result",subject="openroom",content="failed illegal roominfo"}
                            end,
                            From!{downmsg,ResultMessage};
                        "closeroom"->
                            RoomInfo=util_RoomInfoParas:paraElements(Message),
                            ResultMessage=
                            if 
                                is_record(RoomInfo,roominfo)->
                                    #roominfo{id=Id}=RoomInfo,
                                    room_manager:removeRoom(Id),
                                    #message{type="result",subject="closeroom",content="succ"};
                                    %diliver result message to client
                                true->
                                    io:format("illegal RoomInfo subject:~p~n",[RoomInfo]),
                                    #message{type="result",subject="openroom",content="failed illegal roominfo"}
                                    %diliver result message to client
                            end,
                            From!{downmsg,ResultMessage};
                        _Els->
                            io:format("unkonw msssage subject:~p~n",[Sub])
                    end;
            "get"->
                    case Sub of
                        "clientinfo"->
                            ......
                        "roominfo"->
                            RoomList=room_manager:getAllRooms(),
                            ListJson=util_RoomInfoParas:deparaElement(RoomList),
                            ResultMessage=#message{type="result",subject="roominfo",content=ListJson},
                            %diliver result message to client
                            From!{downmsg,ResultMessage};
                        _Els->
                            io:format("unkonw msssage subject:~p~n",[Sub])
                    end;            
            _Els->
                {error,"wrong message type"}
            end
    .

          为了将操作的结果发送回给对应的客户端,以上代码对routeMessage 函数的参数进行了修改,添加了State参数。State 为一个#clientinfo 可以从里面取出客户端进行PID。

          相应的也要修改接口函数的参数:

    route(Message,State)when is_record(Message,message)->
        #message{type=Type}=Message,
        case validateType(Type) of
            {error,Reason}->
                io:format("validate message type error:~p~n",[Reason]);
            TheType->
                #message{subject=Sub}=Message,
                case validateSubject(Sub) of
                    {error,Reason}->
                        io:format("validate message subject error:~p~n",[Reason]);
                    TheSub->
                        routeMessage(TheType,TheSub,Message,State)
                end
        end
    ;
    route(Els,State)->
        io:format("message should be record:~p~n",[Els])
    .

          可以看到,具体的房间开启、删除都是调用的room_manager.erl中对应的方法。

          以下为room_manager.erl 中查询所有房间信息的代码:

    getAllRooms()->    
        getNextRoom([],[])
    .

    getNextRoom([],Infos)->
        case ets:first(roominfo) of
            Key->
                Record =ets:lookup(roominfo, Key),
                NewInfos=[Record|Infos],
                case ets:next(roominfo, Key) of
                    Next ->
                        getNextRoom(Next,NewInfos);
                    '$end_of_table'->
                        NewInfos
                end;            
            '$end_of_table'->
                Infos
        end
    ;
    getNextRoom(Id,Infos)->
        Record =ets:lookup(roominfo, Id),
        NewInfos=[Record|Infos],
        case ets:next(roominfo, Id) of
            Next ->
                getNextRoom(Next,NewInfos);
            '$end_of_table'->
                NewInfos
        end
    .

         接下来就是JSON消息的解包和打包,这里新建一个util_RoomInfoParas.erl模块:

    %% Author: Administrator
    %% Created: 2012-3-12
    %% Description: TODO: Add description to util_RoomInfoParas
    -module(util_RoomInfoParas).

    %%
    %% Include files
    %%
    -include("roominfo.hrl").
    %%
    %% Exported Functions
    %%
    -export([paraElements/1,deparaElement/1]).

    %%
    %% API Functions
    %%
    paraElements(Obj)->
        {obj,List}=Obj,
        Data =#roominfo{},
        %catch exception here
        io:format("data list is:~p~n",[List]),
        try paraEle(List,Data)        
        catch
            {error,Reason,NewData}->
                {error,Reason,NewData}
        end
    .

    paraEle([Ele|Els],Data)->
        io:format("ele is:~p~n",[Ele]),
        NewData=para(Ele,Data),
        paraEle(Els,NewData)
    ;
    paraEle([],Data)->
        Data
    .

    para({"type",Val},Data)->
        io:format("para type:~p~n",[Data]),    
        NewData=Data#roominfo{type=Val},
        io:format("paraed content:~p~n",[NewData]),
        NewData
    ;
    para({"name",Val},Data)->
        io:format("para name:~p~n",[Data]),    
        NewData=Data#roominfo{name=Val},
        io:format("paraed content:~p~n",[NewData]),
        NewData
    ;
    para({"type",Val},Data)->
        io:format("para type:~p~n",[Data]),    
        NewData=Data#roominfo{type=Val},
        io:format("paraed content:~p~n",[NewData]),
        NewData
    ;
    para({Key,Val},Data)->
        io:format("decode key is:~p~n",[Key]),
        io:format("decode Val is:~p~n",[Val]),
        %no mache
        %throw exception
        throw({error,"unkown element",Data})
    .

    %%
    %% Local Functions
    %%
    deparaElement(Record)->
        #roominfo{id=Id,
                  name=Name,
                  type=Type,
                  unum=Unum,
                  tablename=TableName,
                  status=Status,
                  creationDate=CreationDate}=Record,
        {obj,[
                 {"id",list_to_binary(setDef(id,"i"))},            
                 {"name",setDef(Name,"s")},
                 {"type",setDef(Type,"s")},
                 {"unum",setDef(Unum,"i")},
                 {"tablename",setDef(TableName,"s")},
                 {"status",setDef(Status,"s")}
                 ]}    
    .

    setDef(Val,Type)->
        Defv=case Type of
                  "s"->
                    "";
                   "i"->
                    0;
                  "l"->
                    []
            end,
                
        case Val of
            undefined->
                Defv;
            Els->
                Val
        end
    .

           里面提供了#roominfo 和 JSONString 之间的互转方法。

           OK,服务器端的代码就到这里,同样的先不做测试,后面一起做。

  • 相关阅读:
    Linux操作篇之配置Samba
    Chrome扩展实现网页图片右键上传(以E站图片搜索为例)
    Linux开机自动挂载NFS配置的一个误区
    ffmpeg指令解读海康威视摄像头
    linux服务器性能调优之tcp/ip性能调优
    多线程程序设计中的8条简单原则
    初识文件系统
    socket中的listen到底干了哪些事情?
    ip面向无连接?TCP面向连接?HTTP连接方式?
    网络层和数据链层的区别
  • 原文地址:https://www.cnblogs.com/yjl49/p/2392451.html
Copyright © 2011-2022 走看看