`
timcuisw
  • 浏览: 20111 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
最近访客 更多访客>>
社区版块
存档分类
最新评论

Red5 Flash交互服务器学习笔记(3)(转载)

阅读更多
    忙了好几天,最近也算把Red5服务器服务端基本搞定了。
    为了熟悉服务端代码,以及了解API,我仿照着FMS的模式做了一个多人聊天室。基本实现了视频、群聊、私聊几个基本功能。看到网上似乎还没有人放出这类的源代码,我索性就先当回螃蟹吧!
  我们先来看代码:
  服务端:
  Application.java
  
package org.jerry.videochat;

import java.util.*;
import org.red5.server.adapter.ApplicationAdapter;
import org.red5.server.api.IConnection;
import org.red5.server.api.IScope;
import org.red5.server.api.service.IServiceCapableConnection;
import org.red5.server.api.so.ISharedObject;

public class Application extends ApplicationAdapter {
// 属性
private IScope appScope;

private String username;

private ISharedObject listSO;

private ISharedObject msgSO;

private Map<String, IConnection> onLineClient = new HashMap<String, IConnection>();

// 方法
// 此应用开始运行时触发的方法
public boolean appStart(IScope app) {
   if (!super.appStart(app)) {
    return false;
   }
   appScope = app;
   return true;
}

// 客户端连接的时候触发的方法
public boolean appConnect(IConnection conn, Object[] params) {
   username = (String) params[0];
   // 登入时将连接ID和连接信息形成对应关系并存入在线列表
   String link_id = conn.getClient().getId();
   onLineClient.put(username, conn);
   // 为用户列表共享对象添加属性
   // 创建用户列表共享对象
   listSO = getSharedObject(appScope, "listSO", false);
   // 创建用户聊天内容共享对象
   msgSO = getSharedObject(appScope, "msgSO", false);
   listSO.setAttribute(link_id, username);
   return true;
}

// 广播消息
public void broadcastUserMsg(String msg) {
   // 公聊
   // 刷新共享对象属性
   msgSO.setAttribute("msg", msg);
}

// 私聊信息
public void msgFromPrivate(String msg, String from, String to) {
   IServiceCapableConnection fc = (IServiceCapableConnection) onLineClient
     .get(from);
   IServiceCapableConnection tc = (IServiceCapableConnection) onLineClient
     .get(to);
   fc.invoke("showMsgByPrivate", new Object[] { msg });
   tc.invoke("showMsgByPrivate", new Object[] { msg });
}

// 用户断开连接的时候触发
public void appDisconnect(IConnection conn) {
   String dis_link_id = conn.getClient().getId();
   String user = (String) listSO.getAttribute(dis_link_id);
   // 根据ID删除对应在线纪录
   onLineClient.remove(user);
   // 删除用户列表共享对象的对应属性
   listSO.removeAttribute(dis_link_id);
}
}

  客户端代码:

  videoChat.as

package
{
import fl.controls.Button;
import fl.controls.List;
import fl.controls.TextArea;
import fl.controls.TextInput;
import fl.data.DataProvider;
import fl.managers.StyleManager;
import flash.display.Sprite;
import flash.events.AsyncErrorEvent;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.events.NetStatusEvent;
import flash.events.SecurityErrorEvent;
import flash.events.SyncEvent;
import flash.media.Camera;
import flash.media.Microphone;
import flash.media.Video;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.net.SharedObject;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.ui.Keyboard;

/**
* ... Red5 视频聊天 ...
* @author Jerry
*/
public class videoChat extends Sprite {
   //属性
   private var IP:String;
   private var redPath:String;
   private var nc:NetConnection;
   private var ns:NetStream;
   private var ns2:NetStream;
   private var cam:Camera;
   private var mic:Microphone;
   private var listSO:SharedObject;
   private var msgSO:SharedObject;
   private var userArr:Array;
   private var sendMsg:String;
   private var now:Date;
   private var userIDObj:Object;
 
   //构造函数
   public function videoChat() {
    _init();       //初始化
    _setComponentStyle();    //设置组件样式
    _startConnect();     //开始连接服务器
   }
 
   //初始化
   private function _init() {
    IP = "192.168.0.10";
    redPath = "rtmp://" + IP + "/videoChat";
    nc = new NetConnection();
    from.text = "guest" + int(Math.random() * 1000);
    to.text = "所有人";
    now = new Date();
   }
 
   //设置组件样式
   private function _setComponentStyle() {
    var myTF:TextFormat = new TextFormat();
    myTF.size = 12;
    myTF.font = "雅黑宋体";
    StyleManager.setStyle("textFormat", myTF);
   }
 
   //开始连接
   private function _startConnect() {
    nc.addEventListener(NetStatusEvent.NET_STATUS, _statusHandler);
    nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, _securityHandler);
    nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, _asyncHandler);
    nc.connect(redPath, from.text);
    nc.client = this;
   }
 
   //状态监听
   private function _statusHandler(evt:NetStatusEvent) {
    if (evt.info.code == "NetConnection.Connect.Success") {
     chatCon.text += "连接成功!\n";
     _scrollToEnd();
     _publishVideo();     //发布自己的视频
     _setListSO();      //创建用户列表共享对象
     _setMsgSO();      //创建发言信息共享对象
     sendBtn.addEventListener(MouseEvent.CLICK, _sendBtnByClick);   //单击发送信息
     stage.addEventListener(KeyboardEvent.KEY_DOWN, _sendBtnByKey);     //回车发送信息
    }
    if (evt.info.code == "NetConnection.Connect.Failed") {
     chatCon.text += "连接失败!\n";
     _scrollToEnd();
    }
    if (evt.info.code == "NetConnection.Connect.Closed") {
     chatCon.text += "连接关闭!\n";
     _scrollToEnd();
    }
   }
 
   //安全性监听
   private function _securityHandler(evt:SecurityError) {
    chatCon.text += "安全性错误!\n";
    _scrollToEnd();
   }
 
   //异步错误
   private function _asyncHandler(evt:AsyncErrorEvent) {
    chatCon.text += "异步错误!\n";
    _scrollToEnd();
   }
 
   //发布自己的视频
   private function _publishVideo() {
    ns = new NetStream(nc);
    cam = Camera.getCamera();
    mic = Microphone.getMicrophone();
    liveVideo.attachCamera(cam);
    ns.client = this;
    ns.addEventListener(NetStatusEvent.NET_STATUS, _statusHandler);
    ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, _asyncHandler);
    ns.attachCamera(cam);
    ns.attachAudio(mic);
    ns.publish(from.text, "live");
    whoseVideo.text = from.text + "的视频";
   }
 
   //创建用户列表共享对象
   private function _setListSO() {
    listSO = SharedObject.getRemote("listSO", nc.uri, false);
    listSO.connect(nc);
    listSO.addEventListener(SyncEvent.SYNC, _listSOSyncHandler);
   }
 
   //创建发言信息共享对象
   private function _setMsgSO() {
    msgSO = SharedObject.getRemote("msgSO", nc.uri, false);
    msgSO.addEventListener(SyncEvent.SYNC, _msgSOSyncHandler);
    msgSO.connect(nc);
   }
 
   //用户列表共享对象被更新之后事件
   private function _listSOSyncHandler(evt:SyncEvent) {
    _showUserList();     //更新用户列表
    //用户列表添加鼠标事件
    userList.addEventListener(MouseEvent.CLICK, _updateChatTo);
    userList.addEventListener(MouseEvent.DOUBLE_CLICK, _updateVideoShow);
   }
 
   //发言信息共享对象被更新之后事件
   private function _msgSOSyncHandler(evt:SyncEvent) {
    //更新聊天内容
    for (var i in msgSO.data) {
     chatCon.htmlText += msgSO.data[i];
    }
   }
 
   //更新用户列表
   private function _showUserList() {
    userArr = new Array();
    //用户数组更新
    for (var tmp in listSO.data) {
     userArr.push(listSO.data[tmp]);
    }
  
  
    //添加DataProvider
    var tmpDP:DataProvider = new DataProvider();
    for (var i = 0; i < userArr.length; i++ ) {
     tmpDP.addItem( { label:userArr[i] } );
    }
    //名称排序
    tmpDP.sortOn("label");
    //在用户列表顶端加一个“所有人”
    tmpDP.addItemAt( { label:"所有人" }, 0);
    //将数组添加到列表中显示出来
    userList.dataProvider = tmpDP;
   }
 
   //更新聊天对象
   private function _updateChatTo(evt:MouseEvent) {
    to.text = userList.selectedItem.label;
   }
 
   //更新视频显示和视频文本显示
   private function _updateVideoShow(evt:MouseEvent) {
    ns2 = new NetStream(nc);
    if (from.text == to.text) {
     //显示我的视频
     ns2.close();
     liveVideo.clear();
     whoseVideo.text = "我的视频";
     liveVideo.attachCamera(cam);
    }
    else {
     //显示其他人的视频
     whoseVideo.text = to.text + "的视频";
     ns2.client = this;
     ns2.addEventListener(NetStatusEvent.NET_STATUS, _statusHandler);
     ns2.addEventListener(AsyncErrorEvent.ASYNC_ERROR, _asyncHandler);
     liveVideo.attachNetStream(ns2);
     ns2.play(to.text);
    }
   }
 
   //单击发送信息
   private function _sendBtnByClick(evt:MouseEvent) {
    _sendMsg();
   }
 
   //回车发送信息
   private function _sendBtnByKey(evt:KeyboardEvent) {
    if (evt.keyCode == Keyboard.ENTER) {
     _sendMsg();
    }
   }
 
 
   //发送信息处理方法
   private function _sendMsg() {
    sendMsg="<font color='#ff0000'>" + from.text + "</font>" + " 对 " + "<font color='#ff0000'>" + to.text + "</font>" + " 说 " + "(" + "<font color='#0000ff'>" + now.getHours() + ":" + (now.getMinutes() < 10?"0" + now.getMinutes():now.getMinutes()) + ":" + (now.getSeconds() < 10?"0" + now.getSeconds():now.getSeconds()) + "</font>" + ")" + ":" +"\t" + msgInput.text + "\n";
  
    if (from.text == to.text) {
     //禁止对自己发言
     chatCon.text += "对不起,您不能对自己发言!";
     _scrollToEnd();
    }
    else if(msgInput.text==""){
     //发言不能为空
     chatCon.text += "请在下面的文本框中输入发言内容!";
     _scrollToEnd();
    }
    else if (to.text == "所有人") {
     //调用服务端广播方法
     nc.call("broadcastUserMsg", null, sendMsg);
     msgInput.text = "";
    }
    else {
     //私聊
     nc.call("msgFromPrivate", null, sendMsg, from.text, to.text);
     msgInput.text = "";
    }
   }
 
   //将滚动条滚动到最底端
   private function _scrollToEnd() {
    chatCon.verticalScrollPosition = chatCon.maxVerticalScrollPosition;
   }
 
   //私聊方法(被服务端调用)
   public function showMsgByPrivate(_msg:String) {
    chatCon.htmlText += _msg;
    _scrollToEnd();
   }
}

}

注释写得还算详细,我想大部分人应该都能看得懂吧,实在不懂得话就多看看Red5的官方API文档。

  在这里需要讲一下制作中的一个小插曲。

  在FMS中我的共享对象创建代码是写在服务器开启的方法中的,本以为在Red5中照此方式也可行,但是问题出来了,Red5的共享对象机制和FMS还是有一点点区别的,Red5的共享对象的机制是这样的,创建共享对象之后,有客户端连接之后断开连接的话,该共享对象会自动销毁,再次有客户端连接的时候服务器会自动生成一个客户端的共享对象(注意:这里强调是“客户端的”),而因为之前的客户端注册的事件针对的对象是被销毁的服务端共享对象,所以就发生了一个,用其他人的话说就是“unexpected problems ”。

  在我的测试中,这个问题很明显的被暴露了出来。

  最开始,我将创建共享对象的代码写在了服务器开始运行的方法里面,然后就发生了一个很奇怪的现象:当最开始有一个客户端连接又断开连接之后,再次登录,用户列表就只显示“所有人”(用户列表部分使用了共享对象)。而另外一种情况即时,只要保证有一个客户端始终连接着服务器就不会出现这样的问题。当时脑袋里想到的就是,很有可能服务端的SharedObject被销毁了。查了API没有找到可以检测共享对象的,所以没办法验证自己的猜测,所以只好放弃,改用Google。Google了一下,发现了一片文章,当然,还是英文的。还好,自己的英文水平还足以理解文章的内容,最终也是验证了自己的猜测。(PS:貌似使用房间创建的方法并不会出现这样的问题,因为没有做这个测试,所以也不知道什么情况,大家可以在我的代码的基础上修改一下,最好把结果也告诉我,本人也是比较懒的程序员。)

  源代码在这里放出,至于打包的源代码,因为百度不提供上传,我就没办法了,不过有想要的可以留下E-mail地址,有时间我会给你发过去的。多多共享,大家才能一起进步嘛!呵呵!

  还有,大家也可以到“ActionScript天地会”论坛和“Open Red5 ”论坛去下载,我在那里都发了帖子。

原文地址:http://hi.baidu.com/cosmos53076/blog/item/84089e51985f32878d543018.html
分享到:
评论

相关推荐

    Red5服务器如何调用Flash客户端的方法

    在IT行业中,尤其是在流媒体应用开发中,Red5服务器和Flash客户端的交互是常见的技术需求。Red5是一个开源的流媒体服务器,它支持多种协议,如RTMP(Real-Time Messaging Protocol),可以用来实时传输音频、视频等...

    red5流媒体服务器

    - **Flex或ActionScript**:使用Flash IDE或命令行工具构建客户端应用,与Red5服务器进行交互。 - **Java**:编写Server端的Java应用程序,实现特定功能,如自定义流处理器或广播服务。 - **WebRTC**:结合WebRTC...

    RED5流媒体服务器

    RED5流媒体服务器是一款开源的Java技术实现的流媒体服务器,它支持实时传输协议(RTMP)、RTMFP(Adobe的P2P协议)、HLS(High-Level Streaming)等多种流媒体协议,广泛应用于在线视频直播、点播服务。在本教程中,我们将...

    red5与flash聊天代码

    总的来说,Red5与Flash结合实现聊天功能,主要涉及Red5服务器的配置和应用开发,以及Flash客户端的ActionScript编程。开发者需要对网络通信、流媒体处理以及Flash ActionScript有深入理解,才能构建出稳定、高效的...

    RED5流媒体服务器(解压直接运行即可)

    RED5流媒体服务器是一款强大的基于Java开发的开源流媒体服务器,专为支持基于Flash的流媒体服务而设计。它的出现使得开发者和企业能够构建自定义的流媒体解决方案,包括视频直播、点播、录制和回放等功能。RED5提供...

    利用red5和ffmpeg搭建rtmp流媒体服务器

    Red5是一个开源的RTMP服务器,支持Flash媒体服务器的绝大部分功能。它适用于Java环境,需要先安装Java Development Kit(JDK)。 - 安装JDK:首先下载并安装JDK,然后设置JAVA_HOME环境变量指向JDK的安装目录,例如...

    red5流媒体服务器一个正常的demo

    4. **客户端播放**:学习如何使用Flash或HTML5播放器播放由Red5服务器提供的流媒体内容。 5. **互动功能**:了解如何实现聊天、投票等互动功能,这通常涉及服务器端和客户端的编程。 6. **记录与回放**:理解Red5的...

    Red5是一个开源的Flash服务器代码

    Red5是一款基于Java开发的开源Flash服务器,它为开发者提供了实时流媒体和交互性应用程序的服务。这个技术的主要目的是为了支持Adobe Flash Player以及其他可以与Flash Media Server(FMS)交互的客户端,提供类似的...

    类似FMS的RED5开源FLASH流媒体服务器源码

    3. **互动性**:RED5支持双向通信,这意味着用户不仅可以观看流媒体内容,还可以通过Flash Player与服务器交互,实现聊天室、投票等互动功能。 4. **适应性流媒体**:RED5可以根据网络条件动态调整流媒体质量,提供...

    Red5_Flash服务器研究.pdf

    ### Red5 Flash 服务器关键技术与应用 #### 一、引言 随着富互联网应用(RIA)的兴起,Flash/Flex技术因其强大的表现力、广泛的插件支持以及跨浏览器能力而备受开发人员青睐。在此背景下,对Flash服务器的研究显得...

    基于 Red5 的流媒体服务器的搭建和应用

    **Red5**是一款基于Java开发的开源免费Flash流媒体服务器。它利用Java语言及一系列强大开源框架构建而成,为企业的各类应用提供了坚实的基础。Red5支持多种流媒体协议,包括RTMP、RTMPT、RTMPS以及RTMPE,能够实现...

    red5chatv2.1 red5建的一个FLASH视频聊天会议例子

    【描述】中提到的"red5chatv2.1 red5建的一个FLASH视频聊天会议例子"表明这是一个使用Adobe Flash技术实现的客户端界面,与RED5服务器进行交互,用于视频聊天和会议的示例项目。"有JAVA和FLASH源码"意味着开发者可以...

    red5-rtsp视频服务器

    Red5 RTSP视频服务器是一款开源的流媒体服务器软件,它为开发者提供了构建实时通信系统的能力,特别是对于处理视频流有着显著的优势。RTSP(Real-Time Streaming Protocol)是一种网络协议,常用于控制音视频数据的...

    JAVA-RED5.rar_flash 服务器_java 网络会议_red5_red5 java _视频会议

    Java RED5是一款开源的Flash流媒体服务器,它允许开发者创建实时的、交互式的网络应用程序,如视频会议系统。RED5以其强大的功能和灵活性在Java社区中受到广泛关注,尤其是在需要处理实时音视频流的场景下。 RED5的...

    red5入门详细教程

    2. ActionScript 3.0接口:在Flash中,使用ActionScript 3.0与Red5服务器进行交互,包括连接服务器、创建流、发布和播放流等操作。熟悉AS3的基本语法和Red5相关的API是开发的关键。 三、Flash多媒体应用 1. 视频...

    本项目是由springboot构建的red5流媒体服务器 服务添加了hls支持http请求支持

    本项目是由springboot构建的red5流媒体服务器。服务添加了hls支持http请求支持。red5_hls是对red5的1.1.1版本进行springboot整合,整合后直接使用springboot进行启动和管理。打jar包运行。目前通过实时推流测试。该...

    red5入门,tomcat+red5+myeclipse集成,原创禁止转载

    了解了基础的集成后,你可以进一步学习Red5的API和特性,如如何处理流、如何实现录制和播放、如何与其他服务交互等。同时,通过阅读Red5的源码和参与社区讨论,可以深入理解其工作原理,提升开发能力。 六、注意...

    Red5流媒体服务器

    【Red5流媒体服务器】是基于Java开发的开源流媒体服务器,主要支持RTMP(实时消息传输协议)来实现Flash客户端与服务器之间的交互。Red5提供了视频、音频流的传输,以及Remote Shared Object等功能,与Adobe的FMS...

    red5-server,RED5服务器核心.zip

    Red5服务器是一个基于Java开发的开源流媒体服务器,它的出现为开发者提供了一个强大的工具来处理实时数据通信,尤其是在Flash内容的交互方面。ReD5的名字来源于"Red"代表开源(Open Source)和"5"代表Flash Player的...

    red5把flex与java交互的例子

    Red5是一款开源的Java流媒体服务器,它支持实时流传输协议(RTMP)、RTMPT、RTMPE、RTMPF、RTMPS等,使得开发者可以构建丰富的互动媒体...通过学习和实践使用Red5,我们可以创建出更富交互性、更具吸引力的Web应用。

Global site tag (gtag.js) - Google Analytics