转自其他网站
核心提示:在信息时代,网络技术应用已经很普通。其中很多应用都依赖于从一个主机向多个主机或者从多个主机向多个主机发送同一信息的能力,在Internet 上分发的数目可能达数十万台,这些都需要更高的带宽,并且大大超出了单播的能力。一种能最大限度地利用现有带宽的重
在信息时代,网络技术应用已经很普通。其中很多应用都依赖于从一个主机向多个主机或者从多个主机向多个主机发送同一信息的能力,在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 类清单
1. package recmail.multiservice;
2.
3. import java.net.*;
4. import java.io.IOException;
5.
6. /**
7. * 该类封装了MulticastSocket 类, 完成了MulticastSocket 类实例的创建、初始化功能,
8. * 并提供了一个发送数据的接口.
9. */
10.
11. public class MultiSender {
12. public static final int MultiSender_Port= 4099 ;
13. private MulticastSocket road;
14. private InetAddress ia;
15.
16. public MultiSender() {
17. try {
18.
19. // 组播地址
20. ia = InetAddress.getByName( "239.66.69.18" );
21. road = new MulticastSocket(MultiSender_Port);
22. road.joinGroup(ia);
23. }
24. catch (UnknownHostException ex) {
25. }
26. catch (IOException ex1) {
27. }
28. }
29. public InetAddress getInetAddress(){
30. return ia;
31. }
32. public MulticastSocket getRoad(){
33. return road;
34. }
35. public void send( byte [] b){
36. DatagramPacket dp = new DatagramPacket(b, 0 , b.length,
37. ia, MultiSender.MultiSender_Port);
38. try {
39. road.send(dp);
40. }
41. catch (IOException ex) {
42. ex.printStackTrace();
43. }
44. }
45. }
ImageServer 类, 使用上面的类发送文件数据.
1. package recmail.multiservice;
2. import java.io.*;
3. import javax.swing.Timer;
4. import java.awt.event.*;
5. import java.awt.image.*;
6. import java.util.*;
7. import java.io.FileFilter;
8. import java.io.FilenameFilter;
9.
10. /**
11. * 本类利用MultiSender 类发送文件数据到一个组播组发送数据.
12. */
13.
14. public class ImageServer
15. extends Thread implements ActionListener {
16. Timer timer;
17. BufferedImage image;
18. ArrayList streamfragments;
19. int counter = 0 ;
20. byte [] imagebyte;
21. ArrayList listener;
22. MultiSender sender;
23.
24. public ImageServer(ArrayList f) {
25. timer = new Timer( 50 , this );
26. timer.addActionListener( this );
27. listener = new ArrayList();
28. streamfragments = f;
29. sender = new MultiSender();
30. timer.start();
31. }
32.
33. public void addDataSwapListener(DataSwapListener dsl) {
34. listener.add(dsl);
35. }
36.
37. public void removeDataSwapListener(DataSwapListener dsl) {
38. listener.remove(dsl);
39. }
40.
41. private void processEvent() {
42. for ( int i = 0 ; i < this .listener.size(); i++) {
43. DataSwapEvent dse = new DataSwapEvent();
44. ( (DataSwapListener) this .listener.get(i)).OnDataSendFinished( this , dse);
45. }
46. }
47.
48. public void actionPerformed(ActionEvent e) {
49. DataPacket dp = new DataPacket(streamfragments.get(counter).toString());
50. DataEntry de;
51. try {
52. ArrayList al = dp.getDataPackets();
53. Thread.sleep( 1000 );
54. System.out.println(streamfragments.get(counter).toString());
55. for ( int i = 0 ; i < al.size(); i++) {
56. imagebyte = ( (DataEntry) al.get(i)).getByte(); //(byte[]) al.get(i);
57. sender.send(imagebyte);
58. }
59. this .processEvent();
60. }
61. catch (Exception ex) {
62. System.out.println(ex);
63. }
64. counter++;
65. if (counter >= streamfragments.size())
66. counter = 0 ;
67. }
68.
69. public void run() {
70. while ( true ) {
71. try {
72. this .sleep( 20 );
73. }
74. catch (InterruptedException ex) {
75. }
76. }
77. }
78.
79. public static void main(String[] args) {
80. String file[];
81. ArrayList al = new ArrayList();
82. String path = "E://mzip//" ;
83. File f = new File(path);
84. file = f.list();
85. for ( int i = 0 ; i < file.length; i++) {
86. if (file[i].endsWith( "jpg" ) || file[i].endsWith( "bmp" ))
87. al.add(path + file[i]);
88. }
89. ImageServer is = new ImageServer(al);
90. is.start();
91. }
92. }
1. package recmail.multiservice;
2.
3. import java.net.*;
4. import java.io.*;
5. import java.awt.image.*;
6. /**
7. * 该类封装了MulticastSocket 类, 完成了MulticastSocket 类实例的创建、初始化功能,
8. * 并提供一个接收数据的线程, 在判断接收完毕后产生事件, 更新UI 显示.
9. * 该类由testFrame 使用.
10. */
11. public class ImageShow
12. extends DataSwapListenerAdapter
13. implements Runnable {
14. private InetAddress ia;
15. private int port = 4099 ;
16. private MulticastSocket road;
17. DataSwapEvent dsevent;
18. java.awt.image.BufferedImage bi;
19.
20. public ImageShow() {
21. dsevent = new DataSwapEvent( this );
22. try {
23. ia = InetAddress.getByName( "239.66.69.18" );
24. road = new MulticastSocket(port);
25. road.joinGroup(ia);
26. }
27. catch (IOException ex) {
28. }
29. }
30.
31. public void run() {
32. byte [] buffer = new byte [DataPacket.DataSwapSize];
33. DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
34. DataPacket dp = new DataPacket();
35. while ( true ) {
36. packet.setLength(buffer.length);
37. System.out.println( "wait .. " );
38. try {
39. road.receive(packet);
40. dp.Add(packet.getData());
41. if (dp.isFull()) {
42. dsevent.setImage(dp.Gereratedata());
43. this .processRecvFinishedEvent(dsevent);
44. dp = new DataPacket();
45. }
46. }
47. catch (IOException ex) {
48. System.out.println(ex);
49. }
50. }
51. }
52. }
接收端界面类:
1. package recmail.multiservice;
2.
3. import javax.swing.*;
4. import java.awt.*;
5. import java.awt.image.*;
6.
7. /**
8. * 该类使用ImageShow 更新显示的图象.
9. */
10.
11. public class testFrame
12. extends JApplet
13. implements DataSwapListener {
14. private JPanel root;
15. JLabel label;
16. JImagePanel ip;
17. java.awt.Image bi;
18.
19. public testFrame() {
20. initmain();
21. }
22.
23. public void init() {
24. initmain();
25. this .setContentPane(root);
26. ImageShow is = new ImageShow();
27. is.addDataSwapListener( this );
28. Thread thread = new Thread(is, "test" );
29. thread.start();
30. }
31.
32. public static void main(String[] args) {
33. testFrame test = new testFrame();
34. test.go( new JFrame());
35. ImageShow is = new ImageShow();
36. is.addDataSwapListener(test);
37. Thread thread = new Thread(is, "test" );
38. thread.start();
39. }
40.
41. public void go(JFrame frame) {
42. frame.setContentPane(root);
43. frame.setSize( 300 , 200 );
44. frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
45. frame.validate();
46. frame.setVisible( true );
47. }
48.
49. public void initmain() {
50. root = new JPanel();
51. //label = new JLabel();
52. ip = new JImagePanel();
53. root.setLayout( new BorderLayout( 5 , 5 ));
54. root.add(ip, BorderLayout.CENTER);
55. }
56.
57. public void setRefreshImage(java.awt.image.BufferedImage img) {
58. this .bi = img;
59. ip.setImage(bi);
60. }
61.
62. public void paint(Graphics g) {
63. super .paint(g);
64. }
65.
66. public void paintComponents(Graphics g) {
67. super .paintComponents(g);
68. Graphics g1 = root.getGraphics();
69. g1.drawImage(bi, 0 , 0 , this );
70. }
71.
72. public void OnDataSendFinished(Object s, DataSwapEvent e) {
73.
74. }
75.
76. public void OnDataRecvFinished(Object s, DataSwapEvent e) {
77. this .bi = e.getImage();
78. ip.setImage(bi);
79. System.out.println( "recv Finished!" );
80. }
81. }
到此, 这个多播程序编写完毕, 通过这个程序可以看出在Java 中进行组播编程有两个特点, 一是使用Java 的MulticastSocket 类, 二是使用组播地址配置MulticastSocket 实例.
数据报编程的全部内容已结束, 如果要改进, 可以在两个方面进行, 一个是改善传输的可靠性方面, 一个是采用数据收发的异步方面, 因为在J2SDK1.4 中MulticastSocket 类增加了方法getChannel().