Red5学习笔记(二)连接通信

2 篇文章 0 订阅
1 篇文章 0 订阅
Red服务器对象关系:
    首先服务器会有一个全局的Scope对象 ,它包含每一个应用对应的WebScope对象,一个WebScope对象包含唯一的ApplicationAdapter对象;一个ApplicationAdapter对象可以继续创建从属于自己的多个Room对象。WebScope对象和Room对象都是IScope对象的具体实现,它们都包含一个IClient类型的集合体Set。IClient对象包含一个IConnection类型的集合体Set。用于通信的SharedObject生存在WebScope或者Room里。

通信流程:
    1、 当ActionScript 3里的NetConnection对象尝试连接Red5的某个应用时,Red5服务器端对应的WebScope会响应这个请求,将接收到的连接转换成一个IClient对象,保存在当前的Scope,也就是Web Scope的Set<IClient>里,这样就完成了创建连接的过程。
    2、在RTMP协议下,有两种方法可以在客户端之间传递信息:
        a、使用服务器端SharedObject传递信息。该方法会尝试支所有连接成功的客户端广播信息,效率更好。
        b、使用服务器端NectConnection 调用 客户端Client自定义方法。该方法可对指定的客户传播信息,更加准确。
    3、当客户端连接成功时,Red5服务器端创建出一个SharedObject,用于不同客户端之间共享信息。
服务器端代码:
package com.red5app;
import java.util.HashMap;
import java.util.Map;
import org.red5.server.adapter.ApplicationAdapter;
import org.red5.server.api.IConnection;
import org.red5.server.api.IScope;
import org.red5.server.api.so.ISharedObject;
/**
* 在Red5的服务器端类体系里,每一个监听的应用实例都需要继承类ApplicationAdapter
* 项目需要引用Red5安装目录下的red5.jar
* @author Administrator
*/
public class Application extends ApplicationAdapter{
/**
* 实现appStart和appStop两个必要的方法
**/
private IScope appScope;
/**clientDic用来保存连接的客户端用户信息,key为连接的用户名,value是对应的IConnection对象*/
private Map<String,IConnection> clientDic = new HashMap<String,IConnection>();
public boolean appStart()
{
return true;
}
public void appStop()
{
}
@Override
/***
* 连接逻辑处理
*
*/
public synchronized boolean connect(IConnection conn, IScope scope,
Object[] params) {
if(params.length == 0){
rejectClient("Must pass the login name.");
}
/**获取第一个参数,第一个参数传用户名*/
String loginname = params[0].toString();
/**当前连接对象设置一个用户名属性*/
conn.setAttribute("UserName", loginname);
/**判断当前用户名是否存在HashMap里,如果存在则拒绝连接*/
if(!clientDic.keySet().contains(loginname))
{
clientDic.put(loginname, conn);
/**
* 获取服务器端SharedObject对象,当SharedObject对象为空时创建,并将用户列表保存到该对象
* 每次执行连接时,维护更新用户列表
* */
ISharedObject so = this.getSharedObject(scope, "UserSO");
if(so==null)
{
this.createSharedObject(scope, "UserSO",true);
so = getSharedObject(scope, "UserSO");
}
so.setAttribute("userlist", clientDic.keySet().toArray());
}
else
{
this.rejectClient("The same user has logged in already.");
}
return super.connect(conn, scope, params);
}
@Override
/***
* 断开连接逻辑处理
*
*/
public synchronized void disconnect(IConnection conn, IScope scope) {
/**判断断开的用户是否存在当前用户列表,如果存在就删除,然后更新用户列表*/
String loginname = conn.getAttribute("UserName").toString();
if(loginname != null)
{
if(clientDic.keySet().contains(loginname))
{
clientDic.remove(loginname);
ISharedObject so = this.getSharedObject(scope, "UserSO");
if(so != null)
{
so.setAttribute("userlist", clientDic.keySet().toArray());
}
}
}
super.disconnect(conn, scope);
}
}
客户端代码:
package
{
import flash.display.Sprite;
import flash.events.NetStatusEvent;
import flash.events.SyncEvent;
import flash.net.NetConnection;
import flash.net.SharedObject;
public class ConnectTest extends Sprite
{
private var nc:NetConnection;
private var so:SharedObject;
public function ConnectTest()
{
nc = new NetConnection();
nc.addEventListener(NetStatusEvent.NET_STATUS,netStatus);
nc.connect("rtmp://127.0.0.1/firstapp","test1");//连接时地址不需要端口号
}
private function netStatus(e:NetStatusEvent):void
{
trace(e.info.code);
trace(e.info.level);
switch(e.info.code)
{
case "NetConnection.Connect.Success":
so = SharedObject.getRemote("UserSO",nc.uri,true);
so.addEventListener(SyncEvent.SYNC,onSync); //在服务器更新了远程共享对象后调度
so.connect(nc);
break;
default:
trace(e.info.application);
break;
}
}
private function onSync(e:SyncEvent):void
{
trace("event:"+e);
//遍历值改变的属性,changeList存着服务器端SharedObject对象属性变化的对象,其中每个元素都有一个code属性表明变化的类型
for(var i:Object in e.changeList)
{
var changeObj:Object = e.changeList[i];
trace("Change Code:"+changeObj.code);
switch(changeObj.code)
{
case "change":
trace("name:"+changeObj.name,"oldValue:"+changeObj.oldValue);
break;
}
}
}
}
}

