基于Java组播技术到安卓的实战应用于讲解(一)

来源:互联网 发布:钉钉软件手机 编辑:程序博客网 时间:2024/05/16 08:06

一、IP组播技术的基础知识概述

IP组播技术的概念

IP组播(也称多址广播或多播)技术,是一种允许一台或多台主机(组播源)发送单一数据包到多台主机(一次的,同时的)的TCP/IP网络技术。组播作为一点对多点的通信,是节省网络带宽的有效方法之一。在网络音频/视频广播的应用中,当需要将一个节点的信号传送到多个节点时,无论是采用重复点对点通信方式,还是采用广播方式,都会严重浪费网络带宽,只有组播才是最好的选择。组播能使一个或多个组播源只把数据包发送给特定的组播组,而只有加入该组播组的主机才能接收到数据包。目前,IP组播技术被广泛应用在网络音频/视频广播、AOD/VOD、网络视频会议、多媒体远程教育、“push”技术(如股票行情等)和虚拟现实游戏等方面。

IP组播地址和组播组

IP组播通信必须依赖于IP组播地址,在IPv4中它是一个D类IP地址,范围从224.0.0.0到239.255.255.255,并被划分为局部链接组播地址、预留组播地址和管理权限组播地址三类。其中,局部链接组播地址范围在224.0.0.0~224.0.0.255,这是为路由协议和其它用途保留的地址,路由器并不转发属于此范围的IP包;预留组播地址为224.0.1.0~238.255.255.255,可用于全球范围(如Internet)或网络协议;管理权限组播地址为239.0.0.0~239.255.255.255,可供组织内部使用,类似于私有IP地址,不能用于Internet,可限制组播范围。

使用同一个IP组播地址接收组播数据包的所有主机构成了一个主机组,也称为组播组。一个组播组的成员是随时变动的,一台主机可以随时加入或离开组播组,组播组成员的数目和所在的地理位置也不受限制,一台主机也可以属于几个组播组。此外,不属于某一个组播组的主机也可以向该组播组发送数据包。

组播分布树

为了向所有接收主机传送组播数据,用组播分布树来描述IP组播在网络中传输的路径。组播分布树有两个基本类型:有源树和共享树。

有源树是以组播源作为有源树的根,有源树的分支形成通过网络到达接收主机的分布树,因为有源树以最短的路径贯穿网络,所以也常称为最短路径树(SPT).共享树以组播网中某些可选择的组播路由中的一个作为共享树的公共根,这个根被称为汇合点(RP)。共享树又可分为单向共享树和双向共享树。单向共享树指组播数据流必须经过共享树从根发送到组播接收机。双向共享树指组播数据流可以不经过共享树。

逆向路径转发

逆向路径转发(RPF)是组播路由协议中组播数据转发过程的基础,其工作机制是当组播信息通过有源树时,组播路由器检查到达的组播数据包的组播源地址,以确定该组播数据包所经过的接口是否在有源的分支上,如果在,则RPF检查成功,组播数据包被转发;如果RPF检查失败,则丢弃该组播数据包。

Internet组播主干(MBONE)网络

Internet组播主干(MBONE)网络是由一系列相互连接的子网主机和相互连接支持IP组播的路由器组成。它可以看成是一个架构在Internet物理网络上层的虚拟网,在该虚拟网中,组播源发出的组播信息流可直接在支持IP组播的路由器组之间传输,而在组播路由器组和非组播路由器组之间要通过点对点隧道技术进行传输。

二丶IP组播路由中的隧道传输机制(待研究)

组播中的隧道概念指将组播包再封装成一个IP数据包在不支持组播的互联网络中路由传输。最有名的组播隧道的例子就是MBONE(采用DVMRP协议)。在隧道的入口处进行数据包的封装,在隧道的出口处则进行拆封。在达到本地全IP组播配置传输机制上,隧道机制非常有用。三、利用IP组播实现视频传输的方法(待研究)

因为网上信息的交互性和互动性,使网络中的信息传输量日益剧增,网络传输的瓶颈问题是突出的。在多媒体应用中,视频传输带来的网络带宽问题更突出。当n个IP地址同时接收网络多媒体视频流时,设每个视频流所需传输带宽为1.5 Mbps,按现在网络结构,所需带宽为n×1.5 Mbps,同时会带来无法忍受的网络延时和抖动。现有的大部分网络多是使用TCP/IP点到点的协议构置,因此我们研究的重点是如何在现有网络条件下不作过多的改变来实现视频的传输,即IP组播解决方案要与现有网络兼容。

 多媒体视频流对数据可靠性要求不高,适当的数据丢失不会过多影响视频播出的实际效果。虽然多媒体视频流对网络传输延时和抖动比较敏感,而IP组播在网络中延时与抖动是很少的。所以用IP组播通信来传输IP视频信号是可行的

