Java数据报编程之组播 选择自 keepeye 的 Blog

转载 2006年05月25日 11:13:00
 

在信息时代,网络技术应用已经很普通。其中很多应用都依赖于从一个主机向多个主机或者从多个主机向多个主机发送同一信息的能力,在Internet上分发的数目可能达数十万台,这些都需要更高的带宽,并且大大超出了单播的能力。一种能最大限度地利用现有带宽的重要技术是IP组播。


1.IP组播技术的概念

IP组播技术,是一种允许一台或多台主机(组播源)发送单一数据包到多台主机(一次的,同时的)的TCP/IP网络技术,是一点对多点的通信。在网络多媒体广播的应用中,当需要将一个节点的信号传送到多个节点时,无论是采用重复点对点通信方式,还是采用广播方式,都会严重浪费网络带宽,只有组播才是最好的选择。组播能使一个或多个组播源只把数据包发送给特定的组播组,而只有加入该组播组的主机才能接收到数据包。

2.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,可限制组播范围。

3.组播组

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

本文使用MulticastSocket类的实例编写组播应用,MulticastSocket类提供连接和离开组播等操作。

MultiSender类清单

package recmail.multiservice;

import java.net.*;
import java.io.IOException;

/**
 * 该类封装了MulticastSocket类,完成了MulticastSocket类实例的创建、初始化功能,
 * 并提供了一个发送数据的接口.
 */

public class MultiSender {
  public static final int MultiSender_Port=4099;
  private MulticastSocket road;
  private InetAddress ia;

  public MultiSender() {
    try {

      //组播地址
      ia = InetAddress.getByName("239.66.69.18");
      road = new MulticastSocket(MultiSender_Port);
      road.joinGroup(ia);
    }
    catch (UnknownHostException ex) {
    }
    catch (IOException ex1) {
    }
  }
  public InetAddress getInetAddress(){
    return ia;
  }
  public MulticastSocket getRoad(){
    return road;
  }
  public void send(byte[] b){
    DatagramPacket dp = new DatagramPacket(b, 0, b.length,
                                               ia, MultiSender.MultiSender_Port);
    try {
      road.send(dp);
    }
    catch (IOException ex) {
      ex.printStackTrace();
    }
  }
}

ImageServer类,使用上面的类发送文件数据.

package recmail.multiservice;
import java.io.*;
import javax.swing.Timer;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import java.io.FileFilter;
import java.io.FilenameFilter;

/**
 * 本类利用MultiSender类发送文件数据到一个组播组发送数据.
 */

public class ImageServer
    extends Thread implements ActionListener {
  Timer timer;
  BufferedImage image;
  ArrayList streamfragments;
  int counter = 0;
  byte[] imagebyte;
  ArrayList listener;
  MultiSender sender;

  public ImageServer(ArrayList f) {
    timer = new Timer(50, this);
    timer.addActionListener(this);
    listener = new ArrayList();
    streamfragments = f;
    sender = new MultiSender();
    timer.start();
  }

  public void addDataSwapListener(DataSwapListener dsl) {
    listener.add(dsl);
  }

  public void removeDataSwapListener(DataSwapListener dsl) {
    listener.remove(dsl);
  }

  private void processEvent() {
    for (int i = 0; i < this.listener.size(); i++) {
      DataSwapEvent dse = new DataSwapEvent();
      ( (DataSwapListener)this.listener.get(i)).OnDataSendFinished(this, dse);
    }
  }

  public void actionPerformed(ActionEvent e) {
    DataPacket dp = new DataPacket(streamfragments.get(counter).toString());
    DataEntry de;
    try {
      ArrayList al = dp.getDataPackets();
      Thread.sleep(1000);
      System.out.println(streamfragments.get(counter).toString());
      for (int i = 0; i < al.size(); i++) {
        imagebyte = ( (DataEntry) al.get(i)).getByte(); //(byte[]) al.get(i);
        sender.send(imagebyte);
      }
      this.processEvent();
    }
    catch (Exception ex) {
      System.out.println(ex);
    }
    counter++;
    if (counter >= streamfragments.size())
      counter = 0;
  }

  public void run() {
    while (true) {
      try {
        this.sleep(20);
      }
      catch (InterruptedException ex) {
      }
    }
  }

  public static void main(String[] args) {
    String file[];
    ArrayList al = new ArrayList();
    String path = "E://mzip//"; 
    File f = new File(path);
    file = f.list();
    for (int i = 0; i < file.length; i++) {
      if (file[i].endsWith("jpg") || file[i].endsWith("bmp")) 
        al.add(path + file[i]);
    }
    ImageServer is = new ImageServer(al);
    is.start();
  }
}

package recmail.multiservice;

import java.net.*;
import java.io.*;
import java.awt.image.*;
/**
 * 该类封装了MulticastSocket类,完成了MulticastSocket类实例的创建、初始化功能,
 * 并提供一个接收数据的线程,在判断接收完毕后产生事件,更新UI显示.
 * 该类由testFrame使用.
 */
