谈Flash客户端与C++后台的几种通信方法
一,Flash 8以前时代:??????? 使用AS2 API根据fscommand,以及SetVariable实现双工简单通信。当时这些小儿科的东西,我玩的不亦乐乎,还用在学校学生实验平台上。简单明了的SetVariable方法在AS3里面不能用了。特点:通信量小。 ? ? Flash给C++传递参数: fscommand("MsgBox","helloword");C++获取Flash传递的参数通过添加FSCommand消息函数来实现: void CCppFlashDlg::FSCommandShockwaveflash1(LPCTSTR command,LPCTSTR args) { if (0 == strcmp("MsgBox",command)) { MessageBox(args); } } 二,Flash 9以上AS3的ExternalInterface:???????通过AS3的ExternalInterface调用C++中的函数,C++端通过Flash Player ActiveX控件中接口CallFunction调用AS3中的函数,值得注意的是,通信字符串格式都是XML格式,需要对XML文档进行解析。C++类的XML解析库有CMarkup和tinyXML。刚会了这些内容,我就用在了工业测控程序上,效果不错。特点:通信量小。 ? ? C++调用Flash的函数必须先在Flash客户端里面注册,方法如下: import mx.controls.Alert; import flash.external.*; ExternalInterface.addCallback("MsgBox2",this,MsgBox2); function MsgBox2(msg:String) { Alert.show(msg); }? ? ? 注册好以后VC即可调用Flash中的函数了,慢,不要着急,调用格式是XML的,所以需要多多学习XML文档的解析与生成: void CCppFlashDlg::OnOK() { swfUI.CallFunction("/ <invoke name=/"MsgBox2/">/ <arguments>/ <string>Hi</string>/ </arguments>/ </invoke>"); } 三,通过Socket通信?????? 建立Socket连接,需要特别处理Flash的安全策略文件。特点:通信量大,可以远程交互。 安全策略文件参考Flex Socket 与 C++ 通讯 --- 安全沙箱问题解决?? ? ?其代码如下:#include <winsock2.h> #include <windows.h> #include <iostream> using namespace std; #pragma comment(lib,"ws2_32.lib") void main() { WORD wVersionRequested; WSADATA wsaData; int err; short port=1800;//端口号 wVersionRequested = MAKEWORD( 1,1 ); err = WSAStartup( wVersionRequested,&wsaData );//初始化套接字 if ( err != 0 ) { return; } if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) { WSACleanup( ); return; } SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0);//创建套接字 SOCKET sockConn;//用来和客户端通信的套接字 SOCKADDR_IN addrSrv;//用来和客户端通信的套接字地址 addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY); addrSrv.sin_family=AF_INET; addrSrv.sin_port=htons(port); bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));//绑定端口 listen(sockSrv,5);//侦听 printf("Server %d is listening....../n",port); SOCKADDR_IN addrClient; int len=sizeof(SOCKADDR); char buf[4096];//接收的数据 char rbuf[100]= "<cross-domain-policy> " "<allow-access-from domain=/"*/" to-ports=/"*/"/>" "</cross-domain-policy> ";//套接字策略文件 while(1) { //接受连接 sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len); printf("Accept connection from %s/n",inet_ntoa(addrClient.sin_addr)); recv: //接收数据 int bytes; if((bytes=recv(sockConn,buf,sizeof(buf),0))==SOCKET_ERROR) { printf("接收数据失败!/n"); exit(-1); } buf[bytes]='/0'; printf("Message from %s: %s/n",inet_ntoa(addrClient.sin_addr),buf); if (0 == strcmp(buf,"<policy-file-request/>")) { //发送数据 if(send(sockConn,rbuf,strlen(rbuf)+1,0)==SOCKET_ERROR) { printf("发送数据失败!"); exit(-1); } printf("Message to %s: %s/n",rbuf); } else { //Echo if(send(sockConn,strlen(buf)+1,buf); goto recv; } //清理套接字占用的资源 closesocket(sockConn); } } 四,通过LocalConnection实现AS3与C++交互:? ? Flash的LocalConnection是基于内存文件读写实现的。在C++客户端开启线程监视内存文件,获取Flash建立的LocalConnection,解析其发送的数据,需要了解Adobe的AMF格式。特点:限于一台电脑上通信。 ? ? 假设仿真类已完成,并定义了消息: #define WM_LOCAL_CONN_MESSAGE_IN WM_USER+7 // A character was received and placed in the input buffer.? ? 当线程检测到Flash发送消息时 ,该仿真类派发该消息: ::SendMessage(pOwner->m_hWnd,WM_LOCAL_CONN_MESSAGE_IN,(WPARAM) msgRcv,(LPARAM) len); ? ? 在对话框类定义LocalConnectionEmulator实例,监测Flash的消息发送: protected: LocalConnEmulator lcSim;? ? 启动LocalConnection仿真程序: lcSim.InitEmulator(this); lcSim.StartEmulator();? ? Flash客户端发送的信息的获取是通过仿真程序派发自定义事件捕获得到,定义自定义消息函数: // Generated message map functions virtual BOOL OnInitDialog(); afx_msg LONG OnMessageIn(WPARAM arrayPtr,LPARAM len); afx_msg void OnSysCommand(UINT nID,LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP()? ? 添加消息映射: BEGIN_MESSAGE_MAP(CCppLocalConnDlg,CDialogEx) ON_MESSAGE(WM_LOCAL_CONN_MESSAGE_IN,OnMessageIn) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BUTTON1,&CCppLocalConnDlg::OnBnClickedButton1) END_MESSAGE_MAP()? ? 实现自定义消息函数: LONG CCppLocalConnDlg::OnMessageIn(WPARAM arrayPtr,LPARAM len) { char msgRcv[256]; memcpy(msgRcv,(char*)arrayPtr,len); msgRcv[len]=0; this->SetWindowText(msgRcv); return true; } 五,开源软件实现RTMP Server:??????诸如CRTMP Server,openRTMFP。特点:很强大,易于实现音视频聊天类应用。总体而言CRTMP Server还支持远程共享对象的,功能更加强大,而且内存和CPU资源占用极小,一句话,好的没法说,但是openRTMFP可以通过lua脚本配置服务器,实现与Adobe Flash Media的类似脚本,也相当不错,这一点由于crtmpServer。 ??? 如下为crtmpServer实现视频直播的demo,通过服务器直播摄像头内容(我使用虚拟摄像头,就是专门由来视频骗别人借钱汇款之类的软件),客户端为Adobe AS3API 文档中的例子: package { import flash.display.Sprite; import flash.events.*; import flash.media.Video; import flash.media.Camera; import flash.net.NetConnection; import flash.net.NetStream; import fl.controls.Button; import fl.controls.Label; public class NetStream_publish extends Sprite { private var connectionURL:String = "rtmp://127.0.0.1/live/"; private var videoURL:String = "liveVideo"; private var nc:NetConnection; private var ns_publish:NetStream; private var ns_playback:NetStream; private var video_publish:Video; private var video_playback:Video; private var cam:Camera; private var b:Button; private var l:Label; public function NetStream_publish() { setUpUI(); nc = new NetConnection(); nc.addEventListener(NetStatusEvent.NET_STATUS,netStatusHandler); // Add bandwidth detection handlers on the NetConnection Client to // prevent Reference Errors at runtime when using the "live" and "vod" applications. var clientObj:Object = new Object(); clientObj.onBWDone = onBWDone; clientObj.onBWCheck = onBWCheck; nc.client = clientObj; // Connect to the "live" application on Flash Media Server. nc.connect(connectionURL); } private function netStatusHandler(event:NetStatusEvent):void { trace(event.info.code + " | " + event.info.description); switch (event.info.code) { case "NetConnection.Connect.Success": // Enable the "Publish" button after the client connects to the server. b.enabled = true; break; case "NetStream.Publish.Start": playbackVideo(); break; } } private function publishVideo(event:MouseEvent):void{ // Disable the button so that you can only publish once. b.enabled = false; // Create a NetStream to send video to FMS. ns_publish = new NetStream(nc); ns_publish.addEventListener(NetStatusEvent.NET_STATUS,netStatusHandler); // Publish (send) the video to FMS. cam = Camera.getCamera(); ns_publish.attachCamera(cam); ns_publish.publish(videoURL); } private function playbackVideo():void { // Create the Video object to show the video on the stage video_playback = new Video(cam.width,cam.height); video_playback.x = cam.width + 20; video_playback.y = 10; addChild(video_playback); // Create a NetStream to receive the video from FMS. ns_playback = new NetStream(nc); ns_playback.addEventListener(NetStatusEvent.NET_STATUS,netStatusHandler); // Display the video that was published to FMS. video_playback.attachNetStream(ns_playback); ns_playback.play(videoURL); } private function setUpUI():void { b = new Button(); b.addEventListener(MouseEvent.CLICK,publishVideo); b.width = 150; b.label = "Publish video to server"; b.move(10,150); b.enabled = false; l = new Label(); l.width = 150; l.text = "Playing back from server" l.move(190,150); addChild(b); addChild(l); } // Handlers called by the Flash Media Server "live" and "vod" applications. public function onBWDone(... rest):Boolean { return true; } public function onBWCheck(... rest):Number { return 0; } } } ??? 多个客户端连接,同时实现点播视频与在线视频流播放: 如下为openRTMFP(目前尚不支持远程共享对象)的使用实例,需要配置服务器(CumulusServer.ini)及基于lua脚本语言的服务器脚本(main.lua): ;CumulusServer.ini port = 1985 udpBufferSize = 114688 keepAlivePeer = 10 keepAliveServer = 15 [logs] name=log directory=logs? ? 服务器lua脚本如下: function onStart(path) NOTE("Application '"..path.."' started") end function onStop(path) NOTE("Application '"..path.."' stopped") end function onConnection(client,userName,meeting) client.userName = userName; client.meeting = meeting; INFO("User connected: ",client.userName,"meeting: ",client.meeting); function client:getParticipants(meeting) result = {} i = 0; for key,cur_client in cumulus.clients:pairs() do if (cur_client.meeting == meeting) then i = i+1; participant = {}; participant.userName = cur_client.userName; participant.meeting = cur_client.meeting; if cur_client.id then participant.protocol = 'rtmfp'; end participant.farID = cur_client.id; result[i] = participant; end end return result; end function client:sendMessage(meeting,from,message) for key,cur_client in cumulus.clients:pairs() do if (cur_client.meeting == meeting) then cur_client.writer:writeAMFMessage("onMessage",message); end end end sendParticipantUpdate(client.meeting); end function onDisconnection(client) INFO("User disconnecting: "..client.userName); sendParticipantUpdate(client.meeting); end function sendParticipantUpdate(meeting) for key,cur_client in cumulus.clients:pairs() do if (cur_client.meeting == meeting) then cur_client.writer:writeAMFMessage("participantChanged"); end end end? ? Flash聊天客户端软件下载: 基于openRTMFP的聊天应用?
??
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |