轉自其他網站
核心提示:在信息時代,網絡技術應用已經很普通。其中很多應用都依賴於從一個主機向多個主機或者從多個主機向多個主機發送同一信息的能力,在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().