这其实关于文件分享示例的改版,原文示例是基于flex的,我改成flash版本了(大致原理与上一篇完全相同):

有三个基本类:

1、P2PSharedObject.as 用于定义要分享的(图片)数据类



package p2p
{
import flash.utils.ByteArray;

public class P2PSharedObject
{

public var size:Number = 0;
public var packetLenght:uint = 0;
public var actualFetchIndex:Number = 0;
public var data:ByteArray;
public var chunks:Object = new Object();

public function P2PSharedObject()
{
}
}
}


2、LocalFileLoader.as 用于浏览本地图片并加载到舞台,将自动将图片以约64000 byte左右为单位,分成一块一块



package p2p
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.SecurityErrorEvent;
import flash.events.StatusEvent;
import flash.net.FileReference;
import flash.utils.ByteArray;


public class LocalFileLoader extends EventDispatcher
{
public function LocalFileLoader()
{

}


private var file:FileReference;
public var p2pSharedObject:P2PSharedObject;


public function browseFileSystem():void {
file = new FileReference();
file.addEventListener(Event.SELECT, selectHandler);
file.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
file.addEventListener(ProgressEvent.PROGRESS, progressHandler);
file.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler)
file.addEventListener(Event.COMPLETE, completeHandler);
file.browse();
}

protected function selectHandler(event:Event):void {
writeText("fileChosen");

writeText(file.name+" | "+file.size);

file.load();
}

protected function ioErrorHandler(event:IOErrorEvent):void {
writeText("ioErrorHandler: " + event);
}

protected function securityErrorHandler(event:SecurityErrorEvent):void {
writeText("securityError: " + event);
}

protected function progressHandler(event:ProgressEvent):void {
var file:FileReference = FileReference(event.target);
writeText("progressHandler: bytesLoaded=" + event.bytesLoaded + "/" +event.bytesTotal);

}

protected function completeHandler(event:Event):void {
writeText("completeHandler");

p2pSharedObject = new P2PSharedObject();
p2pSharedObject.size = file.size;
p2pSharedObject.packetLenght = Math.floor(file.size/64000)+1;
p2pSharedObject.data = file.data;


p2pSharedObject.chunks = new Object();
p2pSharedObject.chunks[0] = p2pSharedObject.packetLenght+1;
for(var i:int = 1;i<p2pSharedObject.packetLenght;i++){
p2pSharedObject.chunks[i] = new ByteArray();
p2pSharedObject.data.readBytes(p2pSharedObject.chunks[i],0,64000);

}
// +1 last packet
p2pSharedObject.chunks[p2pSharedObject.packetLenght] = new ByteArray();
p2pSharedObject.data.readBytes(p2pSharedObject.chunks[i],0,p2pSharedObject.data.bytesAvailable);

p2pSharedObject.packetLenght+=1;

writeText("----- p2pSharedObject -----");
writeText("packetLenght: "+(p2pSharedObject.packetLenght));


dispatchEvent(new Event(Event.COMPLETE));
}

protected function writeText(str:String):void{
var e:StatusEvent = new StatusEvent(StatusEvent.STATUS,false,false,"status",str);

dispatchEvent(e);
}
}
}


3、P2PFileShare.as 用于处理P2P文件分享(即从一个peer端发送另一个peer端)



package p2p
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.NetStatusEvent;
import flash.events.StatusEvent;
import flash.net.GroupSpecifier;
import flash.net.NetConnection;
import flash.net.NetGroup;
import flash.net.NetGroupReplicationStrategy;
import flash.utils.ByteArray;

public class P2PFileShare extends EventDispatcher
{

public var connected:Boolean = false;

public var netConnection:NetConnection;


public var netGroup:NetGroup;

private const SERVER:String = "rtmfp://localhost/";
private const DEVKEY:String = "HelloServer";

public var p2pSharedObject:P2PSharedObject;

public function P2PFileShare()
{
}

public function connect():void{
netConnection = new NetConnection();
netConnection.addEventListener(NetStatusEvent.NET_STATUS,netStatus);
netConnection.connect(SERVER+DEVKEY);
}

public function startSharing(p2pSharedObject:P2PSharedObject):void{
triggerEvent("startSharing - chunks shared: "+p2pSharedObject.packetLenght);
this.p2pSharedObject = p2pSharedObject;
netGroup.addHaveObjects(0,p2pSharedObject.packetLenght);
}

public function startReceiving():void{
triggerEvent("startReceiving");
p2pSharedObject = new P2PSharedObject();
p2pSharedObject.chunks = new Object();
receiveObject(0);
}


protected function onGroupConnected():void{
netGroup.replicationStrategy = NetGroupReplicationStrategy.LOWEST_FIRST;

}

protected function netStatus(event:NetStatusEvent):void{
triggerEvent(event.info.code);

switch(event.info.code){
case "NetConnection.Connect.Success":
setupGroup();
break;

case "NetGroup.Connect.Success":
connected = true;

onGroupConnected();

break;

case "NetGroup.Replication.Fetch.SendNotify": // e.info.index
triggerEvent("____ index: "+event.info.index);

break;

case "NetGroup.Replication.Fetch.Failed": // e.info.index
triggerEvent("____ index: "+event.info.index);

break;

case "NetGroup.Replication.Fetch.Result": // e.info.index, e.info.object
//triggerEvent("____ index: "+event.info.index+" | object: "+event.info.object);

netGroup.addHaveObjects(event.info.index,event.info.index);

p2pSharedObject.chunks[event.info.index] = event.info.object;

if(event.info.index == 0){
p2pSharedObject.packetLenght = Number(event.info.object);
triggerEvent("p2pSharedObject.packetLenght: "+p2pSharedObject.packetLenght);

receiveObject(1);

}else{
if(event.info.index+1<p2pSharedObject.packetLenght){
receiveObject(event.info.index+1);
}else{
triggerEvent("Receiving DONE");
triggerEvent("p2pSharedObject.packetLenght: "+p2pSharedObject.packetLenght);

p2pSharedObject.data = new ByteArray();
for(var i:int = 1;i<p2pSharedObject.packetLenght;i++){
p2pSharedObject.data.writeBytes(p2pSharedObject.chunks[i]);
}

triggerEvent("p2pSharedObject.data.bytesAvailable: "+p2pSharedObject.data.bytesAvailable);
triggerEvent("p2pSharedObject.data.length: "+p2pSharedObject.data.length);

dispatchEvent(new Event(Event.COMPLETE));
}
}


break;

case "NetGroup.Replication.Request": // e.info.index, e.info.requestID
netGroup.writeRequestedObject(event.info.requestID,p2pSharedObject.chunks[event.info.index])
//

triggerEvent("____ ID: "+event.info.requestID+", index: "+event.info.index);
break;

default:
break;
}
}

protected function setupGroup():void{
triggerEvent("setupGroup");
var spec:GroupSpecifier = new GroupSpecifier("myGroup");
spec.serverChannelEnabled = true;
spec.objectReplicationEnabled = true;
netGroup = new NetGroup(netConnection,spec.groupspecWithAuthorizations());
netGroup.addEventListener(NetStatusEvent.NET_STATUS,netStatus);
}


protected function receiveObject(index:Number):void{
netGroup.addWantObjects(index,index);
p2pSharedObject.actualFetchIndex = index;
}

protected function triggerEvent(str:String):void {
trace("P2pFilShare.triggerEvent 被调用:str->", str);
var e:StatusEvent = new StatusEvent(StatusEvent.STATUS,false,false,"status",str);

dispatchEvent(e);
}



}
}


