1. %%聊天的中转站,将{chan,MM,Msg}形式的信息转化为 {mm, MM, Msg}形式
  2. -module(mod_chat_controller).
  3. -export([start/3]).
  4. -import(lib_chan_mm, [send/2]).
  5.  
  6. start(MM, _, _) ->
  7. process_flag(trap_exit, true),
  8. io:format("mod_chat_controller off we go ...~p~n",[MM]),
  9. loop(MM).
  10.  
  11. loop(MM) ->
  12. receive
  13. {chan, MM, Msg} ->
  14. chat_server ! {mm, MM, Msg},
  15. loop(MM);
  16. {'EXIT', MM, _Why} ->
  17. chat_server ! {mm_closed, MM};
  18. Other ->
  19. io:format("mod_chat_controller unexpected message =~p (MM=~p)~n",
  20. [Other, MM]),
  21. loop(MM)
  22. end.

mod_chat_controller

  1. %%聊天服务器
  2. -module(chat_server).
  3. -import(lib_chan_mm, [send/2, controller/2]).
  4. -import(lists, [delete/2, foreach/2, map/2, member/2,reverse/2]).
  5.  
  6. -compile(export_all).
  7.  
  8. %%用chat.conf的配置启动服务器,每个连接到服务器的socket将调用mod_chat_controller模块的start函数
  9. %%{port, 2223}.
  10. %%{service, chat, password,"AsDT67aQ",mfa,mod_chat_controller,start,[]}.
  11. start() ->
  12. start_server(),
  13. lib_chan:start_server("D:\\code\\erlcode\\socket_dist\\chat.conf").
  14.  
  15. start_server() ->
  16. register(chat_server,
  17. spawn(fun() ->
  18. process_flag(trap_exit, true),
  19. Val= (catch server_loop([])),
  20. io:format("Server terminated with:~p~n",[Val])
  21. end)).
  22.  
  23. %%新启的进程,注册为chat_server,用来接收客户端用户的登录消息,当收到某一群组的登录信息时,如果该群组已经存在则传消息给该群组,如果不在则创建群组
  24. server_loop(L) ->
  25. receive
  26. {mm, Channel, {login, Group, Nick}} ->
  27. case lookup(Group, L) of
  28. {ok, Pid} ->
  29. Pid ! {login, Channel, Nick},
  30. server_loop(L);
  31. error ->
  32. Pid = spawn_link(fun() ->
  33. chat_group:start(Channel, Nick)
  34. end),
  35. server_loop([{Group,Pid}|L])
  36. end;
  37. {mm_closed, _} ->
  38. server_loop(L);
  39. {'EXIT', Pid, allGone} ->
  40. L1 = remove_group(Pid, L),
  41. server_loop(L1);
  42. Msg ->
  43. io:format("Server received Msg=~p~n",
  44. [Msg]),
  45. server_loop(L)
  46. end.
  47.  
  48. lookup(G, [{G,Pid}|_]) -> {ok, Pid};
  49. lookup(G, [_|T]) -> lookup(G, T);
  50. lookup(_,[]) -> error.
  51.  
  52. remove_group(Pid, [{G,Pid}|T]) -> io:format("~p removed~n",[G]), T;
  53. remove_group(Pid, [H|T]) -> [H|remove_group(Pid, T)];
  54. remove_group(_, []) -> [].