广播信息
服务器端:
    在客户端,可以通过NetConnection对象的call方法来调用服务器端的某个方法,NetConnection对象通过call调用服务器方法里会传入一个字符串、一个Responder对象和其他参数,在服务器定义被调用的方法应有一个List<String>参数定义并且此方法必须是public类型。 该方法需要实现以下逻辑为: 获取当前共享的SharedObject; 通过SharedObject广播信息到所有客户端。
    下面代码是服务器端方法获得当前共享的SharedObject对象并广播信息:
   public void sendMessage(List<String> params){
                //通过Red5获取当前的Connection对象和Scope
               IConnection conn = Red5.getConnectionLocal();    
               IScope scope = conn.getScope();
               ISharedObject so = getSharedObject(scope,"UserSO");//获取名字UserSO的服务器端SharedObject对象
         //sharedObject通过sendMessage方法调用所有客户端的receiveMsg方法广播信息,
        <span style="font-family:Microsoft YaHei UI;">//</span>客户端实现 receiveMsg方法接收信息并处理  <pre name="code" class="java">        so.sendMessage("receiveMsg",params);
 }
 客户端代码: 
  
function netStatus(event:NetStatusEvent):void{
   if(event.info.code == "NetConnection.Connect.Success"){
       var so:SharedObject = SharedObject.getRemote("UserSO",nc.uri,true);
       //<span style="font-family:Microsoft YaHei UI;">设置服务器端回调方法的对象</span>
       so.client = this;
       so.connect(nc);
   }
}
/<span style="font-family:Microsoft YaHei UI;">**
 * 被服务器端回调的方法
 * @params msg 信息
</span><span style="font-family:Microsoft YaHei UI;">public function receiveMessge(msg:String):void{
//逻辑处理
}
</span>

单播信息到特定用户
    单播信息的原理和多播类似,不同的是单播是通过服务器端调用客户端回调方法来完成而不是依靠SharedObject的同步机制来完成。
    与广播同样,在服务器端需要定义一个方法供客户端调用,客户端需要传递发送方、接收者、内容等信息。 服务器端定义接收信息的方法如下:
 /**
* 接收客户端传递的调用信息
* @params params 客户端传递的参数数组,第一个参数是发送者名称,第二个参数是接收者名称,第三个参数是信息内容
*
*/
   public void sendPrvMessage(List<String> params) {
if(params.size() != 3){
  //做一些错误处理
return;
}
String sender = params.get(0);
String receiver = params.get(1);
String msg = params.get(2);
              //判断是否有接收者的连接
              if(clientdic.keySet().contains(receiver)){
                  IConnection conn = clientdic.get(receiver);
                  //要回调客户端的方法,需要使用接口类型IServiceCapableConnection
                  if(conn instanceof IServiceCapableConnectioin){
                    IServiceCapableConnection sc = (IServiceCapableConnection) conn;
                    //调用conn所连接的客户端的receivePrvMsg方法
                    sc.invoke("receivePrvMsg",new Object[]{sender,msg});
                  }
               }
}

客户端定义回调函数receivePrvMsg:
public function receivePrveMsg(sender:String,msg:String):void{
    //逻辑处理
}









  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值