erlang服务端,主要实现与flash客户端的连接、消息传递服务
自带843端口服务解决flash9以上暴汗的安全沙箱问题
- -module(chat).
- -behaviour(gen_server).
- -export([start/0,find/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(player, {id,socket,time=none}).
- %%回调gen_server创建服务
- start() ->
- gen_server:start_link({local,?MODULE},?MODULE,[8080],[]).%%定为8080端口
- %%停止服务
- stop() ->
- gen_server:call(?MODULE,stop).
- %%查找玩家
- find(Uname)->
- client_manager ! {list,Uname}.
- %%初始化,Port被持久化
- init([Port]) ->
- %%维护队列
- register(client_manager, spawn(fun() -> manage_clients([]) end)),
- {Tag, LSocket}=gen_tcp:listen(Port, ?TCP_OPTIONS),
- case Tag of %%创建监听
- ok -> spawn(fun() -> do_accept(LSocket) end); %%统一接收
- error -> exit({accept,LSocket}) %%出错,退出连接
- end,
- %%与flash通信的安全策略文件传送监听接口
- {Req, AsSocket}=gen_tcp:listen(843, ?TCP_OPTIONS),
- case Req of
- ok -> spawn(fun() -> do_accept2(AsSocket) end);
- error -> exit({accept,AsSocket})
- end,
- {ok,LSocket}.
- handle_call(stop,_From,Tab) ->
- client_manager!{exit},
- {stop,normal,stopped,Tab}.
- handle_cast(_Msg,State) ->
- {noreply,State}.
- handle_info(_Info,State) ->
- {noreply,State}.
- terminate(_Reason,_State) ->
- ok.
- %%热交换
- code_change(_OldVsn,State,_) ->
- {ok,State}.
- %% -----------------------------------
- %% -------------私有函数--------------
- %% -----------------------------------
- %%新建连接,只有新连接时才调用
- do_accept(LSocket) ->
- case gen_tcp:accept(LSocket) of
- {ok, Socket}->
- %%创建进程处理响应
- spawn(fun() -> handle_client(Socket) end),
- %%创建新连接,持久化
- client_manager ! {connect, Socket},
- do_accept(LSocket);
- _->ok
- end.
- %%处理flash安全策略文件的发送服务
- do_accept2(LSocket) ->
- case gen_tcp:accept(LSocket) of
- {ok, Socket}->
- spawn(fun() -> put_file(Socket) end),
- do_accept2(LSocket);
- _->error
- end.
- %%短连接策略,连接完关闭
- %%flash安全沙箱处理守候服务
- put_file(Socket)->
- case gen_tcp:recv(Socket, 0) of
- {ok, _} ->
- %%判断数据返回策略文件
- gen_tcp:send(Socket, "
-
-
- ");
- {error, closed} ->ok
- end,
- gen_tcp:close(Socket). %%关闭连接
- %%持续、长连接的响应
- handle_client(Socket) ->
- case gen_tcp:recv(Socket, 0) of
- {ok, Data} ->
- client_manager ! {chat, Data},
- handle_client(Socket);
- {error, closed} ->
- client_manager ! {disconnect, Socket} %%这里退出时会出错
- end.
- %%对内响应,管理连接,事件列表,记录玩家数据
- manage_clients(Players) ->
- receive
- {connect, Socket} ->
- Player = #player{
- id="guest_"++integer_to_list(random:uniform(100000)), %%随机命名用户名
- socket=Socket,
- time=time()
- }, %%新增记录
- io:fwrite("Connected: ~w~n", [Socket]),
- NewPlayers = [Player|Players]; %%累加到列表
- {disconnect, Socket} ->
- io:fwrite("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({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("User information: ~w~n", [Player]);
- _->io:fwrite("No found.~n")
- 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();
- }
- }
- }
- }
文章来自:
阅读(799) | 评论(0) | 转发(0) |