chat_server

  1. %%聊天群组,包含各个连接进该群组的进程id
  2. -module(chat_group).
  3. -import(lib_chan_mm, [send/2, controller/2]).
  4. -import(lists, [foreach/2, reverse/2]).
  5.  
  6. -export([start/2]).
  7.  
  8. start(C, Nick) ->
  9. process_flag(trap_exit, true),
  10. controller(C, self()),
  11. send(C, ack),
  12. self() ! {chan, C, {relay, Nick, "I'm starting the group"}},
  13. group_controller([{C,Nick}]).
  14.  
  15. delete(Pid, [{Pid,Nick}|T], L) -> {Nick, reverse(T, L)};
  16. delete(Pid, [H|T], L) -> delete(Pid, T, [H|L]);
  17. delete(_, [], L) -> {"????", L}.
  18.  
  19. group_controller([]) ->
  20. exit(allGone);
  21. group_controller(L) ->
  22. receive
  23. {chan, C, {relay, Nick, Str}} ->
  24. foreach(fun({Pid,_}) -> send(Pid, {msg,Nick,C,Str}) end, L),
  25. group_controller(L);
  26. {login, C, Nick} ->
  27. controller(C, self()),
  28. send(C, ack),
  29. self() ! {chan, C, {relay, Nick, "I'm joining the group"}},
  30. group_controller([{C,Nick}|L]);
  31. {chan_closed, C} ->
  32. {Nick, L1} = delete(C, L, []),
  33. self() ! {chan, C, {relay, Nick, "I'm leaving the group"}},
  34. group_controller(L1);
  35. Any ->
  36. io:format("group controller received Msg=~p~n", [Any]),
  37. group_controller(L)
  38. end.

chat_group

  1. -module(chat_client).
  2.  
  3. -import(io_widget,
  4. [get_state/1, insert_str/2, set_prompt/2, set_state/2,
  5. set_title/2, set_handler/2, update_state/3]).
  6.  
  7. -export([start/0, test/0, connect/5]).
  8.  
  9. start() ->
  10. connect("localhost", 2223, "AsDT67aQ", "general", "joe").
  11.  
  12. test() ->
  13. connect("localhost", 2223, "AsDT67aQ", "general", "joe"),
  14. connect("localhost", 2223, "AsDT67aQ", "general", "jane"),
  15. connect("localhost", 2223, "AsDT67aQ", "general", "jim"),
  16. connect("localhost", 2223, "AsDT67aQ", "general", "sue").
  17.  
  18. connect(Host, Port, HostPsw, Group, Nick) ->
  19. spawn(fun() -> handler(Host, Port, HostPsw, Group, Nick) end).
  20.  
  21. handler(Host, Port, HostPsw, Group, Nick) ->
  22. process_flag(trap_exit, true),
  23. Widget = io_widget:start(self()),
  24. set_title(Widget, Nick),
  25. set_state(Widget, Nick),
  26. set_prompt(Widget, [Nick, " > "]),
  27. set_handler(Widget, fun parse_command/1),
  28. start_connector(Host, Port, HostPsw),
  29. disconnected(Widget, Group, Nick).
  30.  
  31. %%接收服务器的连接反馈信息,连接上后进行登录
  32. disconnected(Widget, Group, Nick) ->
  33. receive
  34. {connected, MM} ->
  35. insert_str(Widget, "connected to server\nsending data\n"),
  36. lib_chan_mm:send(MM, {login, Group, Nick}),
  37. wait_login_response(Widget, MM);
  38. {Widget, destroyed} ->
  39. exit(died);
  40. {status, S} ->
  41. insert_str(Widget, to_str(S)),
  42. disconnected(Widget, Group, Nick);
  43. Other ->
  44. io:format("chat_client disconnected unexpected:~p~n",[Other]),
  45. disconnected(Widget, Group, Nick)
  46. end.
  47.  
  48. %%接收服务器的登录反馈信息
  49. wait_login_response(Widget, MM) ->
  50. receive
  51. {chan, MM, ack} ->
  52. active(Widget, MM);
  53. Other ->
  54. io:format("chat_client login unexpected:~p~n",[Other]),
  55. wait_login_response(Widget, MM)
  56. end.
  57.  
  58. %%登录后获取客户端的反馈,并接受传到客户端的信息
  59. active(Widget, MM) ->
  60. receive
  61. {Widget, Nick, Str} ->
  62. lib_chan_mm:send(MM, {relay, Nick, Str}),
  63. active(Widget, MM);
  64. {chan, MM, {msg, From, Pid, Str}} ->
  65. insert_str(Widget, [From,"@",pid_to_list(Pid)," ", Str, "\n"]),
  66. active(Widget, MM);
  67. {'EXIT',Widget,windowDestroyed} ->
  68. lib_chan_mm:close(MM);
  69. {close, MM} ->
  70. exit(serverDied);
  71. Other ->
  72. io:format("chat_client active unexpected:~p~n",[Other]),
  73. active(Widget, MM)
  74. end.
  75.  
  76. %%链接chat服务器
  77. start_connector(Host, Port, Pwd) ->
  78. S = self(),
  79. spawn_link(fun() -> try_to_connect(S, Host, Port, Pwd) end).
  80.  
  81. try_to_connect(Parent, Host, Port, Pwd) ->
  82. %% Parent is the Pid of the process that spawned this process
  83. case lib_chan:connect(Host, Port, chat, Pwd, []) of
  84. {error, _Why} ->
  85. Parent ! {status, {cannot, connect, Host, Port}},
  86. sleep(2000),
  87. try_to_connect(Parent, Host, Port, Pwd);
  88. {ok, MM} ->
  89. lib_chan_mm:controller(MM, Parent),
  90. Parent ! {connected, MM},
  91. exit(connectorFinished)
  92. end.
  93.  
  94. sleep(T) ->
  95. receive
  96. after T -> true
  97. end.
  98.  
  99. to_str(Term) ->
  100. io_lib:format("~p~n",[Term]).
  101.  
  102. parse_command(Str) -> skip_to_gt(Str).
  103.  
  104. skip_to_gt(">" ++ T) -> T;
  105. skip_to_gt([_|T]) -> skip_to_gt(T);
  106. skip_to_gt([]) -> exit("no >").

