• IRC程序学习


    %%聊天的中转站,将{chan,MM,Msg}形式的信息转化为 {mm, MM, Msg}形式
    -module(mod_chat_controller).
    -export([start/3]).
    -import(lib_chan_mm, [send/2]).
    
    start(MM, _, _) ->
        process_flag(trap_exit, true),
        io:format("mod_chat_controller off we go ...~p~n",[MM]),
        loop(MM).
    
    loop(MM) ->
         receive
         {chan, MM, Msg} ->
             chat_server ! {mm, MM, Msg},
             loop(MM);
         {'EXIT', MM, _Why} ->
             chat_server ! {mm_closed, MM};
         Other ->
             io:format("mod_chat_controller unexpected message =~p (MM=~p)~n",
                   [Other, MM]),
             loop(MM)
        end.
    mod_chat_controller
    %%聊天服务器
    -module(chat_server).
    -import(lib_chan_mm, [send/2, controller/2]).
    -import(lists, [delete/2, foreach/2, map/2, member/2,reverse/2]).
    
    -compile(export_all).
    
    %%用chat.conf的配置启动服务器,每个连接到服务器的socket将调用mod_chat_controller模块的start函数
    %%{port, 2223}.
    %%{service, chat, password,"AsDT67aQ",mfa,mod_chat_controller,start,[]}.
    start() ->
        start_server(),
        lib_chan:start_server("D:\code\erlcode\socket_dist\chat.conf").
    
    start_server() ->
        register(chat_server, 
             spawn(fun() ->
                   process_flag(trap_exit, true),
                   Val= (catch server_loop([])),
                   io:format("Server terminated with:~p~n",[Val])
               end)).
    
    
    %%新启的进程,注册为chat_server,用来接收客户端用户的登录消息,当收到某一群组的登录信息时,如果该群组已经存在则传消息给该群组,如果不在则创建群组
    server_loop(L) ->
        receive
        {mm, Channel, {login, Group, Nick}} ->
            case lookup(Group, L) of
            {ok, Pid} ->
                Pid ! {login, Channel, Nick},
                server_loop(L);
            error ->
                Pid = spawn_link(fun() ->
                             chat_group:start(Channel, Nick) 
                         end),
                server_loop([{Group,Pid}|L])
            end;
        {mm_closed, _} ->
            server_loop(L); 
        {'EXIT', Pid, allGone} ->
            L1 = remove_group(Pid, L),
            server_loop(L1);
        Msg ->
            io:format("Server received Msg=~p~n",
                  [Msg]),
            server_loop(L)
        end.
    
    
    
    lookup(G, [{G,Pid}|_]) -> {ok, Pid};
    lookup(G, [_|T])       -> lookup(G, T);
    lookup(_,[])           -> error.
    
    remove_group(Pid, [{G,Pid}|T]) -> io:format("~p removed~n",[G]), T;
    remove_group(Pid, [H|T])       -> [H|remove_group(Pid, T)];
    remove_group(_, [])            -> [].
    chat_server
    %%聊天群组,包含各个连接进该群组的进程id
    -module(chat_group).
    -import(lib_chan_mm, [send/2, controller/2]).
    -import(lists, [foreach/2, reverse/2]).
    
    -export([start/2]).
    
    start(C, Nick) ->
        process_flag(trap_exit, true),
        controller(C, self()),
        send(C, ack),
        self() ! {chan, C, {relay, Nick, "I'm starting the group"}},
        group_controller([{C,Nick}]).
    
    
    
    delete(Pid, [{Pid,Nick}|T], L) -> {Nick, reverse(T, L)};
    delete(Pid, [H|T], L)          -> delete(Pid, T, [H|L]);
    delete(_, [], L)               -> {"????", L}.
    
    
    
    group_controller([]) ->
        exit(allGone);
    group_controller(L) ->
        receive
        {chan, C, {relay, Nick, Str}} ->
            foreach(fun({Pid,_}) -> send(Pid, {msg,Nick,C,Str}) end, L),
            group_controller(L);
        {login, C, Nick} ->
            controller(C, self()),
            send(C, ack),
            self() ! {chan, C, {relay, Nick, "I'm joining the group"}},
            group_controller([{C,Nick}|L]);
        {chan_closed, C} ->
            {Nick, L1} = delete(C, L, []),
            self() ! {chan, C, {relay, Nick, "I'm leaving the group"}},
            group_controller(L1);
        Any ->
            io:format("group controller received Msg=~p~n", [Any]),
            group_controller(L)
        end.
    chat_group
    -module(chat_client).
    
    -import(io_widget, 
        [get_state/1, insert_str/2, set_prompt/2, set_state/2, 
         set_title/2, set_handler/2, update_state/3]).
    
    -export([start/0, test/0, connect/5]).
    
    
    start() -> 
        connect("localhost", 2223, "AsDT67aQ", "general", "joe").
    
    
    test() ->
        connect("localhost", 2223, "AsDT67aQ", "general", "joe"),
        connect("localhost", 2223, "AsDT67aQ", "general", "jane"),
        connect("localhost", 2223, "AsDT67aQ", "general", "jim"),
        connect("localhost", 2223, "AsDT67aQ", "general", "sue").
           
    
    connect(Host, Port, HostPsw, Group, Nick) ->
        spawn(fun() -> handler(Host, Port, HostPsw, Group, Nick) end).
                     
    handler(Host, Port, HostPsw, Group, Nick) ->
        process_flag(trap_exit, true),
        Widget = io_widget:start(self()),
        set_title(Widget, Nick),
        set_state(Widget, Nick),
        set_prompt(Widget, [Nick, " > "]),
        set_handler(Widget, fun parse_command/1),
        start_connector(Host, Port, HostPsw),    
        disconnected(Widget, Group, Nick).
    
    
    %%接收服务器的连接反馈信息,连接上后进行登录
    disconnected(Widget, Group, Nick) ->
        receive
        {connected, MM} ->
            insert_str(Widget, "connected to server
    sending data
    "),
            lib_chan_mm:send(MM, {login, Group, Nick}),
            wait_login_response(Widget, MM);
        {Widget, destroyed} ->
            exit(died);
        {status, S} ->
            insert_str(Widget, to_str(S)),
            disconnected(Widget, Group, Nick);
        Other ->
            io:format("chat_client disconnected unexpected:~p~n",[Other]),
            disconnected(Widget, Group, Nick)
        end.
    
    
    %%接收服务器的登录反馈信息
    wait_login_response(Widget, MM) ->
        receive
        {chan, MM, ack} ->
            active(Widget, MM);
        Other ->
            io:format("chat_client login unexpected:~p~n",[Other]),
            wait_login_response(Widget, MM)
        end. 
    
    
    %%登录后获取客户端的反馈,并接受传到客户端的信息
    active(Widget, MM) ->
         receive
         {Widget, Nick, Str} ->
             lib_chan_mm:send(MM, {relay, Nick, Str}),
             active(Widget, MM);
         {chan, MM, {msg, From, Pid, Str}} ->
             insert_str(Widget, [From,"@",pid_to_list(Pid)," ", Str, "
    "]),
             active(Widget, MM);
         {'EXIT',Widget,windowDestroyed} ->
             lib_chan_mm:close(MM);
         {close, MM} ->
             exit(serverDied);
         Other ->
             io:format("chat_client active unexpected:~p~n",[Other]),
             active(Widget, MM)
         end. 
    
    
    %%链接chat服务器
    start_connector(Host, Port, Pwd) ->
        S = self(),
        spawn_link(fun() -> try_to_connect(S, Host, Port, Pwd) end).
        
    try_to_connect(Parent, Host, Port, Pwd) ->
        %% Parent is the Pid of the process that spawned this process
        case lib_chan:connect(Host, Port, chat, Pwd, []) of
        {error, _Why} ->
            Parent ! {status, {cannot, connect, Host, Port}},
            sleep(2000),
            try_to_connect(Parent, Host, Port, Pwd);
        {ok, MM} ->
            lib_chan_mm:controller(MM, Parent),
            Parent ! {connected, MM},
            exit(connectorFinished)
        end.
    
    
    sleep(T) ->
        receive
        after T -> true
        end.
            
    to_str(Term) ->
        io_lib:format("~p~n",[Term]).
    
    parse_command(Str) -> skip_to_gt(Str).
    
    skip_to_gt(">" ++ T) -> T;
    skip_to_gt([_|T])    -> skip_to_gt(T);
    skip_to_gt([])       -> exit("no >").
    chat_client
    -module(io_widget).
    
    -export([get_state/1,
         start/1, test/0, 
         set_handler/2, 
         set_prompt/2,
         set_state/2,
         set_title/2, insert_str/2, update_state/3]).
    
    start(Pid) ->
        gs:start(),
        spawn_link(fun() -> widget(Pid) end).
    
    get_state(Pid)          -> rpc(Pid, get_state).
    set_title(Pid, Str)     -> Pid ! {title, Str}.
    set_handler(Pid, Fun)   -> Pid ! {handler, Fun}.
    set_prompt(Pid, Str)    -> Pid ! {prompt, Str}.
    set_state(Pid, State)   -> Pid ! {state, State}.
    insert_str(Pid, Str)    -> Pid ! {insert, Str}.
    update_state(Pid, N, X) -> Pid ! {updateState, N, X}. 
    
    rpc(Pid, Q) ->    
        Pid ! {self(), Q},
        receive
        {Pid, R} ->
            R
        end.
    
    widget(Pid) ->
        Size = [{width,500},{height,200}],
        Win = gs:window(gs:start(),
                [{map,true},{configure,true},{title,"window"}|Size]),
        gs:frame(packer, Win,[{packer_x, [{stretch,1,500}]},
                  {packer_y, [{stretch,10,100,120},
                          {stretch,1,15,15}]}]),
        gs:create(editor,editor,packer, [{pack_x,1},{pack_y,1},{vscroll,right}]),
        gs:create(entry, entry, packer, [{pack_x,1},{pack_y,2},{keypress,true}]),
        gs:config(packer, Size),
        Prompt = " > ",
        State = nil,
        gs:config(entry, {insert,{0,Prompt}}),
        loop(Win, Pid, Prompt, State, fun parse/1). 
    
    loop(Win, Pid, Prompt, State, Parse) ->   
        receive
        {From, get_state} ->
            From ! {self(), State},
            loop(Win, Pid, Prompt, State, Parse);
        {handler, Fun} ->
            loop(Win, Pid, Prompt, State, Fun);
        {prompt, Str} ->
            %% this clobbers the line being input ...
            %% this could be fixed - hint
            gs:config(entry, {delete,{0,last}}),
            gs:config(entry, {insert,{0,Str}}),
            loop(Win, Pid, Str, State, Parse);
        {state, S} ->
            loop(Win, Pid, Prompt, S, Parse);
        {title, Str} ->
            gs:config(Win, [{title, Str}]),
            loop(Win, Pid, Prompt, State, Parse);
        {insert, Str} ->
            gs:config(editor, {insert,{'end',Str}}),
            scroll_to_show_last_line(),
            loop(Win, Pid, Prompt, State, Parse);
        {updateState, N, X} ->
            io:format("setelemtn N=~p X=~p State=~p~n",[N,X,State]),
            State1 = setelement(N, State, X),
            loop(Win, Pid, Prompt, State1, Parse);
        {gs,_,destroy,_,_} ->
            io:format("Destroyed~n",[]),
            exit(windowDestroyed);
        {gs, entry,keypress,_,['Return'|_]} ->
            Text = gs:read(entry, text),
            io:format("io_widget:input text:~p~n",[Text]),
              io:format("io_widget:send text to pid:~p~n",[Pid]),
            gs:config(entry, {delete,{0,last}}),
            gs:config(entry, {insert,{0,Prompt}}),
            try Parse(Text) of
            Term ->
                Pid ! {self(), State, Term}
            catch
            _:_ ->
                self() ! {insert, "** bad input**
    ** /h for help
    "}
            end,
            loop(Win, Pid, Prompt, State, Parse);
        {gs,_,configure,[],[W,H,_,_]} ->
            gs:config(packer, [{width,W},{height,H}]),
            loop(Win, Pid, Prompt, State, Parse);
        {gs, entry,keypress,_,_} ->
            loop(Win, Pid, Prompt, State, Parse);
        Any ->
            io:format("Discarded:~p~n",[Any]),
            loop(Win, Pid, Prompt, State, Parse)
        end.
    
    scroll_to_show_last_line() ->
        Size       = gs:read(editor, size),
        Height     = gs:read(editor, height),
        CharHeight = gs:read(editor, char_height),
        TopRow     = Size - Height/CharHeight,
        if  TopRow > 0 -> gs:config(editor, {vscrollpos, TopRow});
        true       -> gs:config(editor, {vscrollpos, 0})
        end.
    
    test() ->
        spawn(fun() -> test1() end).
    
    test1() ->
        W = io_widget:start(self()),
        io_widget:set_title(W, "Test window"),
        loop(W).
    
    loop(W) ->
        receive
        {W, {str, Str}} ->
            Str1 = Str ++ "
    ",
            io_widget:insert_str(W, Str1),
            loop(W)
        end.
    
    parse(Str) ->
        {str, Str}.
    io_widget
  • 相关阅读:
    你会做夹具吗?(一)
    DDR3布线设计要点总结
    PCB设计要点-DDR3布局布线技巧及注意事项
    走进JEDEC,解读DDR(下)
    [转]关于STM32 PB3 PB4 如何设置成普通GPIO的配置
    [转]Verilog有符号数与无符号数作运算
    [转]实用光电二极管pd的采样电路
    STM32外部8M晶振不启动
    ALTCLKCTRL核的作用
    [转]如何在Altium Designer中将PCB生成PDF?
  • 原文地址:https://www.cnblogs.com/studynote/p/3348437.html
Copyright © 2020-2023  润新知