首先来明确下,在网络传输视频时候又什么样的具体要求.

因为多媒体信号是交互的、互动的,它对网络提出了以下的应用要求:

(1) 吞吐(throughtput)的要求:是指对高传输带宽、大存储缓冲带宽的要求和对流量的控制。

(2) 可靠性的要求:在这里对可靠性的要求不是重点。适当的数据丢失不会过多影响视频播出的实际效果。

(3) 网络延时要求:对网络延时、抖动要求较高,因为多媒体视频流对网络传输延时和抖动比较敏感。如传输的视频信号与音频信号必须同步等。


(目前在IP网上提供视频服务的方式主要有两种:)

(1)完全利用路由器的Multicast(多路广播组播)技术,不需另加服务器转发,但会增加路由器负担,有“ 广播风暴”危险,网络路由协议也需调整。

(2)利用软件和服务器,在整个IP宽带网上叠加一个处理媒体流的叠加网,由叠加网实现点到多点组播、媒体流路由和多点注入等功能。

目前采用视频服务方式一般都为方案(2)。具体地说就是:计算机配合专用软件组成服务器,实现实时控制。控制的目的是:对于多媒体视频服务器端,必须具有最大效率的发送机制,也就是说,系统能够最大限度地在最短时间内响应和满足从多媒体视频接收端送来的视频请求,一次完成指向需求用户所有地址的数据发送,计算机实时控制系统随时监控视频传输的质量,同时自动调整带宽等。当然传输方法的实现能与目前的网络设施兼容。该方案实施过程中,计算机(服务器)时刻监控着系统,达到尽可能好的广播质量和高效率,绝不发生如“广播风暴”等危险。

用IP组播实现视频传输的系统由由4部分组成:即视频发送、视频转发、视频接收、视频控制。

视频发送:为预制视频或者称为实时视频,它可以是独立的计算机,也可以与第一级“视频转发”单元共用一台计算机。具体地说,先将视频按MPEG-1 编码技术进行实时视频压缩,此格式的数码率为1.5 Mbit/s,图像采用SIF格式(352×288),每秒30帧,2路立体声伴音。之所以按MPEG-1 编码技术进行实时视频压缩,因为通过它压缩后的视频信号质量令人满意,而数码率带宽相对比较窄,有利于IP组播(当然也可以用其他编码技术),然后将压缩后的信号送到视频转发端。信号从视频发送连接到视频转发是点到点的传输(此单元属于IPv4的通信方式)。

视频转发:主要是将从视频发送端发送来的视频信号,通过IP网络转发给视频接收端或下一级的视频转发端。它是IP组播传输视频信号的核心,视频信号用IP组播方式转发,即对一组特定IP地址(同一类请求的用户)进行数据传送。视频转发,由转发计算机(服务器)完成。

视频接收:是用户的多媒体终端。要求用户的多媒体终端设备必须能支持IP组播。

视频控制:主要功能是对转发站点进行控制,用来建立和管理转发站点上的IP组播数据组的传输。控制系统要最大限度地满足完成指向需求用户的数据发送,同时密切注意视频传输的质量。具体地说就是要尽可能多地为同类请求用户发送数据,但要在允许的带宽范围之内。这个带宽是通过计算机实时控制的,计算机实时控制系统随时监控视频传输的质量,自动调整带宽;同时对网络其他各项参数也实现实时监控。可见,视频控制实质上也就是计算机的实时控制。计算机实时控制的好坏直接决定了IP组播的效果。                                                                                           四丶IP组播技术在多点视频数据传输方面的优势

由于数字视频在网络传输时有着很大的数据吞吐量,如果使用端对端的IP单播技术进行数字视频的多点传送,首先,视频服务器必须始终保持在侦听状态,以了解每一个动态加入的客户端的服务请求,而套接字的侦听非常消耗系统的CPU资源,过于频繁的侦听容易造成系统的不稳定,同时还会影响视频传输的实时性,造成视频在网络中传输时出现频繁抖动,最终影响视频传输的服务质量(QoS);其次,视频服务器面对不同的客户端的同一视频服务请求,需要进行重复发送,N个客户端需要占用N倍的网络带宽资源,极大地浪费了网络带宽资源,如果控制不力,还会引起广播风暴,造成系统全面崩溃。

