erlang服务端,主要实现与flash客户端的连接、消息传递服务
自带843端口服务解决flash9以上暴汗的安全沙箱问题
chat.erl
- -module(chat).
- -export([start/0,manage_clients/1,stop/0,find/1]).
- -record(player, {id,socket,time=none}).
- start() ->
- chat_server:start(?MODULE,manage_clients).
- stop()->
- chat_server:stop(?MODULE),
- timer:sleep(2000), %%等待所有连接断开
- manage_clients!{exit}.
- manage_clients(Players) ->
- receive
- {connect, Socket} ->
- Player = #player{
- id="guest_"++integer_to_list(random:uniform(100000)),
- socket=Socket,
- time=time()
- }, %%新增记录
- io:fwrite("Socket connected: ~w~n", [Socket]),
- NewPlayers = [Player|Players]; %%累加到列表
- {disconnect, Socket} ->
- io:fwrite("Socket disconnected: ~w~n", [Socket]),
- Player = find_Socket(Socket, Players), %%查找socket对应的记录
- NewPlayers = lists:delete(Player, Players); %%删除记录
- {chat,Data} ->
- send_data(Players, Data),
- NewPlayers=Players;
- {list,Uname}->
- find_player(Uname,Players),
- NewPlayers = Players;
- {exit}->
- NewPlayers="",
- exit({stop, exit})
- end,
- manage_clients(NewPlayers).
- %%对客户端进行广播
- send_data(Players, Data) ->
- SendData = fun(Player) ->
- gen_tcp:send(Player#player.socket, Data)
- end,
- lists:foreach(SendData, Players).
- %%查找指定记录
- find_Socket(Socket, Players) ->
- {value, Player} = lists:keysearch(Socket, #player.socket, Players),
- Player.
- find_player(Uname, Players) ->
- case lists:keysearch(Uname, #player.id, Players) of
- {value, Player}->
- io:fwrite("Find a player: ~w~n", [Player]);
- _->io:fwrite("No found.~n")
- end.
- %%查找用户
- find(Uname)->
- client_manager ! {list,Uname}.
chat_server.erl
- -module(chat_server).
- -behaviour(gen_server).
- -export([start/2,stop/1]).
- %% gen_server回调
- -export([init/1,handle_call/3,handle_cast/2,handle_info/2,
- terminate/2,code_change/3]).
- -compile(export_all).
- -define(TCP_OPTIONS, [list, {packet, 0}, {active, false}, {reuseaddr, true},{nodelay, false},{delay_send, true}]).
- %%状态表
- -record(state, {name,loop,socket}).
- %%回调gen_server创建服务
- start(Name,Loop) ->
- State=#state{name=Name,loop=Loop}, %%定为记录
- gen_server:start_link({local,Name},?MODULE,State,[]).
- %%start() ->
- %% gen_server:start_link({local,?MODULE},?MODULE,[],[]).
- %%停止服务
- stop(Name) ->
- gen_server:call(Name,stop).
- init(State) ->
- %%维护队列 chat.rar (17.12 KB, 下载次数: 379) 2009-12-15 20:04 上传下载次数: 379
- register(State#state.loop, spawn(fun() -> (State#state.name):(State#state.loop)([]) end)),
- {Tag, LSocket}=gen_tcp:listen(8080, ?TCP_OPTIONS), %%默认8080
- case Tag of %%创建监听
- ok -> spawn(fun() -> do_accept(State#state{socket=LSocket}) end); %%统一接收
- error -> exit({stop, exit}) %%出错,退出连接
- end,
-
- %%与flash通信的安全策略文件传送监听接口
- {Req, AsSocket}=gen_tcp:listen(843, ?TCP_OPTIONS),
- case Req of
- ok -> spawn(fun() -> do_accept2(AsSocket) end);
- error -> exit({stop, exit})
- end,
- {ok,LSocket}.
- handle_call(stop,_From,Tab) ->
- {stop,normal,stopped,Tab}.
- handle_cast(stop,State) ->{stop, normal, State};
- handle_cast(_Msg,State) ->{noreply,State}.
- handle_info(_Info,State) ->{noreply,State}.
- terminate(_Reason,_State) ->ok.
- code_change(_OldVsn,State,_) ->{ok,State}.
- %% -----------------------------------
- %% -------------私有函数--------------
- %% -----------------------------------
- %%新建连接,只有新连接时才调用
- do_accept(State) ->
- case gen_tcp:accept(State#state.socket) of
- {ok, Socket}->
- %%创建进程处理响应
- spawn(fun() -> handle_client(State,Socket) end),
- %%创建新连接,持久化
- State#state.loop ! {connect, Socket},
- do_accept(State);
- _->
- ok
- end.
- %%处理flash安全策略文件的发送服务
- do_accept2(LSocket) ->
- case gen_tcp:accept(LSocket) of
- {ok, Socket}->
- spawn(fun() -> put_file(Socket) end),
- do_accept2(LSocket);
- _->ok
- end.
- %%短连接策略,连接完关闭
- put_file(Socket)->
- case gen_tcp:recv(Socket, 0) of
- {ok, _} ->
- %%判断数据返回策略文件
- gen_tcp:send(Socket, "
-
-
- \0");
- {error, closed} ->ok
- end,
- gen_tcp:close(Socket). %%关闭连接
- handle_client(State,Socket) ->
- case gen_tcp:recv(Socket, 0) of
- {ok, Data} ->
- State#state.loop ! {chat, Data},
- handle_client(State,Socket);
- {error, closed} ->
- State#state.loop ! {disconnect, Socket}
- end.
简单的flash客户端,为as3代码:
- package
- {
- import flash.net.Socket;
- import flash.display.Sprite;
- import flash.events.*;
- import flash.text.TextField;
- [SWF(width=600, height=300)]
- public class chat extends Sprite
- {
- private var textArea:TextField;
- private var input:TextField;
- private var label:TextField;
- private var socket:Socket=new Socket();
- public function chat()
- {
- socket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
- socket.connect("192.168.10.112", 8080); //连接到服务端,这里改成服务端的IP和端口
- socket.flush();
- initUI();
- input.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler); //按回车响应
- textArea.addEventListener(Event.RENDER, renderHandler);
- }
-
- private function sendMsg(Msg:String):void
- {
- socket.writeUTFBytes(Msg);
- socket.flush();
- }
-
- private function keyDownHandler(e:KeyboardEvent):void
- {
- if (13 == e.charCode)
- {
- var s:String = input.text ? input.text : "null";
- input.text = "";
- sendMsg(s);
- }
- }
-
- private function renderHandler(e:Event):void
- {
- textArea.scrollV = textArea.maxScrollV;
- }
-
-
- //初始化
- private function initUI():void
- {
- textArea = new TextField();
- textArea.width = 400;
- textArea.height = 150;
- textArea.border = true;
- textArea.x = 100;
- textArea.y = 30;
- addChild(textArea);
-
- input = new TextField();
- input.height = 20;
- input.width = 350;
- input.type = "input";
- input.border = true;
- input.multiline = false;
- input.x = 100;
- input.y = 200;
- addChild(input);
-
- label = new TextField();
- label.text = "回车发送";
- label.height = label.textHeight + 4;
- label.width = label.textWidth + 4;
- label.mouseEnabled = false;
- label.x = 460;
- label.y = 200;
- addChild(label);
- }
-
- // 事件处理回调函数,显示到屏幕上
- private function onSocketData(event:ProgressEvent):void
- {
- while (socket.bytesAvailable)
- {
- var s:String = socket.readUTFBytes(socket.bytesAvailable);
- if (textArea.text) s = "\n" + s;
- textArea.appendText(s);
- stage.invalidate();
- }
- }
- }
- }
运行
- 1> c(chat).
- {ok,chat}
- 2> c(chat_server).
- {ok,chat_server}
- 3> chat:start().
- {ok,<0.435.0>}
- .....
- n> chat:stop().
- {exit}
附件: chat.rar
文章来自:
阅读(1847) | 评论(0) | 转发(0) |