Java 基於UDP 實現單播、組播、廣播 Socket 程式設計
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
- package udp;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.net.DatagramPacket;
- import java.net.DatagramSocket;
- import java.net.InetAddress;
- import java.net.SocketException;
- /**
- *
- *
- * 編寫一個聊天的工具
- * 有收資料部分,和發資料部分
- * 這兩個不部分同時執行
- * 就需要多執行緒技術
- * 一個執行緒控制收,一個執行緒控制發
- *
- * 因為收和發動作是不一致的,所以要定義兩個方法
- * 而且這兩個方法要封裝到不同的類中
- *
- * @author 言曌
- * @date 2017/12/6 下午8:25
- */
- class Send implements Runnable {
- private DatagramSocket socket;
- public Send(DatagramSocket socket) {
- this.socket = socket;
- }
- @Override
- public void run() {
- try {
- BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
- String line = null;
- while((line = bufferedReader.readLine()) != null) {
- byte[] buff = line.getBytes();
- DatagramPacket packet = new DatagramPacket(buff,buff.length, InetAddress.getByName("192.168.168.106"),10001);
- socket.send(packet);
- if("bye".equals(line)) {
- break;
- }
- }
- socket.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- class Rece implements Runnable {
- private DatagramSocket socket;
- public Rece(DatagramSocket socket) {
- this.socket = socket;
- }
- @Override
- public void run() {
- try {
- while(true) {
- byte[] buff = new byte[1024];
- DatagramPacket packet = new DatagramPacket(buff,buff.length);
- socket.receive(packet);
- String ip = packet.getAddress().getHostAddress();
- String data = new String(packet.getData(),0,packet.getLength());
- if("bye".equals(data)) {
- System.out.println(ip+"已經離開了");
- continue;
- }
- System.out.println(ip+"說"+data);
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- public class ChatDemo {
- /**
- * 可以持續傳送到 192.168.168.106:10001
- * 傳送到接受者的10001埠,接受者需要在10001埠接受
- */
- public static void main(String args[]) throws SocketException {
- DatagramSocket sendSocket = new DatagramSocket();
- DatagramSocket reveSocket = new DatagramSocket(10001);
- new Thread(new Send(sendSocket)).start();
- new Thread(new Rece(reveSocket)).start();
- }
- }
說明
我這裡有兩臺電腦
一臺 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 控制檯傳送資料並回車
Windows 端的 IDEA 控制檯接收資料
組播
ChatDemo2.java
- package udp;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.net.*;
- /**
- *
- *
- * 編寫一個聊天的工具
- * 有收資料部分,和發資料部分
- * 這兩個不部分同時執行
- * 就需要多執行緒技術
- * 一個執行緒控制收,一個執行緒控制發
- *
- * 因為收和發動作是不一致的,所以要定義兩個方法
- * 而且這兩個方法要封裝到不同的類中
- *
- * @author 言曌
- * @date 2017/12/6 下午8:25
- */
- class Send2 implements Runnable {
- private MulticastSocket socket;
- public Send2(MulticastSocket socket) {
- this.socket = socket;
- }
- @Override
- public void run() {
- try {
- BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
- InetAddress group = InetAddress.getByName("228.5.6.7");
- socket.joinGroup(group);
- String line = null;
- while((line = reader.readLine())!= null) {
- byte[] buff = line.getBytes();
- DatagramPacket packet = new DatagramPacket(buff,buff.length,group,6789);
- socket.send(packet);
- if("bey".equals(line)) {
- break;
- }
- }
- socket.close();
- } catch (IOException e) {
- throw new RuntimeException("傳送端失敗");
- }
- }
- }
- class Rece2 implements Runnable {
- private MulticastSocket socket;
- public Rece2(MulticastSocket socket) {
- this.socket = socket;
- }
- @Override
- public void run() {
- try {
- byte[] buff = new byte[1024];
- InetAddress group = InetAddress.getByName("228.5.6.7");
- socket.joinGroup(group);
- while(true) {
- DatagramPacket packet = new DatagramPacket(buff,buff.length);
- socket.receive(packet);
- String data = new String(packet.getData(),0,packet.getLength());
- String ip = packet.getAddress().getHostAddress();
- if("bye".equals(data)) {
- System.out.println(ip+"離開了");
- continue;
- }
- System.out.println("ip:"+ip+" 說:"+data);
- }
- } catch (IOException e) {
- throw new RuntimeException("接受端失敗");
- }
- }
- }
- public class ChatDemo2 {
- public static void main(String args[]) throws IOException {
- MulticastSocket sendSocket = new MulticastSocket();
- MulticastSocket receSocket = new MulticastSocket(6789);
- new Thread(new Send2(sendSocket)).start();
- new Thread(new Rece2(receSocket)).start();
- }
- }
說明
還是兩天機器,都執行上面的程式碼。都加入一個 ip 為 228.5.6.7 的組,在 6789 埠接受發資料。
效果圖
Mac 端的 IDEA 控制檯
Windows 端的 IDEA 控制檯
廣播
ChatDemo3.java
- package udp;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.net.DatagramPacket;
- import java.net.DatagramSocket;
- import java.net.InetAddress;
- import java.net.SocketException;
- /**
- *
- *
- * 編寫一個聊天的工具
- * 有收資料部分,和發資料部分
- * 這兩個不部分同時執行
- * 就需要多執行緒技術
- * 一個執行緒控制收,一個執行緒控制發
- *
- * 因為收和發動作是不一致的,所以要定義兩個方法
- * 而且這兩個方法要封裝到不同的類中
- *
- * @author 言曌
- * @date 2017/12/6 下午8:25
- */
- class Send3 implements Runnable {
- private DatagramSocket socket;
- public Send3(DatagramSocket socket) {
- this.socket = socket;
- }
- @Override
- public void run() {
- try {
- BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
- String line = null;
- while((line = bufferedReader.readLine()) != null) {
- byte[] buff = line.getBytes();
- DatagramPacket packet = new DatagramPacket(buff,buff.length, InetAddress.getByName("192.168.168.255"),10001);
- socket.send(packet);
- if("bye".equals(line)) {
- break;
- }
- }
- socket.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- class Rece3 implements Runnable {
- private DatagramSocket socket;
- public Rece3(DatagramSocket socket) {
- this.socket = socket;
- }
- @Override
- public void run() {
- try {
- while(true) {
- byte[] buff = new byte[1024];
- DatagramPacket packet = new DatagramPacket(buff,buff.length);
- socket.receive(packet);
- String ip = packet.getAddress().getHostAddress();
- String data = new String(packet.getData(),0,packet.getLength());
- if("bye".equals(data)) {
- System.out.println(ip+"離開了");
- }
- System.out.println(ip+"說"+data);
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- public class ChatDemo3 {
- public static void main(String args[]) throws SocketException {
- DatagramSocket sendSocket = new DatagramSocket();
- DatagramSocket reveSocket = new DatagramSocket(10001);
- new Thread(new Send3(sendSocket)).start();
- new Thread(new Rece3(reveSocket)).start();
- }
- }
說明
廣播比較好理解,我這裡的區域網網路地址是 192.168.168.0
所以 ip 為 192.168.168.1 - 192.168.168.254 是一個本區域網內的有效 ip 地址
192.168.168.255 被稱為廣播地址,只要給廣播地址發訊息,該區域網內的所有人都能收到。
執行結果
Mac 版 IDEA 的控制檯
Windows 版 IDEA 的控制檯
相關文章
- 單播、多播(組播)和廣播的區別
- 組播和廣播的區別
- iOS下的UDP廣播iOSUDP
- java傳送接收組播(多播)資料包(UDP包)JavaUDP
- VC UDP接收 傳送 廣播UDP
- 使用 Laravel 廣播事件實現基於 Socket.io 的實時訊息通知Laravel事件
- 基於websocket的簡單廣播系統Web
- Netty 框架學習 —— UDP 廣播Netty框架UDP
- SOCKET實現廣播(BoardCast)的傳送和接收 (轉)AST
- C#實現任意源組播與特定源組播C#
- 廣播基礎使用
- IP組播網路程式設計程式設計
- ServerSocket實現簡單的廣播系統Server
- 一個基於UDP資料廣播的區域網路會議程式UDP
- 廣播接收器——接收系統廣播
- 廣播模式模式
- UDP介紹及UDP傳送端和接收端廣播程式碼UDP
- 小區廣播背景音樂IP網路廣播系統方案設計概要
- Java實現區域網內單播Java
- Android開機廣播和關機廣播Android
- 大學校園IP網路廣播-基於校園區域網的大學校園IP廣播方案設計指南
- 基於 Redis驅動的 Laravel 事件廣播RedisLaravel事件
- vlc的應用:用vlc做單播,組播及點播伺服器伺服器
- 用張量廣播機制實現神經網路反向傳播神經網路反向傳播
- node.js實現的簡單udp廣播伺服器和客戶端程式碼例項Node.jsUDP伺服器客戶端
- 小學校園IP網路廣播-基於校園區域網的小學IP數字廣播系統設計
- HCNP Routing&Switching之組播技術-組播基礎
- IP組播
- 組播地址
- Laravel 廣播入門,彈幕的實現Laravel
- Udp廣播的傳送與接收(C#+UdpClient) 上篇UDPC#client
- Udp廣播的傳送和接收(iOS + AsyncUdpSocket)下篇UDPiOS
- 基於 flex 的 order 實現 carousel 輪播圖Flex
- 廣播丟資料
- NumPy之:理解廣播
- IP多路廣播 (轉)
- Socket程式設計入門(基於Java實現)程式設計Java
- 廣電:電視不能播的 網路也不能播