因此,在网络带宽环境能够无限满足视频传输需要的前提下,点对点传送和组播在性能上无本质差异,但是,这种理想状态基本上不会出现,否则除了研究网络带宽以外,其它的网络技术就失去了研究的基础和意义。我们设想在10BASE-T的局域网环境下,当只有2个或单个客户机提出视频服务请求时,二者无明显性能差异;当有3个至5个客户机提出视频服务请求时,二者之间的差异就比较显著,采用点对点传送方式的视频服务器明显已经力不从心,网络丢包和延迟比较严重,接收端视频明显滞后、不连续;当有5个以上的客户机提出视频服务请求时,就造成了广播风暴,系统处于崩溃的边缘。

由此可见,IP组播技术在多点视频数据传输方面具有很大的优势,当某个IP站点向网络中的多个IP站点发送同一视频数据时,IP组播技术可以减少不必要的重叠发送,与多次点对点的单播(Unicast)相比,减轻了系统和网络的负担,提高了CPU资源和网络带宽的利用率,极大地改善了视频数据传输的实时性。参与通信的各主机不论是源站点还是目的站点均使用同一程序,无客户机和服务器之分,从而具有对等性。

IP组播带入了许多新的应用并减少了网络的拥塞和服务器的负担。目前IP组播的应用范围还不够大,但它能够降低占用带宽,减轻服务器负荷,并能改善传送数据的质量,尤其适用于需要大量带宽的多媒体应用,如音频、视频等。这项新技术已成为当前网络界的热门话题,并将从根本上改变网络的体系结构。  五丶Android实战开发--通过组播技术实现聊天功能

读者通过上述的描述肯定已经对java组播技术的概念,优势,以及特性有了一个初步的了解.权衡利弊的去使用Java组播技术.那么下面就实战一次.通过代码来更加方便直观的接触Java组播技术.

我自己手写了一个组播工具类.里面包含了客户端服务端所需要的方法以及调用顺序.不足之处也请各位大牛不吝赐教.我自当虚心接受.

组播Utils(聊天版)                                                                                                                              

