隐锋的BLOG
ASP,.net开发

Red5共享对象的处理机制

Red5的共享对象有一条很关键:当没有客户端连这个共享对象时,该共享对象自动清空。客户端再次连接该共享对象时将创建新的同名共享对象,这时属性值为空。

创建:

当调用ApplicationAdapter的public boolean createSharedObject(IScope scope, String name, boolean persistent)方法时,就在scope下创建了一个名为name的共享对象。它又调用ISharedObjectService的createSharedObject方法。ISharedObjectService是在red5-common.xml中注入的,默认是org.red5.server.so.SharedObjectService。它的创建方法是:

 1:  /** {@inheritDoc} */
 2:  public boolean createSharedObject(IScope scope, String name, boolean persistent) {
 3:      if (hasSharedObject(scope, name)) {
 4:          // The shared object already exists.
 5:          return true;
 6:      }
 7:      synchronized (scope) {
 8:          final IBasicScope soScope = new SharedObjectScope(scope, name, persistent, getStore(scope, persistent));
 9:          return scope.addChildScope(soScope);
10:      }
11:  }

可以看到创建共享对象其实就是new了一个SharedObjectScope,它继承了BaseScope,实现了ISharedObject接口。

1:  public class SharedObjectScope extends BasicScope implements ISharedObject, StatusCodes

通过ApplicationAdapter的getSharedObject方法获取共享对象其实就是SharedObjectScope这个Scope!它有一个SharedObject成员,它负责存取具体的共享对象属性值。SharedObject并没有实现ISharedObject,我们平常操作的共享对象是ISharedObject(其实就是SharedObjectScope这个Scope),并非SharedObject对象。

当有客户端连接名为name的共享对象时,如果没有则调用ISharedObjectService的createSharedObject方法创建一个名为name的共享对象(scope)。

销毁:

客户端断开共享对象的连接,其实就是断开共享对象这个scope的连接!客户端发起断开共享对象的连接的事件时,RTMPHandler监听到SharedObject事件,进入onSharedObject处理函数。将共享对象消息分派给SharedObjectScope(实现ISharedObject接口)的dispatchEvent处理,根据消息的类型(SERVER_DISCONNECT)要么从rtmp连接中注销这个Scope(unregisterBasicScope),要么removeEventListener。

1:      public void unregisterBasicScope(IBasicScope basicScope) {
2:          basicScopes.remove(basicScope);
3:          basicScope.removeEventListener(this);
4:      }

它依然走了SharedObjectScope的removeEventListener方法。

 1:      @Override
 2:      public void removeEventListener(IEventListener listener) {
 3:          so.unregister(listener);
 4:          //part 1 of the fix for TRAC #360 - if we have not been released by all that acquired then 
 5:          //keep on disconnection of the last listener
 6:          if (so.isAcquired()) {
 7:              keepOnDisconnect = true;
 8:          }
 9:          //remove the listener
10:          super.removeEventListener(listener);
11:          //part 2 of the fix for TRAC #360 - check acquire
12:          if (!so.isPersistentObject() && (so.getListeners() == null || so.getListeners().isEmpty()) && !so.isAcquired()) {
13:              getParent().removeChildScope(this);
14:          }
15:  
16:          for (ISharedObjectListener soListener : serverListeners) {
17:              soListener.onSharedObjectDisconnect(this);
18:          }
19:      }

so.unregister中

1:      protected void unregister(IEventListener listener) {
2:          listeners.remove(listener);
3:          listenerStats.decrement();
4:          checkRelease();
5:      }

调用了checkRelease()方法:

 1:  /**
 2:   * Check if shared object must be released.
 3:   */
 4:  protected void checkRelease() {
 5:      //part 3 of fix for TRAC #360
 6:      if (!isPersistentObject() && listeners.isEmpty() && !isAcquired()) {
 7:          log.info("Deleting shared object {} because all clients disconnected and it is no longer acquired.", name);
 8:          if (storage != null) {
 9:              if (!storage.remove(this)) {
10:                  log.error("Could not remove shared object.");
11:              }
12:          }
13:          close();
14:      }
15:  }

看到了吗“Deleting shared object {} because all clients disconnected and it is no longer acquired.”,。在close中删除了共享对象的所有属性。再回到removeEventListener中:

1:  if (!so.isPersistentObject() && (so.getListeners() == null || so.getListeners().isEmpty()) && !so.isAcquired()) {
2:              getParent().removeChildScope(this);
3:          }

这里将SharedObjectScope这个Scope删掉了。

客户端再次连到这个共享对象时,如果没有则再次创建:

1:              if (!sharedObjectService.createSharedObject(scope, name, persistent)) {
2:                  sendSOCreationFailed(conn, name, persistent);
3:                  return;
4:              }

 

如果你的应用希望没有客户端连接时仍然保持着共享对象,可以通过checkRelease函数找解决办法——checkRelease有如下判断:

隐藏行号 复制代码 这是一段程序代码。
  1. if (!isPersistentObject() && listeners.isEmpty() && !isAcquired())
    

只有当该共享对象不是持久化的且没有客户端监听且没有获取(acquireCount=0)时,才走close清空共享对象。所以要想满足不清空的需求,要么让其持久化,要么监听不为空,要么acquireCount>0。对于非持久化的共享对象。系统调用

隐藏行号 复制代码 这是一段程序代码。
  1. sharedObject.acquire();
    

一下,就能保证所有客户端断开共享对象时acquireCount仍然大于0。以后需要释放的时候调用:

隐藏行号 复制代码 这是一段程序代码。
  1. sharedObject.release();
    
即可。

release函数源代码:

隐藏行号 复制代码 这是一段程序代码。
  1. public void release() {
    
  2.         if (acquireCount.get() == 0) {
    
  3.             throw new RuntimeException("The shared object was not acquired before.");
    
  4.         }
    
  5.         if (acquireCount.decrementAndGet() == 0) {
    
  6.             checkRelease();
    
  7.         }
    
  8.     }
    

当前acquireCount==0时调用release将会抛异常,提示“The shared object was not acquired before.”。

posted on 2010-06-19 19:22  糊涂隐锋  阅读(392)  评论(0编辑  收藏  举报