Erlang与Flash的Socket通讯-02
前一次实验,我使用的是本地swf文件,所以没有遇到安全沙箱问题,但在实际环境中我们的Flash文件是通过URL引用的,这时候Flash的Socket通讯会受到安全沙箱机制的限制。具体原理是:Flash在尝试向服务器A发起Socket连接前,会先尝试连接服务器A的843端口,求情一个xml格式的安全策略文件,该文件告诉Flash是否有权限向服务器A发起Socket连接。所以,我们需要在Erlang端增设一个守候在843端口的安全策略文件服务器。
此次实验的Erlang代码:
-module(server). -export([start/1]). -export([policy_file_server/0, policy_file_server_proc/1]). -export([flash_socket_server/1, flash_socket_server_proc/1]). start (Port) -> spawn(?MODULE, policy_file_server, []), spawn(?MODULE, flash_socket_server, [Port]). %%------------------------------------------------------------------------------ %% Flash Policy File Server %%------------------------------------------------------------------------------ policy_file_server () -> {ok, LSock} = gen_tcp:listen(843, [binary, {packet, 0}, {active, false}]), policy_file_server_accept(LSock). policy_file_server_accept (LSock) -> case gen_tcp:accept(LSock) of {ok, Sock} -> spawn(?MODULE, policy_file_server_proc, [Sock]), policy_file_server_accept(LSock); {error, Reason} -> io:format("policy file server exit: ~s~n", [Reason]), exit(Reason) end. policy_file_server_proc (Sock) -> case gen_tcp:recv(Sock, 0) of {ok, _} -> gen_tcp:send(Sock, << "<?xml version="1.0"?>" "<cross-domain-policy>", "<allow-access-from domain="*" to-ports="*" />", "</cross-domain-policy>",0 >>); _ -> ok end, gen_tcp:close(Sock). %%------------------------------------------------------------------------------ %% Flash Socket Server %%------------------------------------------------------------------------------ flash_socket_server (Port) -> {ok, LSock} = gen_tcp:listen(Port, [list, {packet, 2}, {active, false}]), flash_socket_server_accpet(LSock). flash_socket_server_accpet (LSock) -> case gen_tcp:accept(LSock) of {ok, Sock} -> spawn(?MODULE, flash_socket_server_proc, [Sock]), flash_socket_server_accpet(LSock); {error, Reason} -> io:format("flash socket server exit: ~s~n", [Reason]), exit(Reason) end. flash_socket_server_proc (Sock) -> case gen_tcp:recv(Sock, 0) of {ok, Request} -> io:format("Received: ~p~n", [Request]), gen_tcp:send(Sock, "done!"), flash_socket_server_proc(Sock); {error, closed} -> io:format("Client closed~n"), exit(closed); {error, Reason} -> io:format("Error: ~s~n", Reason), exit(Reason) end.
在调试Flash端时,我调试了很久都没有效果,最后发现原来是浏览器缓存问题。
以下是Flash端的实验代码:
package { import flash.events.MouseEvent; import flash.events.ProgressEvent; import flash.net.Socket; import flash.display.Sprite; import flash.text.TextField; import flash.text.TextFieldAutoSize; public class Main extends Sprite { private var sock:Socket; private var send:TextField; private var input:TextField; private var output:TextField; public function Main () { send = new TextField(); send.border = true; send.multiline = true; send.autoSize = TextFieldAutoSize.CENTER; send.htmlText = "<a href='event:#'> Send </a>"; send.mouseEnabled = true; send.selectable = false; send.x = 320 - send.width; send.y = 20; send.height = 21; input = new TextField(); input.border = true; input.type = "input"; input.autoSize = TextFieldAutoSize.NONE; input.x = 20; input.y = 20; input.width = 300 - send.width - 10; input.height = 19; output = new TextField(); output.border = true; output.multiline = true; output.autoSize = TextFieldAutoSize.NONE; output.x = 20; output.y = 20 + input.height + 10; output.width = 300; output.height = 300; output.wordWrap = true; addChild(send); addChild(input); addChild(output); sock = new Socket(); sock.addEventListener( ProgressEvent.SOCKET_DATA, function (event:ProgressEvent):void { /* 与Erlang端{packet, 0}对应的代码 while (sock.bytesAvailable) { var s:String = sock.readUTFBytes(sock.bytesAvailable); output.appendText(s); } */ /* 与Erlang端{packet, 0}对应的代码 */ var s:String = sock.readUTF(); input.text = ""; output.appendText(s); output.appendText("rn"); } ); sock.connect("localhost", 10086); sock.flush(); send.addEventListener( MouseEvent.CLICK, function (event:MouseEvent):void { /* 与Erlang端{packet, 0}对应的代码 sock.writeUTFBytes("Hello World!"); */ /* 与Erlang端{packet, 0}对应的代码 */ sock.writeUTF(input.text); sock.flush(); } ); } } }