chat_client

  1. -module(io_widget).
  2.  
  3. -export([get_state/1,
  4. start/1, test/0,
  5. set_handler/2,
  6. set_prompt/2,
  7. set_state/2,
  8. set_title/2, insert_str/2, update_state/3]).
  9.  
  10. start(Pid) ->
  11. gs:start(),
  12. spawn_link(fun() -> widget(Pid) end).
  13.  
  14. get_state(Pid) -> rpc(Pid, get_state).
  15. set_title(Pid, Str) -> Pid ! {title, Str}.
  16. set_handler(Pid, Fun) -> Pid ! {handler, Fun}.
  17. set_prompt(Pid, Str) -> Pid ! {prompt, Str}.
  18. set_state(Pid, State) -> Pid ! {state, State}.
  19. insert_str(Pid, Str) -> Pid ! {insert, Str}.
  20. update_state(Pid, N, X) -> Pid ! {updateState, N, X}.
  21.  
  22. rpc(Pid, Q) ->
  23. Pid ! {self(), Q},
  24. receive
  25. {Pid, R} ->
  26. R
  27. end.
  28.  
  29. widget(Pid) ->
  30. Size = [{width,500},{height,200}],
  31. Win = gs:window(gs:start(),
  32. [{map,true},{configure,true},{title,"window"}|Size]),
  33. gs:frame(packer, Win,[{packer_x, [{stretch,1,500}]},
  34. {packer_y, [{stretch,10,100,120},
  35. {stretch,1,15,15}]}]),
  36. gs:create(editor,editor,packer, [{pack_x,1},{pack_y,1},{vscroll,right}]),
  37. gs:create(entry, entry, packer, [{pack_x,1},{pack_y,2},{keypress,true}]),
  38. gs:config(packer, Size),
  39. Prompt = " > ",
  40. State = nil,
  41. gs:config(entry, {insert,{0,Prompt}}),
  42. loop(Win, Pid, Prompt, State, fun parse/1).
  43.  
  44. loop(Win, Pid, Prompt, State, Parse) ->
  45. receive
  46. {From, get_state} ->
  47. From ! {self(), State},
  48. loop(Win, Pid, Prompt, State, Parse);
  49. {handler, Fun} ->
  50. loop(Win, Pid, Prompt, State, Fun);
  51. {prompt, Str} ->
  52. %% this clobbers the line being input ...
  53. %% this could be fixed - hint
  54. gs:config(entry, {delete,{0,last}}),
  55. gs:config(entry, {insert,{0,Str}}),
  56. loop(Win, Pid, Str, State, Parse);
  57. {state, S} ->
  58. loop(Win, Pid, Prompt, S, Parse);
  59. {title, Str} ->
  60. gs:config(Win, [{title, Str}]),
  61. loop(Win, Pid, Prompt, State, Parse);
  62. {insert, Str} ->
  63. gs:config(editor, {insert,{'end',Str}}),
  64. scroll_to_show_last_line(),
  65. loop(Win, Pid, Prompt, State, Parse);
  66. {updateState, N, X} ->
  67. io:format("setelemtn N=~p X=~p State=~p~n",[N,X,State]),
  68. State1 = setelement(N, State, X),
  69. loop(Win, Pid, Prompt, State1, Parse);
  70. {gs,_,destroy,_,_} ->
  71. io:format("Destroyed~n",[]),
  72. exit(windowDestroyed);
  73. {gs, entry,keypress,_,['Return'|_]} ->
  74. Text = gs:read(entry, text),
  75. io:format("io_widget:input text:~p~n",[Text]),
  76. io:format("io_widget:send text to pid:~p~n",[Pid]),
  77. gs:config(entry, {delete,{0,last}}),
  78. gs:config(entry, {insert,{0,Prompt}}),
  79. try Parse(Text) of
  80. Term ->
  81. Pid ! {self(), State, Term}
  82. catch
  83. _:_ ->
  84. self() ! {insert, "** bad input**\n** /h for help\n"}
  85. end,
  86. loop(Win, Pid, Prompt, State, Parse);
  87. {gs,_,configure,[],[W,H,_,_]} ->
  88. gs:config(packer, [{width,W},{height,H}]),
  89. loop(Win, Pid, Prompt, State, Parse);
  90. {gs, entry,keypress,_,_} ->
  91. loop(Win, Pid, Prompt, State, Parse);
  92. Any ->
  93. io:format("Discarded:~p~n",[Any]),
  94. loop(Win, Pid, Prompt, State, Parse)
  95. end.
  96.  
  97. scroll_to_show_last_line() ->
  98. Size = gs:read(editor, size),
  99. Height = gs:read(editor, height),
  100. CharHeight = gs:read(editor, char_height),
  101. TopRow = Size - Height/CharHeight,
  102. if TopRow > 0 -> gs:config(editor, {vscrollpos, TopRow});
  103. true -> gs:config(editor, {vscrollpos, 0})
  104. end.
  105.  
  106. test() ->
  107. spawn(fun() -> test1() end).
  108.  
  109. test1() ->
  110. W = io_widget:start(self()),
  111. io_widget:set_title(W, "Test window"),
  112. loop(W).
  113.  
  114. loop(W) ->
  115. receive
  116. {W, {str, Str}} ->
  117. Str1 = Str ++ "\n",
  118. io_widget:insert_str(W, Str1),
  119. loop(W)
  120. end.
  121.  
  122. parse(Str) ->
  123. {str, Str}.

