Java 基於UDP 實現單播、組播、廣播 Socket 程式設計

言曌發表於2018-04-02

UDP資訊傳遞的方式

單播(unicast):

是指封包在計算機網路的傳輸中,目的地址為單一目標的一種傳輸方式。它是現今網路應用最為廣泛,通常所使用的網路協議或服務大多采用單播傳輸,例如一切基於TCP的協議。

 

組播(multicast):

也叫多播, 多點廣播或群播。 指把資訊同時傳遞給一組目的地址。它使用策略是最高效的,因為訊息在每條網路鏈路上只需傳遞一次,而且只有在鏈路分叉的時候,訊息才會被複制。

多播組通過 D 類 IP 地址和標準 UDP 埠號指定。D 類 IP 地址在 224.0.0.0 和 239.255.255.255 的範圍內(包括兩者)。地址 224.0.0.0 被保留,不應使用。

 

廣播(broadcast):

是指封包在計算機網路中傳輸時,目的地址為網路中所有裝置的一種傳輸方式。實際上,這裡所說的“所有裝置”也是限定在一個範圍之中,稱為“廣播域”。

 

 

詳細介紹(來自維基百科)

單播:

每次只有兩個實體相互通訊,傳送端和接收端都是唯一確定的。

在IPv4網路中,0.0.0.0到223.255.255.255屬於單播地址。

你對小月月喊“小月月”,那麼只有小月月回過頭來答應你。

 

組播:

“組播”這個詞通常用來指代IP組播。IP組播是一種通過使用一個組播地址將資料在同一時間以高效的方式發往處於TCP/IP網路上的多個接收者的協議。此外,它還常用來與RTP等音視訊協議相結合。

 

網際網路架構師戴夫·克拉克是這樣描述IP組播的:“你把資料包從一頭放進去,網路就會試圖將它們傳遞到想要得到它們的人那裡。”

 

組播報文的目的地址使用D類IP地址, D類地址不能出現在IP報文的源IP地址欄位。

 

你在大街上大喊一聲“美女”, 會有一群女性回頭看你。

 

組播地址(參考 iana)

組播組可以是永久的也可以是臨時的。組播組地址中,有一部分由官方分配的,稱為永久組播組。永久組播組保持不變的是它的ip地址,組中的成員構成可以發生變化。永久組播組中成員的數量都可以是任意的,甚至可以為零。那些沒有保留下來供永久組播組使用的ip組播地址,可以被臨時組播組利用。

 

  • 224.0.0.0~224.0.0.255為預留的組播地址(永久組地址),地址224.0.0.0保留不做分配,其它地址供路由協議使用;
  • 224.0.1.0~224.0.1.255是公用組播地址,Internetwork Control Block;
  • 224.0.2.0~238.255.255.255為使用者可用的組播地址(臨時組地址),全網範圍內有效;
  • 239.0.0.0~239.255.255.255為本地管理組播地址,僅在特定的本地範圍內有效。

永久的組播地址:

  • 224.0.0.0 基準地址(保留)
  • 224.0.0.1 所有主機的地址 (包括所有路由器地址)
  • 224.0.0.2 所有組播路由器的地址
  • 224.0.0.3 不分配
  • 224.0.0.4 dvmrp路由器
  • 224.0.0.5 所有ospf路由器
  • 224.0.0.6 ospf DR/BDR
  • 224.0.0.7 st路由器
  • 224.0.0.8 st主機
  • 224.0.0.9 rip-2路由器
  • 224.0.0.10 Eigrp路由器
  • 224.0.0.11 活動代理
  • 224.0.0.12 dhcp 伺服器/中繼代理
  • 224.0.0.13 所有pim路由器
  • 224.0.0.14 rsvp封裝
  • 224.0.0.15 所有cbt路由器
  • 224.0.0.16 指定sbm
  • 224.0.0.17 所有sbms
  • 224.0.0.18 vrrp

 

