本文是专门翻译给搭档看的文档,因为可能对某些同学有帮助,所以也贴出来供有需要的人参考。要是不适合你的情况我可无法负责哦。另外,本文是word(页面大小A3)直接导出的,冗余代码太多,懒得改动了,显示分辨率宽度低于1280的兄台阅读时可能发生样式错位,还请将就一下。
FluorineFx开源库提供了一套用于.net框架的、实现了FLEX/FLASH remoting、Flex Data Services和real-time messaging的功能。
Microsoft .NET Framework 1.1 (1.1.4322)
Microsoft .NET Framework 2.0 (2.0.50727)
Microsoft .NET Framework 3.5 (3.5.21022.8)
Mono 1.2.4
(.NET 框架支持向后兼容)
Flex, Flash Remoting (RPC)
Flex Messaging (partial)
Flex Data Services (partial)
Supports AMF0, AMF3 and RTMP protocols (我们用这个)
Service Browser
Template based code generator (ASP.NET like syntax)
Easily integrate rich Internet applications with .NET backend
Easily integrate with Adobe Integrated Runtime (Adobe AIR™)
一个ASP.NET 2.0 application的物理结构如下:
(只有定位在LAC(bin目录)下的集合/类型能被fluorineFX访问)
我们更加推荐参阅FLUORINEFX VISUAL STUDIO 2005 向导章节,去创建一个启用了fluorineFX的解决方案。
如果你宁愿手动部署一个解决方案,下表标明了最少步骤:
1. 创建你的项目,或者打开一个已经存在的解决方案。
2. 使用“添加引用(R)…”来添加所需集合。
或者你打算debug fluorineFX,就把你之前下载来的FluorineFx-2.0.csproj 添加到你的解决方案里,然后使用“添加引用”并且选择一个项目引用。(– – ! 这家伙英语也不太标准,他不爱加标点符号,就和我们网上聊天时候一样,容易产生歧义)
3. 添加以下代码到你的Web.config文件,放到<system.web>节点里:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
…
<system.web>
<httpModules>
<add name="FluorineGateway" type="FluorineFx.FluorineGateway,FluorineFx" />
</httpModules>
…
</system.web>
…
</configuration>
4. 使用”添加Web窗体”来创建一个空文件Gateway.aspx。网关的URL将指向这个文件。
要将创建一个启用了fluorine的ASP.NET简化操作,Fluorine向导使你能够创建一个自定义的新项目,而且已经做了配置,使之能够与网关协同工作。(mousebomb:这里的网关就是Gateway.aspx实现的,一个remoting的服务器端或者一个RTMP的服务器端,都是面向这个网关通信)
有2个项目模板被用来创建完整的启用了FluorineFx的解决方案,而且使用在这个页面给出的选项创建新项目是我们推荐的,这样WebSite项目会被自动化地添加service library项目的引用。
在VS中选 文件\新建\项目… 选项来创建一个空项目。
在VS2005中选 文件\添加\新项目…
在已安装模板面板上,选择FluorineFx ServiceLibrary project模板
向导创建了ServiceLibrary(这只是一个带有fluorineFx集合引用的类库)。ServiceLibrary之所以被使用,有两个原因:你的应用程序能工作在中等信任环境下(mousebomb:不太明白具体指的是啥),而且便于架构分离。
现在工作区应该看上去是这样的:
选 文件\添加\新建网站…
在“已安装的模板”选择面板里选FluorineFx ASP.NET WebSite模板
此时,解决方案资源管理器中应该看到这样的结构:
在在WebSite属性面板页面你能管理程序集的引用(如有需要)。
至此,解决方案创建完毕,接下来就是运行和调试应用程序了。
使用Visual Studio .NET debugger来观察你的程序和service类在运行时的行为。
如果这是你第一次运行该程序,设置启动项目和起始页。
设置启动项目
设置起始页(该教程使用由向导生成的Console.aspx页面,该页面将重定向到Service浏览页)。稍后你可以改变起始页,加载你的客户程序。
设置断点、开始调试
VS启动默认浏览器,开始你的应用程序,加载了起始页。设置参数值并且点击“Call”按钮。
你可以开启更多你想要的浏览器,任何客户端的调用都会触发断点。
VS断点触发
(Mousebomb:这部分调试是以remoting为例子介绍的,我们只是参考一下,调试方法地球人都知道,下面的图文就不翻译了。)
每个Real-time Messaging(RTMP(Real-time Messaging Protocol)是Adobe的FMS产品使用的在线流媒体通信协议,直译叫做“即时消息传输协议”。RTM(Real-time Messaging),直译就是“即时消息传输”。)都有一个Application(Application Adapter)对象。Application对象能被用于管理程序的生命周期,接受、拒绝客户端连接尝试。
Application Adapter对象类似于FCS/FMS Application对象。
ASP.NET网站能支撑多个RTM应用程序。这些程序都位于ASP.NET网站根目录下的”apps”目录里,并以他们的目录名标识。
(mousebomb:比如例子里的HelloWorld就是一个RTM应用程序)
一个ASP.NET网站目录结构:
WebSite
–apps
–SharedBall
–VideoChat
–VideoRecording
一个在IIS中托管的ASP.NET网站目录结构:
Inetpub
–wwwroot
–WebSite
–apps
–SharedBall
-persistence
–VideoChat
–VideoRecording
-streams
此例子中有3个RTM应用程序:SharedBall, VideoChat, VideoRecording。要从客户端连接SharedBall应用程序,需要用这样的程序名:
nc = new NetConnection();
nc.connect("rtmp://localhost:1935/SharedBall")
在RTM程序中,资源都在树中管理。树中每个节点都叫做一个scope。scope是一个有状态对象,在已经连接到相同上下文路径的客户端群体中共享。如果这个scope是一个叶节点,就被称做BasicScope,如果scope有子scope的话,就被称作Scope。有两种预定义的BasicScope:SharedObject Scope和 BroadcastStream Scope。
每个程序都有自己的scope层级,根scope就是WebScope。还有一个全局scope,是WebScope的父级。每个scope有一个名字。GlobalScope名为“default”。WebScope都以每个程序上下文的根级命名。其他scope都以各自路径名命名。SharedObject Scope是以每个SharedObject的名字命名的。BroadcastStream Scope是以每个流的名字命名。
GlobalScope提供跨程序的资源和服务共享。
除了GlobalScope和BasicScopes以外,所有scope都能被客户端连接。一个scope对象能被创建来作为一个客户端连接请求的结果。比如,一个客户端可能发起一个请求,来尝试链接到application/room0,而此时application/room0不存在。在连接建立之后,room0被创建。如果url包含许多中间级scope,所有的这些scope都将被创建。比如请求了application/lobby0/room0,而lobby0和room0都不存在,这样一来lobby0和room0都会被创建。
一个典型的scope层级将是这样:
GlobalScope(default) –> WebScope(application) –> Scope(room0) –> BroadcastStream(live0), SharedObject(so1)
–> Scope(room1) –> SharedObject(so0)
在之前的例子中,代码nc.connect("rtmp://localhost:1935/application")将会连接客户端到WebScope。
IserviceProvider接口定义了一个机制,用来检索服务对象。每个scope对象都是一个服务提供者。
服务在树中管理(服务层级)。一个服务层级由若干ServiceContainer组成。ServiceContainer是用来存储相应类的实例,该类提供了针对自己类型的服务。你可以通过传类型来获取一个服务实例。
服务容器通常绑定到一个父级。这意味着当一个服务被请求且在其容器中没有发现时,容器询问它的父级等等。(服务容器没有子的概念,只有父级)。每个scope持有一个服务容器,此容器的父级是父级scope的服务容器。
在GlobalScope级,你拥有IstreamableFileFactory和IBWControlService等服务。
在WebScope级,你有IStreamFilenameGenerator, IsharedObjectSecurityService等等服务。
要写自己的程序代码,与客户端连接协同工作、处理服务器端事件、调用客户端方法、执行安全,必须实现一个自定义的Application Adapter。
FluorineFx.Messaging.Adapter.ApplicationAdapter类被用来作为新Application的基类。该类提供与客户端连接协同工作的方法、共享对象和流。
除此以外,Application对象有回调函数,可以在程序开始和结束被触发,也可以在客户端连接和断开连接时触发。
Application Adapter是一个程序级scope处理器。
每个RTM程序可以(可选地)包含一个配置文件放在该程序根目录中。配置文件命名为app.config。
自定义的Application Adapter类必须在配置文件里注册。
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!– Application object. Specify a fully qualified type name for your handler –>
<application-handler type="FluorineFx.Messaging.Adapter.ApplicationAdapter"/>
<!– Filename generator for streams. Specify a fully qualified type name to use a custom generator–>
<streamFilenameGenerator type="FluorineFx.Messaging.Rtmp.Stream.DefaultStreamFilenameGenerator"/>
<consumerService type="FluorineFx.Messaging.Rtmp.Stream.ConsumerService"/>
<providerService type="FluorineFx.Messaging.Rtmp.Stream.ProviderService"/>
<streamService type="FluorineFx.Messaging.Rtmp.Stream.StreamService"/>
<!– Manages creation, retrieval and update of remote shared objects–>
<sharedObjectService type="FluorineFx.Messaging.Rtmp.SO.SharedObjectService">
<persistenceStore type="FluorineFx.Messaging.Rtmp.Persistence.FileStore"/>
</sharedObjectService>
<!–
<sharedObjectSecurityService type=""/>
–>
</configuration>
Flash的NetConnection类将客户端连接到服务器。
var nc:NetConnection = new NetConnection();
var uri:String = "rtmp://localhost:1935/SharedBall";
nc.connect( uri );
SharedBall名字是该范例程序在apps目录下的相对程序名。
当application接受了连接请求后,该连接在客户端(flash.net.NetConnection)和服务器端(FluorineFx.Messaging.Api.IConnection)都可用。
自定义的Application Adapter可以重写以下方法,来提供在RTM程序的生命周期内各个步骤的访问。
Event |
Description |
public virtual bool AppStart(IScope application) |
application scope启动时调用 |
public virtual bool RoomStart(IScope room) |
room scope启动时调用 |
public virtual bool AppConnect(IConnection connection, object[] parameters) |
每次有新客户端连接是调用。 parameters 参数中内容是NetConnection.connect方法里uri后面传递的参数列表。 |
public virtual bool RoomConnect(IConnection connection, object[] parameters) |
每次有新客户端连接到application(room)时调用。 parameters 参数中内容是NetConnection.connect方法里uri后面传递的参数列表。 |
public virtual bool AppJoin(IClient client, IScope application) |
每次客户端假如application scope的时候调用。该事件在连接建立后调用。 |
public virtual bool RoomJoin(IClient client, IScope room) |
每次客户端假如room scope后调用。该事件在连接建立后调用。 |
public virtual bool RoomLeave(IClient client, IScope room) |
每次客户端离开room scope后调用。该事件在连接从scope断开之前调用。 |
public virtual bool AppLeave(IClient client, IScope application) |
每次客户端离开application scope时调用。该事件在连接从scope断开之前调用。 |
public virtual bool RoomDisconnect(IConnection connection) |
每次客户端断开时调用。 |
public virtual bool AppDisconnect(IConnection connection) |
每次客户端断开时调用。 |
public virtual bool RoomStop(IScope room) |
当room scope停止时调用。 |
public virtual bool AppStop(IScope application) |
当application scope停止时调用。 |
假设客户端正在连接到rtmp://server/app/room1/room2
首先,连接被建立,所以用户连接到所有room2经过的scope:
app(-> AppConnect)
room1(-> RoomConnect)
room2 (-> RoomConnect)
连接建立之后,客户端对象被检索,而且如果这是该客户端到此scope的首个连接,则加入scope:
app(-> AppJoin)
room1(-> RoomJoin)
room2(-> RoomJoin)
如果相同的客户端建立第二个连接到相同的scope,只有connect方法被调用。如果连接到部分相同的scope,只有一部分join方法被调用,比如,rtmp://server/app/room1/room3将触发:
app(-> AppConnect)
room1(-> RoomConnect)
room3(-> RoomConnect)
room3(-> RoomJoin)
在Application Adapter处理RPC调用
所有加进Application Adapter子类的方法都能被从客户端通过NetConnection.call方法调用。
比如以下服务器端代码:
public class Application : ApplicationAdapter
{
public string Echo(string msg)
{
return "Echo: " + msg;
}
}
能被客户端以下as代码片段触发:
nc = new NetConnection();
nc.connect("rtmp://localhost/application");
nc.onResult = function(obj) {
trace("The result is " + obj);
}
nc.call("Echo", nc, "Hello");
如果方法被定义了一个Iconnection类型的参数作第一个隐式参数,那么在客户端调用该方法时,当前连接将被自动填入。
如果一个connection实现了IserviceCapableConnection接口,那么它支持调用客户端方法。
要从你的application调用客户端上的方法,你将首先需要一个当前连接对象的引用。要获得活动连接,使用FluorineContext.Current.Connection属性。
范例:
IServiceCapableConnection connection = FluorineContext.Current.Connection as IServiceCapableConnection;
if (connection != null)
{
object[] args = new object[] { connection.Client.Id };
connection.invoke("setClientId", args);
}
客户端代码片段:
nc = new NetConnection();
nc.client = this;
nc.connect("rtmp://localhost/application");
…
function setClientId( id:String ):void
{
trace(id);
}
(mousebomb:具体客户端代码怎么实现你不用管,我保证和这个范例代码匹配的方式兼容就行了)
如果你需要获取方法返回的结果,你必须提供一个类,该类实现IpendingServiceCallback接口。在下面例子中,Application Adapter实现了此接口,方法的调用被更新后传递给IpendingServiceCallback接口。
public class Application : ApplicationAdapter, IPendingServiceCallback
{
public void ResultReceived(IPendingServiceCall call)
{
…
}
private void CallClient()
{
IServiceCapableConnection connection = FluorineContext.Current.Connection as IServiceCapableConnection;
if (connection != null)
{
object[] args = new object[] { connection.Client.Id };
connection.invoke("setClientId", args, this);
}
}
}
除此以外,以下ApplicationAdapter辅助方法可以用于调用客户端的方法:
void InvokeClients(string method, object[] arguments, IPendingServiceCallback callback)
void InvokeClients(string method, object[] arguments, IPendingServiceCallback callback, bool ignoreSelf)
void InvokeClients(string method, object[] arguments, IPendingServiceCallback callback, bool ignoreSelf, IScope targetScope)
targetScope 参数设置客户端连接到的将被调用的scope。
(mousebomb:Shared Objects等章节我们用不到,忽略)
RTMP例子参见:X:\Program Files\FluorineFx\Samples\Flash\Rtm
带着一脸茫然,飘过
好久没用了,学校学的那点知识都快荒废了。
学习了~~深奥
感謝您的大作,裨益良多
我是新学的 请问service-config.xml里要怎么设置? 如能指教感激不尽
@artemis : 你是做RTM还是做remoting呢?如果是RTM的话就去X:\Program Files\FluorineFx\Samples\Flash\Rtm下面看例子里的config。
比如说我们做一个RTM应用:
<?xml version=”1.0″ encoding=”utf-8″ ?>
<services-config>
<channels>
<channel-definition id=”my-rtmp” class=”mx.messaging.channels.RTMPChannel”>
<endpoint uri=”rtmp://{server.name}:1935″ class=”flex.messaging.endpoints.RTMPEndpoint”/>
</channel-definition>
</channels>
</services-config>
具体的你可以去问GFox,这篇文章是翻译给他看的,我自己并不玩serverside。
我是在尝试做rtm rtmp://{server.name}:1935这里的端口号是iis所占的端口号 还是任意的?
另外能不能 既有rtm也有remoting呢?
比如这样
1935不是IIS的端口,而是RTMP走的端口。
remoting和RTM是不是可以都有我不确定,应该可以,你可以试试看。
PS:留言会过滤代码,我们可以发邮件继续交流。
非常感谢 我自己再琢磨琢磨 以前用asp.net 后来玩flash 在后来用flex+webservice 没什么经验 就自己瞎折腾 现在FluorineFX的学习资料不多 所以对于这么及时的回复很感激
@artemis: 祝你顺利,希望研究之后分享心得给更多需要的朋友。
具体的你可以去问GFox,这篇文章是翻译给他看的,我自己并不玩serverside
还说你英语不好,太低调了=-=