package com.wh.multicast;import java.io.IOException;import java.net.DatagramPacket;import java.net.InetAddress;import java.net.MulticastSocket;import android.content.Context;import android.net.wifi.WifiManager;import android.net.wifi.WifiManager.MulticastLock;import android.os.StrictMode;/** * @author wh * @version 1.0 启用后可传递信息 */public class MunlticastUtils {private final int SERVERINIT = 0;// 服务器初始方法private final int CLIENTINIT = 1;// 客户端初始化private static int PORT = 8888;// 端口号默认8888private static String MulticastHost = "239.245.245.245";// 组播地址也有默认值private Context context;private int ClientBufferSize = 1024;// 默认1Kprivate boolean ClientFlagisRead = true;// 客户端什么时候停止循环读的判断标记/** * 发送组播的socket * */private MulticastSocket ms = null;// wifi 设备锁private MulticastLock multicastLock = null;// 基本构造方法public MunlticastUtils(Context context, int orInit) {//this.context = context;if (SERVERINIT == orInit) {init();}// 初始化wifiinitWifi();}// 自设组地址端口构造方法public MunlticastUtils(Context context, String MulticastHost, int portNum,int orInit) {this.context = context;this.MulticastHost = MulticastHost;this.PORT = portNum;if (SERVERINIT == orInit) {init();}// 初始化wifiinitWifi();}// 初始化方法private void init() {StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects().penaltyLog().penaltyDeath().build());}// wifi初始化private void initWifi() {WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);multicastLock = wifiManager.createMulticastLock("multicast.test");multicastLock.acquire();}/***************************************** 发送方法 **************************************************//** * 局域网发送广播方法 */public void sendMulticastListener(String str) {DatagramPacket dp = null;byte[] byte_msg;// 存储用户输入InetAddress address;try {// 实例化组播器ms = new MulticastSocket();ms.setTimeToLive(4);byte_msg = str.getBytes();// 将用户信息转换成byte数组,组播技术的核心就是将数据转化为byte数组发送// 根据组播地址拿到组net地址address = InetAddress.getByName(MulticastHost);// 创建电报文dp = new DatagramPacket(byte_msg, byte_msg.length, address, PORT);// 发送电报文ms.send(dp);} catch (IOException e) {e.printStackTrace();// 捕获异常时候退出组ms.close();}}/***************************************** 接受报文 ******************************************************************/public void getMulticastListener(final getonMsgListen gml) {try {InetAddress address;// 初始化电报机ms = new MulticastSocket(PORT);// 根据组播地址拿到组net地址address = InetAddress.getByName(MulticastHost);// 想得到数据需要加组ms.joinGroup(address);// 创建工作线程new Thread(new Runnable() {// 收到的str信息String str_msg;// 用来接受电报文的缓冲区大小byte byte_msg[] = new byte[ClientBufferSize];// 空的电报袋子(比喻)DatagramPacket dp = new DatagramPacket(byte_msg,ClientBufferSize);@Overridepublic void run() {// 因为接受可能会不会很准确的就收到所以利用循环一直去找这个数据报while (ClientFlagisRead) {try {// 查询组内电表并收入byte_msg中ms.receive(dp);if (byte_msg.length != 0) {str_msg = new String(byte_msg, 0,dp.getLength());ClientFlagisRead = false;}} catch (IOException e) {e.printStackTrace();}}// 接口回调传出去gml.getMsg(ClientFlagisRead, str_msg);}}).start();} catch (IOException e) {e.printStackTrace();ms.close();}}/************************************************** 接口回调 **************************************************************/interface getonMsgListen {public void getMsg(boolean ishava, String str_msg);}}


将我们上面的这个代码作为你的聊天工具类,新建立一个工程为Multicast_UtilsText_S(服务端也就是发送端)代码附上Main中是                                                           package com.example.multicast_utilstext;

import com.wh.multicast.MunlticastUtils;import android.support.v7.app.ActionBarActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.EditText;public class MainActivity extends ActionBarActivity {private EditText main_edit;private Button main_btn;private MunlticastUtils mu;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mu = new MunlticastUtils(MainActivity.this, MunlticastUtils.SERVERINIT);init();}private void init() {main_edit = (EditText) findViewById(R.id.main_ed_userIn);main_btn = (Button) findViewById(R.id.main_btn_send);}public void onClick(View v) {// 获取用户输入内容String str_msg = main_edit.getText().toString().trim();// 发出mu.sendMulticastListener(str_msg);main_edit.setText(null);}}
XML文件代码

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.example.multicast_utilstext.MainActivity" >    <EditText        android:id="@+id/main_ed_userIn"        android:layout_width="match_parent"        android:layout_height="wrap_content" />    <Button        android:id="@+id/main_btn_send"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentRight="true"        android:layout_below="@+id/main_ed_userIn"        android:onClick="onClick"        android:text="send" /></RelativeLayout>

清单文件权限添加

 <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />                                              
然后我们在建立一个安卓工程名字为Multicast_UtilsText_C(即是接收端)Main函数代码(同理组播工具包必须在)

package com.example.multicast_utilstext_c;

import com.wh.multicast.MunlticastUtils;import com.wh.multicast.MunlticastUtils.getonMsgListen;import android.support.v7.app.ActionBarActivity;import android.util.Log;import android.widget.TextView;import android.widget.Toast;import android.os.Bundle;public class MainActivity extends ActionBarActivity {private MunlticastUtils mu;private TextView main_tv;private boolean flag = true;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);main_tv = (TextView) findViewById(R.id.main_tv_show);mu = new MunlticastUtils(MainActivity.this, MunlticastUtils.CLIENTINIT);mu.getMulticastListener(new getonMsgListen() {@Overridepublic void getMsg(boolean ishava, final String str_msg) {Log.i("TAG", str_msg);runOnUiThread(new Runnable() {@Overridepublic void run() {
//我这里用的是runOnUiThread当然你也可以Handle传值在到UI操作,但切记在回调函数中直接操作.因为它属于工作线程的子线程.切记!Toast.makeText(MainActivity.this, str_msg.trim(), 0).show();}});}});}}<strong></strong>
然后是XML中的代码.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingLeft="@dimen/activity_horizontal_margin"    android:paddingRight="@dimen/activity_horizontal_margin"    android:paddingTop="@dimen/activity_vertical_margin"    tools:context="com.example.multicast_utilstext_c.MainActivity" ><TextView     android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:id="@+id/main_tv_show"    android:textSize="23sp"    android:text="hello"/></RelativeLayout>

清单文件权限添加

 <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />    


这样就完成了,接收方可以是一台机子,可以是多台不影响.本身组播的特性就是1对多.当然我写的这个更像是统一下发内容.如果你想写一个聊天程序那么只需要在客户端写上同发送端一样的代码,发送端写上客户端代码即可.无论你处于哪种网络环境,WIFI,3G,4G,都是可以通的,但是唯一需要注意的是组播地址必须相同,因为必须保证是在同一个组内.UP主目前已经完成了聊天的测试,和小图片的测试.文件测试我修改了同样应用该技术的Jgroup工具集,因为本身JGroup工具在安卓下是不支持的.我已经修改的将它支持了安卓.可以传输上10MB的文件.通过测试22台机子一个服务器发送只需要5秒就全部拿到了发送的10MB文件.可以说这简直比P2P还屌.如果这个工具类就满足了你,那么就不必期待UP主下次更新的JGroup版传输大文件的帖子啦.当然UP主也是个菜菜嘛,过于较真UP主还是很心塞的.有什么意见或建议,留言留言~UP主会在收到留言的第一时间回复你的~~
0 0
原创粉丝点击