最后的flash peer端:



package {

import fl.controls.Button;
import fl.controls.TextArea;
import fl.controls.TextInput;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.StatusEvent;
import flash.display.Loader;
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.net.NetGroupInfo;
import p2p.LocalFileLoader;
import p2p.P2PFileShare;
import p2p.P2PSharedObject;


public class p2p_FileShare extends MovieClip {

private var _btnBrowse:Button;
private var _btnShare:Button;
private var _btnReceive:Button;
private var _txtOutput:TextArea;
private var _txtReceive:TextInput;
private var _txtSend:TextInput;

private var _localFileLoader:LocalFileLoader;
private var _loader:Loader;
private var _fileShare:P2PFileShare;

public function p2p_FileShare(){
// constructor code
init();
}

private function init():void {
this.stage.align = StageAlign.TOP_LEFT;
this.stage.scaleMode = StageScaleMode.NO_SCALE;

this._localFileLoader = new LocalFileLoader();
this._localFileLoader.addEventListener(StatusEvent.STATUS, onStatus);
this._localFileLoader.addEventListener(Event.COMPLETE, fileLoaderComplete);

_fileShare = new P2PFileShare();
_fileShare.addEventListener(StatusEvent.STATUS, onStatus);
_fileShare.addEventListener(Event.COMPLETE, fileShareComplete);


this._fileShare.connect();
this._loader = new Loader();
addChild(_loader);
_loader.x = 218;
_loader.y = 43.35;

this._btnBrowse = btnBrowse;
this._btnShare = btnStartShare;
this._btnReceive = btnReceive;
this._txtOutput = txtOutput;
this._txtReceive = txtReceive;
this._txtSend = txtSend;

this._btnBrowse.addEventListener(MouseEvent.CLICK, _btnBrowse_Click);
this._btnReceive.addEventListener(MouseEvent.CLICK, _btnReceive_Click);
this._btnShare.addEventListener(MouseEvent.CLICK, _btnShare_Click);
}

private function onStatus(event:StatusEvent):void {
writeText(event.level);
if (event.level == "NetGroup.Connect.Success"){
_btnShare.enabled = false;
_btnReceive.enabled = true;
}
try {
refreshInfo();
} catch (e:Error){

}
}

private function fileLoaderComplete(event:Event):void {
writeText("fileLoaderComplete");
_loader.unload();
_loader.loadBytes(_localFileLoader.p2pSharedObject.data);
this._fileShare.startSharing(this._localFileLoader.p2pSharedObject);
this._btnShare.enabled = true;
this._btnReceive.enabled = false;
this._btnBrowse.enabled = false;
}

private function fileShareComplete(event:Event):void {
writeText("fileShareComplete");
_loader.unload();
_loader.loadBytes(_fileShare.p2pSharedObject.data);
}

private function writeText(txt:String):void {
trace("p2p_FileShare.writeText 被调用:txt->", txt);
this._txtOutput.appendText(txt + "\n");
}

private function _btnBrowse_Click(e:MouseEvent):void {
this._localFileLoader.browseFileSystem();
}

private function _btnShare_Click(e:MouseEvent):void {
this._fileShare.startSharing(this._localFileLoader.p2pSharedObject);
this._btnShare.enabled = false;
}


private function _btnReceive_Click(e:MouseEvent):void {
this._fileShare.startReceiving();
}


protected function refreshInfo():void {
var obj:NetGroupInfo = this._fileShare.netGroup.info;
_txtReceive.text = obj.objectReplicationReceiveBytesPerSecond + "";
_txtSend.text = obj.objectReplicationSendBytesPerSecond + "";
}
}

}


运行截图

fms4 p2p:图片分享_fms4


作者:菩提树下的杨过