public class ImageShow
    extends DataSwapListenerAdapter
    implements Runnable {
  private InetAddress ia;
  private int port = 4099;
  private MulticastSocket road;
  DataSwapEvent dsevent;
  java.awt.image.BufferedImage bi;

  public ImageShow() {
    dsevent = new DataSwapEvent(this);
    try {
      ia = InetAddress.getByName("239.66.69.18");
      road = new MulticastSocket(port);
      road.joinGroup(ia);
    }
    catch (IOException ex) {
    }
  }

  public void run() {
    byte[] buffer = new byte[DataPacket.DataSwapSize];
    DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
    DataPacket dp = new DataPacket();
    while (true) {
      packet.setLength(buffer.length);
      System.out.println("wait .. ");
      try {
        road.receive(packet);
        dp.Add(packet.getData());
        if (dp.isFull()) {
          dsevent.setImage(dp.Gereratedata());
          this.processRecvFinishedEvent(dsevent);
          dp = new DataPacket();
        }
      }
      catch (IOException ex) {
        System.out.println(ex);
      }
    }
  }
}

接收端界面类:

package recmail.multiservice;

import javax.swing.*;
import java.awt.*;
import java.awt.image.*;

/**
 * 该类使用ImageShow更新显示的图象.
 */

public class testFrame
    extends JApplet
    implements DataSwapListener {
  private JPanel root;
  JLabel label;
  JImagePanel ip;
  java.awt.Image bi;

  public testFrame() {
    initmain();
  }

  public void init() {
    initmain();
    this.setContentPane(root);
    ImageShow is = new ImageShow();
    is.addDataSwapListener(this);
    Thread thread = new Thread(is, "test");
    thread.start();
  }

  public static void main(String[] args) {
    testFrame test = new testFrame();
    test.go(new JFrame());
    ImageShow is = new ImageShow();
    is.addDataSwapListener(test);
    Thread thread = new Thread(is, "test");
    thread.start();
  }

  public void go(JFrame frame) {
    frame.setContentPane(root);
    frame.setSize(300, 200);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.validate();
    frame.setVisible(true);
  }

  public void initmain() {
    root = new JPanel();
    //label = new JLabel();
    ip = new JImagePanel();
    root.setLayout(new BorderLayout(5, 5));
    root.add(ip, BorderLayout.CENTER);
  }

  public void setRefreshImage(java.awt.image.BufferedImage img) {
    this.bi = img;
    ip.setImage(bi);
  }

  public void paint(Graphics g) {
    super.paint(g);
  }

  public void paintComponents(Graphics g) {
    super.paintComponents(g);
    Graphics g1 = root.getGraphics();
    g1.drawImage(bi, 0, 0, this);
  }

  public void OnDataSendFinished(Object s, DataSwapEvent e) {

  }

  public void OnDataRecvFinished(Object s, DataSwapEvent e) {
    this.bi = e.getImage();
    ip.setImage(bi);
    System.out.println("recv Finished!");
  }
}

到此,这个多播程序编写完毕,通过这个程序可以看出在Java中进行组播编程有两个特点,一是使用Java的MulticastSocket类,二是使用组播地址配置MulticastSocket实例.

数据报编程的全部内容已结束,如果要改进,可以在两个方面进行,一个是改善传输的可靠性方面,一个是采用数据收发的异步方面,因为在J2SDK1.4中MulticastSocket类增加了方法getChannel().

linux发送组播数据报

我们还是以发送UDP的组播数据为例。其实发送一个UDP的组播数据报跟发送一个单播UDP数据报的差别并不大。     首先是在myudp_sendmsg函数中,如果发送接口的源地址没有确定,并且目的地...

Java 网络编程(六) 使用无连接的数据报(UDP)进行通信

使用无连接的数据报(UDP)进行通信 什么是Datagram?   数据报是网上传输的独立数据包,数据报是否能正确地到达目的地,到达的时间,顺序,内容的正确性均没有保障。     Java中使...

网络编程 ip数据报分析流程

  • 2011年09月08日 12:55
  • 252KB
  • 下载

【Linux网络编程】IP 数据报格式详解

IP 数据报首部 TCP/IP 协议定义了一个在因特网上传输的包,称为 IP 数据报 (IP Datagram)。这是一个与硬件无关的虚拟包,由首部和数据两部...

linux网络编程之TCP/IP基础(一):TCP/IP协议栈与数据报封装

一、ISO/OSI参考模型 OSI(open system interconnection)开放系统互联模型是由ISO(International Organization for Standardi...

Linux 网络编程——TCP 和 UDP 数据报格式详解

TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。 TCP 报文段的报头有 10 个必需的字段和 1 个可选字段...

三、Linux网络编程-TCP/IP基础(三)IP数据报格式、网际校验和、路由

一、IP数据报格式 (1)、IP头部的数据格式 版本  IP协议版本号,长度为4位,IPv4此字段值为4,IPv6此字段值为6 首部长度  以32位的字为单位,该字段长度为4...
  • tianttt
  • tianttt
  • 2015年05月01日 21:13
  • 529

linux网络编程之TCP/IP基础(一):TCP/IP协议栈与数据报封装

http://blog.csdn.NET/jnu_simba/article/details/8957242 一、ISO/OSI参考模型 OSI(open system i...

Linux下发送与接收组播数据(socket编程)

Sender.cpp #include #include #include #include #include #inc...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java数据报编程之组播 选择自 keepeye 的 Blog
举报原因:
原因补充:

(最多只允许输入30个字)