ShareObject 主要用途
SharedObjects (SOs) 主要用于多客户端的实时数据同步和方法统一调用。SharedObject 是一个远程的对象能够被多个客户端共享,也就说这些客户端在同一个域(scope)里面。
什么是 scope?
你可以把scope 当作一个聊天室,这个聊天室是通过URI 链接到服务器
例如:rtmp://localhost/red5test/lobby
"red5test" 是application 域(scope)
"lobby" 是聊天室作用域,也即 "red5test" 子域
客户端代码的编写
客户端可以用下面的代码获得 SharedObject 连接:
// at first you need to establish a connection to the server of course nc = new NetConnection(); nc.connect( "rtmp://localhost/red5test/", true ); // when the NetConnection is successfully established // (you have to listen to NetStatusEvent.NET_STATUS event) // you can connect to a remote SharedObject e.g. named "chat" so = SharedObject.getRemote("chat", nc.uri, false); // when the connection to the SO is successfully established, // you can begin to specify its contents so.setProperty("message","hello to all");
red5 处理 ShareObject 过程
当客户端程序连接到SharedObject,red5就会查找指定作用域SharedObject是否存在(例如上面程序“chat”).如果存在,red5就会重用它;如果不存在,red5 就会在该作用域下创建新的SharedObject提供客户端使用。
当最后一个客户端从该作用域断开连接,SharedObject就会被销毁(at least for non-persistent ones)。
服务端 ShareObject 处理过程
a)服务端获取 SharedObject
也可以从服务获取 SharedObject ,例如,服务端可以对SharedObject 做改动,让后把这些改动以广播的方式传递给客户端
在你的 java程序中你可以用如下的代码检查SharedObject 的存在
//get scope of the current connection first
IScope scope = Red5.getConnectionLocal().getScope();
// get SO
ISharedObject so = getSharedObject(scope, "chat");
b)服务端创建 SharedObject
当room 创建后,就可以创建新的 SharedObject 了,方法是覆写 ApplicationAdapter roomStart 的 roomStart 方法,代码如下:
public class SampleApplication extends ApplicationAdapter { public boolean roomStart(IScope room) { if (!super.roomStart(room)) return false; createSharedObject(room, "sampleSO", true); ISharedObject so = getSharedObject(room, "sampleSO"); // Now you could do something with the shared object... return true; } }
如果需要创建 application 作用域 SharedObject ,那么你需要在appStart 方法中做如同上面代码所做工作
自己创建 ShareObject 问题
其中一个有利因素是你可在SharedObject 增加一个监听,当客户连接到SharedObject 时,你可以更新数据或者断开连接等等。
客户端 还是 服务端 初始化 SharedObject
在java 服务端创建 SharedObject 会有意料不到的问题(至少对我来说有),这些问题大部分与客户端,服务端初始化 SharedObject 有关。
当然所有的 SharedObject 都是在red5server 上创建的,但是不同之处是在哪儿初始化。
a)服务端初始化 SharedObject ,SharedObject 是同过java 服务端 调用createSharedObject 创建的,创建后就等待客户端的连接
b)客户端是初始化SharedObject 是客户端连接到服务端时候,服务端发现不存在SharedObject 然后自动创建的。
问题会出现在你自定义服务端代码来创建SharedObject
例如我想创建 application 作用域名叫 "chat " 的SharedObject ,并且添加一个监听,所以我在appStart 加入如下的代码:
createSharedObject(scope, "chat", false); ISharedObject so = getSharedObject(scope, "chat"); ISharedObjectListener listener = new MyCustomListener(); so.addSharedObjectListener(listener);
appStart 方法在服务器启动时只被调用一次,启动后服务端创建名叫chat 的 SharedObject 对象 。客户端可以用application 作用域连接到 chat 对象,至此所有的工作都很正常。
但是当所有的客户端断开chat 的连接后,由服务端创建的chat 会被red5服务器销毁,之后当客户端再次连接chat 对象,red5 将找不到 chat 对象并自动创建一个 chat 。新的chat对象 是由客户端初始化创建的,这自动的创建方式,没有加入监听,所以自定义事件将不会得到响应。
这样的问题不会出现的room 作用域中,假设把上面的代码放到 roomStart 方法中。当最后一个客户端断开连接后 room 也会被销毁,roomStart 方法在 application 生命周期中将多次被调用,例如:当第一客户端连接一个room .这种情况下问题会出现在最后的客户端断开的不是它连接的room.
自己创建 ShareObject 问题解决办法
如果有些类似如SharedObjectCreationHandler 或者 SharedObjectFactory 方法就好了,不幸的是没有。
但是 ISharedObjectSecurity 提供了此类的解决方案
ISharedObjectSecurity 可以在 Application 中被 registerSharedObjectSecurity 注册,它被用来控制SharedObject的访问,它有一个名叫isCreationAllowed事件方法,该方法在自动创建ObjectSecurity 前判断能否被调用方法创建。
代码如下:
import static org.red5.server.api.ScopeUtils.getScopeService; ... public class MySecurityHandler implements ISharedObjectSecurity { ... public boolean isCreationAllowed(IScope scope, String name, boolean persistent) { if ( "chat".equals(name) ) { // get the SO creation service. Basically the following lines are exactly // what MultiThreadedApplicationAdapter does. You can also pass a reference // to your Application to this SecurityHandler and use it instead ISharedObjectService service = (ISharedObjectService) getScopeService( scope, ISharedObjectService.class, SharedObjectService.class, false ); if( service.createSharedObject(scope, name, persistent) == true ) { ISharedObject so = service.getSharedObject(scope, name); ISharedObjectListener listener = new MyCustomListener(); so.addSharedObjectListener(listener); } } return true; } ... }