乙太網傳輸單播ip報文的時候,目的mac地址使用的是接收者的mac地址。但是在傳輸組播報文時,傳輸目的不再是一個具體的接收者,而是一個成員不確定的組,所以使用的是組播mac地址。組播mac地址是和組播ip地址對應的。iana(internet assigned number authority)規定,組播mac地址的高24bit為0x01005e,mac 地址的低23bit為組播ip地址的低23bit。

 

由於ip組播地址的後28位中只有23位被對映到mac地址,這樣就會有32個ip組播地址對映到同一mac地址上。

 

廣播:

並非所有的計算機網路都支援廣播,例如X.25網路和幀中繼都不支援廣播,而且也沒有在“整個網際網路範圍中”的廣播。IPv6亦不支援廣播,廣播相應的功能由組播代替。

 

通常,廣播都是限制在區域網中的,比如乙太網或令牌環網路。因為廣播在區域網中造成的影響遠比在廣域網中小得多。

 

乙太網和IPv4網都用全1的地址表示廣播,分別是ff:ff:ff:ff:ff:ff和255.255.255.255。
令牌環網路使用IEEE 802.2控制域中的一個特殊值來表示廣播。

 

你在公司大喊一聲“放假了”, 全部同事都會響應,大叫爽死了。

 

 

Java 基於 UDP 的 Socket程式設計

單播:

ChatDemo.java

  1. package udp;
  2. import java.io.BufferedReader;
  3. import java.io.IOException;
  4. import java.io.InputStreamReader;
  5. import java.net.DatagramPacket;
  6. import java.net.DatagramSocket;
  7. import java.net.InetAddress;
  8. import java.net.SocketException;
  9. /**
  10.  *
  11.  *
  12.  * 編寫一個聊天的工具
  13.  * 有收資料部分,和發資料部分
  14.  * 這兩個不部分同時執行
  15.  * 就需要多執行緒技術
  16.  * 一個執行緒控制收,一個執行緒控制發
  17.  *
  18.  * 因為收和發動作是不一致的,所以要定義兩個方法
  19.  * 而且這兩個方法要封裝到不同的類中
  20.  *
  21.  * @author 言曌
  22.  * @date 2017/12/6 下午8:25
  23.  */
  24. class Send implements Runnable {
  25.     private DatagramSocket socket;
  26.     public Send(DatagramSocket socket) {
  27.         this.socket = socket;
  28.     }
  29.     @Override
  30.     public void run() {
  31.         try {
  32.             BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
  33.             String line = null;
  34.             while((line = bufferedReader.readLine()) != null) {
  35.                 byte[] buff = line.getBytes();
  36.                 DatagramPacket packet = new DatagramPacket(buff,buff.length, InetAddress.getByName("192.168.168.106"),10001);
  37.                 socket.send(packet);
  38.                 if("bye".equals(line)) {
  39.                     break;
  40.                 }
  41.             }
  42.             socket.close();
  43.         } catch (IOException e) {
  44.             e.printStackTrace();
  45.         }
  46.     }
  47. }
  48. class Rece implements Runnable {
  49.     private  DatagramSocket socket;
  50.     public Rece(DatagramSocket socket) {
  51.         this.socket = socket;
  52.     }
  53.     @Override
  54.     public void run() {
  55.         try {
  56.             while(true) {
  57.                 byte[] buff = new byte[1024];
  58.                 DatagramPacket packet = new DatagramPacket(buff,buff.length);
  59.                 socket.receive(packet);
  60.                 String ip = packet.getAddress().getHostAddress();
  61.                 String data = new String(packet.getData(),0,packet.getLength());
  62.                 if("bye".equals(data)) {
  63.                     System.out.println(ip+"已經離開了");
  64.                     continue;
  65.                 }
  66.                 System.out.println(ip+"說"+data);
  67.             }
  68.         } catch (IOException e) {
  69.             e.printStackTrace();
  70.         }
  71.     }
  72. }
  73. public class ChatDemo {
  74.     /**
  75.      *  可以持續傳送到 192.168.168.106:10001
  76.      *  傳送到接受者的10001埠,接受者需要在10001埠接受
  77.      */
  78.     public static void main(String args[]) throws SocketException {
  79.         DatagramSocket sendSocket = new DatagramSocket();
  80.         DatagramSocket reveSocket = new DatagramSocket(10001);
  81.         new Thread(new Send(sendSocket)).start();
  82.         new Thread(new Rece(reveSocket)).start();
  83.     }
  84. }

 

