首页 技术 正文
技术 2022年11月17日
0 收藏 353 点赞 3,562 浏览 7046 个字

在fms4以前Adobe只允许在stratus中才能使用p2p功能。令人高兴的是,在最新发布的fms4中,p2p功能已经集成进来了,这将给实时视频类的应用带来更高的效率,adobe这次很给力!

为了使用p2p,开发用的flex sdk至少要4.1以上(当然最高版本是代号为hero的4.5版本,可从adobe的官网下载),另外还需要fms4(同样可从adobe官网下载开发版本)。

先上完整代码吧:

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 package {     import fl.controls.Button;    import fl.controls.Label;    import fl.controls.TextArea;    import flash.display.Sprite;    import flash.events.MouseEvent;    import flash.events.NetStatusEvent;    import flash.net.GroupSpecifier;    import flash.net.NetConnection;    import flash.net.NetGroup;    import flash.net.NetGroupReplicationStrategy;    import flash.text.TextFormat;      public class p2p_HelloWorld extends Sprite {                 private var _lbl:Label;        private var _btnAddToWant:Button;        private var _btnGenData:Button;        private var _btnAddToHave:Button;        private var _txtObj:TextArea;        private var _txtOutput:TextArea;        private var _data:Vector.<String>;        private var _dataLength:uint = 100;        private var _nc:NetConnection;        private var _ng:NetGroup;        private var _spec:GroupSpecifier;        private var _server:String = "rtmfp:https://localhost/HelloServer";        private var _groupName:String = "myGroup";        private var _connected:Boolean = false;         public function p2p_HelloWorld(){            init();        }         private function init():void {            this._btnAddToWant = btnAddToWant;            this._btnAddToHave = btnAddToHave;            this._btnGenData = btnGenData;            this._txtObj = txtObj;            this._txtOutput = txtOutput;            this._lbl = lbl;                         var style:TextFormat = new TextFormat("宋体", 12, 0x000000,false,false,false,null,null,null,null,null,null,5);            this._btnAddToHave.setStyle("textFormat", style);            this._btnAddToWant.setStyle("textFormat", style);            this._btnGenData.setStyle("textFormat", style);            this._txtObj.setStyle("textFormat", style);            this._txtOutput.setStyle("textFormat", style);            this._lbl.setStyle("textFormat", style);                         this._btnGenData.addEventListener(MouseEvent.CLICK, _btnGenData_Click);            this._btnAddToHave.addEventListener(MouseEvent.CLICK, _btnAddToHave_Click);            this._btnAddToWant.addEventListener(MouseEvent.CLICK, _btnAddToWant_Click);             //先连接到服务器            _nc = new NetConnection();            _nc.addEventListener(NetStatusEvent.NET_STATUS, _nc_Net_Status);            _nc.connect(_server);            output("正在连接 " + _server + " ...");        }         private function _nc_Net_Status(e:NetStatusEvent):void {            output(e.info.code);            switch (e.info.code){                case "NetConnection.Connect.Success":                       //连接成功后,要设置NetGroup                    this._spec = new GroupSpecifier(this._groupName);                                       _spec.serverChannelEnabled = true;//设置允许创建到服务端的通道                    _spec.objectReplicationEnabled = true;//允许对象复制                    _ng = new NetGroup(_nc, _spec.groupspecWithAuthorizations());                    _ng.addEventListener(NetStatusEvent.NET_STATUS, _nc_Net_Status);                    break;                case "NetGroup.Connect.Success":                    _connected = true;                    _ng.replicationStrategy = NetGroupReplicationStrategy.LOWEST_FIRST;//设置数据块传输时,先传递索引号最小的块                    break;                case "NetGroup.Replication.Fetch.SendNotify":                     //每当"接收方"有数据到达(但尚未开始接收)时,将触发此处理                    output("    -->通知:数据块 " + e.info.index + "  即将被接收");                    break;                case "NetGroup.Replication.Fetch.Failed":                     //“接收方”有数据接收失败时,将触发此处理                    output("    -->错误:数据块 " + e.info.index + " 接收失败");                    break;                case "NetGroup.Replication.Fetch.Result":                     //“接收方”每次成功接收到数据时,触发此段处理                    output("    -->数据块 " + e.info.index + " 已成功接收,值:" + e.info.object);                    _ng.addHaveObjects(e.info.index, e.info.index); //接收完成以后,将接收到的数据加入“待发送对象列表"中,这样人越多,传输越稳定,速度也越快                      if (_data == null) {                        _data = new Vector.<String>(this._dataLength);                    }                    _data[e.info.index] = e.info.object.toString();                    //说明全部接收完了                    if (e.info.index == this._dataLength - 1) {                        for (var i:int = 0; i < _dataLength; i++){                            _data[i] = "这是数据 " + i.toString();                            this._txtObj.appendText("index:" + i.toString() + ",data:" + _data[i] + " | ");                        }                    }                    break;                case "NetGroup.Replication.Request":                     //每当有数据传输请求时,“提供方”将触发此处理                    _ng.writeRequestedObject(e.info.requestID, _data[e.info.index]);//这里才是真正的响应“接收方",将指定的数据发送过去                    output("    -->数据块 " + e.info.index + " 请求被发送,本次请求ID:" + e.info.requestID);                    break;                default:                    break;            }        }         //初始化生成数据        private function _btnGenData_Click(e:MouseEvent):void {            this._txtObj.text = "";            if (_data==null){                _data = new Vector.<String>(this._dataLength);            }            for (var i:int = 0; i < _dataLength; i++){                _data[i] = "这是数据 " + i.toString();                this._txtObj.appendText("index:" + i.toString() + ",data:" + _data[i] + " | ");            }        }                 //将生成的初始数据,添加到待发送的“列表”中        private function _btnAddToHave_Click(e:MouseEvent):void        {            this._ng.addHaveObjects(0, _dataLength - 1);        }                 //请求接收数据        private function _btnAddToWant_Click(e:MouseEvent):void        {            this._ng.addWantObjects(0, _dataLength - 1);        }         //输出结果        private function output(s:String):void {            this._txtOutput.appendText(s + "\n");        }    } }

在这段代码中我们看到了一个全新的NetGroup对象,要使用p2p,“接收方”与“接收方”必须先加入到“相同名称”的NetGroup中。而且要发送的数据,必须分解有顺序的一块一块(通常用有序数组来保存这些数据块),然后”发送方”调用addHaveObjects方法设置待发送的数据块,而”接收方”则调用addWantObjects请求需要接收的块。

一旦”接收方”调用了addWantObjects方法后,”发送方”便会进入”NetGroup.Replication.Request”状态,此时”发送方”响应”接收方”的请求,将需要的数据块以udp协议发送过去,然后“接收方”会收到”NetGroup.Replication.Fetch.SendNotify”的数据到达通知,如果成功接收,将进入“NetGroup.Replication.Fetch.Result”状态,全部接收完成后,开发人员可根据需要将这些块重新合并成原始对象。

处理过程示意图如下:

FMS4中的P2P功能

文中代码最终的运行截图:

FMS4中的P2P功能

测试方法:发送方先点击“生成初始数据”,然后点击“添加要发送的数据”,最后接收方点击“接收数据”

此外,如果多开几个”接收方”,可以验证一下“接收方”收到数据后是否能变成数据提供者,向其它接收方提供数据,也就是所谓的p2p中”人越多,速度越快,传输越稳定”的现象

FMS4中的P2P功能

但是,FMS4中的p2p也不是完美无缺,实际测试下来,目前尚不能打洞,即所有peer端如果在同一个网段,传输是正常的,但是如果不是同一个网段则无法进行p2p。

不过,如果参与p2p的机器越多,接收到数据的客户端根据文中的代码处理,也可以变成发送方,这表示有可能本来在同一个网段的其它用户原本没有数据来源,但是只要本网段有一个用户接收到数据后(比如这个用户有多重网络),本网段的其它用户也能接收数据了,这在一程度上能解决打洞的矛盾。

示例源文件下载:http://files.cnblogs.com/yjmyzz/p2pTest.7z

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,000
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,512
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,358
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,141
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,771
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,849