io_widget

IRC程序学习的更多相关文章

  1. 通过反汇编C语言小程序学习Liunx汇编语言

    大家好!    我是来自山东师范大学的吴乐.    今天在<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ...

  2. 微信小程序 学习资料

    微信小程序 学习资料 资料名称 网址 官方教程 https://developers.weixin.qq.com/miniprogram/dev/index.html?t=18110517

  3. Tuxedo安装、配置、以及演示样例程序 (学习网址)

    Tuxedo安装.配置.以及演示样例程序 (学习网址): 1.http://liu9403.iteye.com/blog/1415684 2.http://www.cnblogs.com/fnng/a ...

  4. Java开发桌面程序学习(一)——JavaFx+Jfoenix初始以及搭建

    Java开发桌面程序学习(一)--JavaFx+Jfoenix初始以及搭建 前言 想做一个Java的桌面程序,但是,使用原生的Swing感觉又十分麻烦,那个布局都是拿代码设置,看着十分的乱,偶然的情况 ...

  5. 【微信小程序学习笔记】入门与了解

    [微信小程序学习笔记(一)] IDE 下载安装 下载地址 官方工具:https://mp.weixin.qq.com/debug/w … tml?t=1476434678461 下载可执行文件后,可按 ...

  6. 微信小程序学习笔记二 数据绑定 + 事件绑定

    微信小程序学习笔记二 1. 小程序特点概述 没有DOM 组件化开发: 具备特定功能效果的代码集合 体积小, 单个压缩包体积不能大于2M, 否则无法上线 小程序的四个重要的文件 *js *.wxml - ...

  7. 微信小程序学习笔记一 小程序介绍 & 前置知识

    微信小程序学习笔记一 1. 什么是小程序? 2017年度百度百科十大热词之一 微信小程序, 简称小程序, 英文名 Mini Program, 是一种不需要下载安装即可使用的应用 ( 张小龙对其的定义是 ...

  8. 【C#】1.3 WPF应用程序学习要点

    分类:C#.VS2015 创建日期:2016-06-14 使用教材:十二五国家级规划教材<C#程序设计及应用教程>(第3版) 一.要点概述 <C#程序设计及应用教程>(第3版) ...

  9. 微信小程序学习

    官方网站 https://mp.weixin.qq.com/debug/wxadoc/dev/index.html 项目结构介绍 -- MINA框架 https://mp.weixin.qq.com/ ...

随机推荐

  1. printk一些技巧【转】

    转自:http://haohetao.iteye.com/blog/1147791 转自:http://blog.csdn.net/wbd880419/article/details/73530550 ...

  2. OWASP SSL 高级审查工具

    http://www.linuxidc.com/Linux/2016-03/129164.htm InfoWorld 在部署.运营和保障网络安全领域精选出了年度开源工具获奖者. 最佳开源网络和安全软件 ...

  3. twemproxy 简介、安装配置

    twemproxy 简介.安装配置 http://www.xuchanggang.cn/archives/993.html

  4. sicily 1012. Stacking Cylinders & 1206. Stacking Cylinders

    Time Limit: 1sec    Memory Limit:32MB  Description Cylinders (e.g. oil drums) (of radius 1 foot) are ...

  5. win10安装提示“我们无法创建新的分区”

    今日于笔记本安装win10时突然出现提示:我们无法创建新的分区.网上搜了不少建议,尝试了都无果. 由于我的笔记本是固态硬盘与机械硬盘混合,所以情况可能更加特殊. 最后成功的方法是: 1. 先将Win1 ...

  6. VS2017MVC+EF+MySQL环境搭建

    记录一次环境搭建的过程以及出现的问题和解决方法. 编译器Visual Studio 2017Enterprise Edition 1.新建一个MVC应用程序2.在新建的MVC程序中选择Models - ...

  7. [New learn]SDWebImage框架的基本使用

    代码:https://github.com/xufeng79x/SDWebImage 1.简介 SDWebImage是一个第三方框架,它能够帮助我们有效管理应用图片下载,沙盒保存和内存保存的任务.通过 ...

  8. hdu 1087(LIS变形)

    Super Jumping! Jumping! Jumping! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 ...

  9. Go语言基础单元测试示例

    这个要熟悉原理,要能写.. 但现在..... 注意,没有main函数,以_test.go结尾,命令go test -v package main import ( "testing" ...

  10. javascript实现与后端相同的枚举Enum对象

    ; (function (global, undefined) { global.Enum = function (namesToValues) { var enumeration = functio ...