說明

我這裡有兩臺電腦

一臺 ip:192.168.168.107  Mac

一臺電腦:192.168.168.106  Windows

上面的程式碼是 Mac 的程式碼,即 192.168.168.107 不斷給 192.168.168.106 的埠10001傳送資料

192.168.168.106 在 10001接收

 

效果圖

Mac 端的 IDEA 控制檯傳送資料並回車

 

Java 基於UDP 實現單播、組播、廣播 Socket 程式設計

 

Windows 端的 IDEA 控制檯接收資料

Java 基於UDP 實現單播、組播、廣播 Socket 程式設計

 

組播

ChatDemo2.java

  1. package udp;
  2. import java.io.BufferedReader;
  3. import java.io.IOException;
  4. import java.io.InputStreamReader;
  5. import java.net.*;
  6. /**
  7.  *
  8.  *
  9.  * 編寫一個聊天的工具
  10.  * 有收資料部分,和發資料部分
  11.  * 這兩個不部分同時執行
  12.  * 就需要多執行緒技術
  13.  * 一個執行緒控制收,一個執行緒控制發
  14.  *
  15.  * 因為收和發動作是不一致的,所以要定義兩個方法
  16.  * 而且這兩個方法要封裝到不同的類中
  17.  *
  18.  * @author 言曌
  19.  * @date 2017/12/6 下午8:25
  20.  */
  21. class Send2 implements Runnable {
  22.     private MulticastSocket socket;
  23.     public Send2(MulticastSocket socket) {
  24.         this.socket = socket;
  25.     }
  26.     @Override
  27.     public void run() {
  28.         try {
  29.             BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
  30.             InetAddress group = InetAddress.getByName("228.5.6.7");
  31.             socket.joinGroup(group);
  32.             String line = null;
  33.             while((line = reader.readLine())!= null) {
  34.                 byte[] buff = line.getBytes();
  35.                 DatagramPacket packet = new DatagramPacket(buff,buff.length,group,6789);
  36.                 socket.send(packet);
  37.                 if("bey".equals(line)) {
  38.                     break;
  39.                 }
  40.             }
  41.             socket.close();
  42.         } catch (IOException e) {
  43.             throw new RuntimeException("傳送端失敗");
  44.         }
  45.     }
  46. }
  47. class Rece2 implements Runnable {
  48.     private  MulticastSocket socket;
  49.     public Rece2(MulticastSocket socket) {
  50.         this.socket = socket;
  51.     }
  52.     @Override
  53.     public void run() {
  54.         try {
  55.             byte[] buff = new byte[1024];
  56.             InetAddress group = InetAddress.getByName("228.5.6.7");
  57.             socket.joinGroup(group);
  58.             while(true) {
  59.                 DatagramPacket packet = new DatagramPacket(buff,buff.length);
  60.                 socket.receive(packet);
  61.                 String data = new String(packet.getData(),0,packet.getLength());
  62.                 String ip = packet.getAddress().getHostAddress();
  63.                 if("bye".equals(data)) {
  64.                     System.out.println(ip+"離開了");
  65.                     continue;
  66.                 }
  67.                 System.out.println("ip:"+ip+" 說:"+data);
  68.             }
  69.         } catch (IOException e) {
  70.             throw new RuntimeException("接受端失敗");
  71.         }
  72.     }
  73. }
  74. public class ChatDemo2 {
  75.     public static void main(String args[]) throws IOException {
  76.         MulticastSocket sendSocket = new MulticastSocket();
  77.         MulticastSocket receSocket = new MulticastSocket(6789);
  78.         new Thread(new Send2(sendSocket)).start();
  79.         new Thread(new Rece2(receSocket)).start();
  80.     }
  81. }

 

