Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5120221
  • 博文数量: 921
  • 博客积分: 16037
  • 博客等级: 上将
  • 技术积分: 8469
  • 用 户 组: 普通用户
  • 注册时间: 2006-04-05 02:08
文章分类

全部博文(921)

文章存档

2020年(1)

2019年(3)

2018年(3)

2017年(6)

2016年(47)

2015年(72)

2014年(25)

2013年(72)

2012年(125)

2011年(182)

2010年(42)

2009年(14)

2008年(85)

2007年(89)

2006年(155)

分类:

2013-01-01 15:17:44

erlang服务端,主要实现与flash客户端的连接、消息传递服务
自带843端口服务解决flash9以上暴汗的安全沙箱问题

chat.erl


 

  1. -module(chat).
  2. -behaviour(gen_server).
  3. -export([start/0,find/1]).

  4. %% gen_server回调
  5. -export([init/1,handle_call/3,handle_cast/2,handle_info/2,
  6.         terminate/2,code_change/3]).
  7. -compile(export_all).

  8. -define(TCP_OPTIONS, [list, {packet, 0}, {active, false}, {reuseaddr, true},{nodelay, false},{delay_send, true}]).
  9. %%用户列表
  10. -record(player, {id,socket,time=none}).


  11. %%回调gen_server创建服务
  12. start() ->
  13.         gen_server:start_link({local,?MODULE},?MODULE,[8080],[]).%%定为8080端口


  14. %%停止服务
  15. stop() ->
  16.         gen_server:call(?MODULE,stop).

  17. %%查找玩家
  18. find(Uname)->
  19.         client_manager ! {list,Uname}.


  20. %%初始化,Port被持久化
  21. init([Port]) ->
  22.         %%维护队列
  23.         register(client_manager, spawn(fun() -> manage_clients([]) end)),
  24.         {Tag, LSocket}=gen_tcp:listen(Port, ?TCP_OPTIONS),
  25.         case Tag of %%创建监听
  26.                 ok -> spawn(fun() -> do_accept(LSocket) end); %%统一接收
  27.                 error -> exit({accept,LSocket}) %%出错,退出连接
  28.         end,

  29.         %%与flash通信的安全策略文件传送监听接口
  30.         {Req, AsSocket}=gen_tcp:listen(843, ?TCP_OPTIONS),
  31.         case Req of
  32.                 ok -> spawn(fun() -> do_accept2(AsSocket) end);
  33.                 error -> exit({accept,AsSocket})
  34.         end,
  35.         {ok,LSocket}.


  36. handle_call(stop,_From,Tab) ->
  37.         client_manager!{exit},
  38.         {stop,normal,stopped,Tab}.

  39. handle_cast(_Msg,State) ->
  40.         {noreply,State}.


  41. handle_info(_Info,State) ->
  42.         {noreply,State}.


  43. terminate(_Reason,_State) ->
  44.         ok.

  45. %%热交换
  46. code_change(_OldVsn,State,_) ->
  47.         {ok,State}.








  48. %% -----------------------------------
  49. %% -------------私有函数--------------
  50. %% -----------------------------------



  51. %%新建连接,只有新连接时才调用
  52. do_accept(LSocket) ->
  53.         case gen_tcp:accept(LSocket) of
  54.                 {ok, Socket}->
  55.                         %%创建进程处理响应
  56.                         spawn(fun() -> handle_client(Socket) end),
  57.                         %%创建新连接,持久化
  58.                         client_manager ! {connect, Socket},
  59.                         do_accept(LSocket);
  60.                 _->ok
  61.         end.



  62. %%处理flash安全策略文件的发送服务
  63. do_accept2(LSocket) ->
  64.         case gen_tcp:accept(LSocket) of
  65.                 {ok, Socket}->
  66.                         spawn(fun() -> put_file(Socket) end),
  67.                         do_accept2(LSocket);
  68.                 _->error
  69.         end.

  70. %%短连接策略,连接完关闭
  71. %%flash安全沙箱处理守候服务
  72. put_file(Socket)->
  73.           case gen_tcp:recv(Socket, 0) of
  74.                 {ok, _} ->
  75.                         %%判断数据返回策略文件
  76.                         gen_tcp:send(Socket, "
  77.                 
  78.                   
  79.                 ");
  80.                 {error, closed} ->ok
  81.           end,
  82.           gen_tcp:close(Socket). %%关闭连接





  83. %%持续、长连接的响应
  84. handle_client(Socket) ->
  85.           case gen_tcp:recv(Socket, 0) of
  86.                 {ok, Data} ->
  87.                         client_manager ! {chat, Data},
  88.                         handle_client(Socket);
  89.                 {error, closed} ->
  90.                         client_manager ! {disconnect, Socket} %%这里退出时会出错
  91.           end.





  92. %%对内响应,管理连接,事件列表,记录玩家数据
  93. manage_clients(Players) ->
  94.         receive
  95.             {connect, Socket} ->
  96.                 Player = #player{
  97.                         id="guest_"++integer_to_list(random:uniform(100000)), %%随机命名用户名
  98.                         socket=Socket,
  99.                         time=time()
  100.                         }, %%新增记录
  101.                 io:fwrite("Connected: ~w~n", [Socket]),
  102.                 NewPlayers = [Player|Players]; %%累加到列表

  103.             {disconnect, Socket} ->
  104.                 io:fwrite("Disconnected: ~w~n", [Socket]),
  105.                 Player = find_Socket(Socket, Players), %%查找socket对应的记录
  106.                 NewPlayers = lists:delete(Player, Players); %%删除记录

  107.             {chat,Data} ->
  108.                 send_data(Players, Data),
  109.                 NewPlayers=Players;

  110.             {list,Uname}->
  111.                 find_player(Uname,Players),
  112.                 NewPlayers = Players;

  113.             {exit}->
  114.                 NewPlayers="",
  115.                 exit({exit}) %%退出系统应用
  116.         end,
  117.         manage_clients(NewPlayers).



  118. %%对客户端进行广播
  119. send_data(Players, Data) ->
  120.   SendData = fun(Player) ->
  121.     gen_tcp:send(Player#player.socket, Data) %%可设置为非阻断模式,或使用多进程发送
  122.   end,
  123.   lists:foreach(SendData, Players).

  124.   %%查找指定记录
  125. find_Socket(Socket, Players) ->
  126.     {value, Player} = lists:keysearch(Socket, #player.socket, Players),
  127.     Player.

  128. find_player(Uname, Players) ->
  129.     case lists:keysearch(Uname, #player.id, Players) of
  130.     {value, Player}->
  131.         io:fwrite("User information: ~w~n", [Player]);
  132.     _->io:fwrite("No found.~n")
  133.     end.

简单的flash客户端,为as3代码:

  1. package
  2. {
  3.         import flash.net.Socket;
  4.         import flash.display.Sprite;
  5.         import flash.events.*;
  6.         import flash.text.TextField;

  7.         [SWF(width=600, height=300)]
  8.         public class chat extends Sprite
  9.         {
  10.                 private var textArea:TextField;
  11.                 private var input:TextField;
  12.                 private var label:TextField;
  13.                 private var socket:Socket=new Socket();

  14.                 public function chat()
  15.                 {
  16.                         socket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
  17.                         socket.connect("192.168.10.112", 8080); //连接到服务端,这里改成服务端的IP和端口

  18.                         socket.flush();

  19.                         initUI();
  20.                         input.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler); //按回车响应

  21.                         textArea.addEventListener(Event.RENDER, renderHandler);
  22.                 }
  23.                 
  24.                 private function sendMsg(Msg:String):void
  25.                 {
  26.                         socket.writeUTFBytes(Msg);
  27.                         socket.flush();
  28.                 }
  29.                 
  30.                 private function keyDownHandler(e:KeyboardEvent):void
  31.                 {
  32.                         if (13 == e.charCode)
  33.                         {
  34.                                 var s:String = input.text ? input.text : "null";
  35.                                 input.text = "";
  36.                                 sendMsg(s);
  37.                         }
  38.                 }
  39.                 
  40.                 private function renderHandler(e:Event):void
  41.                 {
  42.                         textArea.scrollV = textArea.maxScrollV;
  43.                 }
  44.                 
  45.                 
  46.                 //初始化

  47.                 private function initUI():void
  48.                 {
  49.                         textArea = new TextField();
  50.                         textArea.width = 400;
  51.                         textArea.height = 150;
  52.                         textArea.border = true;
  53.                         textArea.x = 100;
  54.                         textArea.y = 30;
  55.                         addChild(textArea);
  56.                         
  57.                         input = new TextField();
  58.                         input.height = 20;
  59.                         input.width = 350;
  60.                         input.type = "input";
  61.                         input.border = true;
  62.                         input.multiline = false;
  63.                         input.x = 100;
  64.                         input.y = 200;
  65.                         addChild(input);
  66.                         
  67.                         label = new TextField();
  68.                         label.text = "回车发送";
  69.                         label.height = label.textHeight + 4;
  70.                         label.width = label.textWidth + 4;
  71.                         label.mouseEnabled = false;
  72.                         label.x = 460;
  73.                         label.y = 200;
  74.                         addChild(label);
  75.                 }

  76.                 
  77.                 // 事件处理回调函数,显示到屏幕上

  78.                 private function onSocketData(event:ProgressEvent):void
  79.                 {
  80.                         while (socket.bytesAvailable)
  81.                         {
  82.                                 var s:String = socket.readUTFBytes(socket.bytesAvailable);
  83.                                 if (textArea.text) s = "\n" + s;
  84.                                 textArea.appendText(s);
  85.                                 stage.invalidate();
  86.                         }
  87.                 }
  88.         }
  89. }



文章来自:

阅读(1197) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~