說明

還是兩天機器,都執行上面的程式碼。都加入一個 ip 為 228.5.6.7 的組,在 6789 埠接受發資料。

 

 

效果圖

Mac 端的 IDEA 控制檯

Java 基於UDP 實現單播、組播、廣播 Socket 程式設計

 

Windows 端的 IDEA 控制檯

Java 基於UDP 實現單播、組播、廣播 Socket 程式設計

 

 

廣播

ChatDemo3.java

  1. package udp;
  2. import java.io.BufferedReader;
  3. import java.io.IOException;
  4. import java.io.InputStreamReader;
  5. import java.net.DatagramPacket;
  6. import java.net.DatagramSocket;
  7. import java.net.InetAddress;
  8. import java.net.SocketException;
  9. /**
  10.  *
  11.  *
  12.  * 編寫一個聊天的工具
  13.  * 有收資料部分,和發資料部分
  14.  * 這兩個不部分同時執行
  15.  * 就需要多執行緒技術
  16.  * 一個執行緒控制收,一個執行緒控制發
  17.  *
  18.  * 因為收和發動作是不一致的,所以要定義兩個方法
  19.  * 而且這兩個方法要封裝到不同的類中
  20.  *
  21.  * @author 言曌
  22.  * @date 2017/12/6 下午8:25
  23.  */
  24. class Send3 implements Runnable {
  25.     private DatagramSocket socket;
  26.     public Send3(DatagramSocket socket) {
  27.         this.socket = socket;
  28.     }
  29.     @Override
  30.     public void run() {
  31.         try {
  32.             BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
  33.             String line = null;
  34.             while((line = bufferedReader.readLine()) != null) {
  35.                 byte[] buff = line.getBytes();
  36.                 DatagramPacket packet = new DatagramPacket(buff,buff.length, InetAddress.getByName("192.168.168.255"),10001);
  37.                 socket.send(packet);
  38.                 if("bye".equals(line)) {
  39.                     break;
  40.                 }
  41.             }
  42.             socket.close();
  43.         } catch (IOException e) {
  44.             e.printStackTrace();
  45.         }
  46.     }
  47. }
  48. class Rece3 implements Runnable {
  49.     private  DatagramSocket socket;
  50.     public Rece3(DatagramSocket socket) {
  51.         this.socket = socket;
  52.     }
  53.     @Override
  54.     public void run() {
  55.         try {
  56.             while(true) {
  57.                 byte[] buff = new byte[1024];
  58.                 DatagramPacket packet = new DatagramPacket(buff,buff.length);
  59.                 socket.receive(packet);
  60.                 String ip = packet.getAddress().getHostAddress();
  61.                 String data = new String(packet.getData(),0,packet.getLength());
  62.                 if("bye".equals(data)) {
  63.                     System.out.println(ip+"離開了");
  64.                 }
  65.                 System.out.println(ip+"說"+data);
  66.             }
  67.         } catch (IOException e) {
  68.             e.printStackTrace();
  69.         }
  70.     }
  71. }
  72. public class ChatDemo3 {
  73.     public static void main(String args[]) throws SocketException {
  74.         DatagramSocket sendSocket = new DatagramSocket();
  75.         DatagramSocket reveSocket = new DatagramSocket(10001);
  76.         new Thread(new Send3(sendSocket)).start();
  77.         new Thread(new Rece3(reveSocket)).start();
  78.     }
  79. }

 

說明

廣播比較好理解,我這裡的區域網網路地址是 192.168.168.0

所以 ip 為 192.168.168.1 - 192.168.168.254 是一個本區域網內的有效 ip 地址

192.168.168.255 被稱為廣播地址,只要給廣播地址發訊息,該區域網內的所有人都能收到。

 

執行結果

Mac 版 IDEA 的控制檯

Java 基於UDP 實現單播、組播、廣播 Socket 程式設計

 

Windows 版 IDEA 的控制檯

Java 基於UDP 實現單播、組播、廣播 Socket 程式設計

 

 

相關文章