【网络编程3】Java组播套接字

这篇博文是本文学习《Java网络程序设计》书中第5章中组播套接字的学习总结。所有源代码都在文章后面我的github链接代码中。
——惠州学院13网络工程 吴成兵 20160612

目录 1

一 组播套接字概述

前面两篇博客介绍了发送端程序线程发送单一的消息(通过流套接字和数据报套接字)给唯一的接收端程序,这种行为被称为单点传送(unicasting)。如果发送端程序要将同一信息发送给多个接收端,那么发送端程序和接收端程序可以利用多点传送(multicasting)方式进行通信。多点传送就是发送端程序对专用的多点传送组的IP地址和端口发送一系统自寻址数据包,通过加入操作IP地址被多点传送Socket注册,通过这个点,客户程序可以接收发送给组的自寻址包(同样接收端程序也可以给这个组发送自寻址包),一旦客户程序读完所有要读的自寻址数据包,那么可以通过离开组操作多点传送组。
组播套接字通信流程
  DatagramSocket只允许数据报包发送给指定的目的地址,而MulticastSocket则可以将数据报包以广播方式发送到数量不等的多个接收端。若要使用多点广播,则需要让一个数据报包标有组目标主机地址,当数据报包发出后,整个组的所有主机都能收到该数据报包。IP多点广播(或多点发送)实现了将单一信息发送到多个接收端的广播,其思想是设置一个特殊网络地址作为多点广播地址,每一个要收到多点广播地址都被看做一个组,接收端需要接收广播信息时,加入到组即可,发送端则向每组发送数据报包。IP协议为多点广播提供了这批特殊的IP地址,这些IP地址的范围是224.0.0.0~239.255.255.255。

二 MulticastSocket ##

public class MulticastSocket extends DatagramSocket 

MulticastSocket是DatagramSocket的一个子类,扩展了DatagramSocket类的一些方法,就有权访问DatagramSocket的方法。

2.1 MulticastSocket构造方法

  • public MulticastSocket(int port) throws IOException :使用本机默认地址、指定端口来创建一个MulticastSocket对象,用于接收端或发送端。
  • public MulticastSocket() throws IOException :使用本机默认地址、随机端口来创建一个MulticastSocket对象,用于发送端。(同上面构造方法port=0的情况)
  • public MulticastSocket(SocketAddress bindaddr) throws IOException :使用本机指定地址、指定端口来创建一个MulticastSocket对象。

2.2MulticastSocket常用方法

  • public void joinGroup(InetAddress mcastaddr) throws IOException :建立了MultiSocket对象后,要发送或接收组播包,必须用joinGroup方法加入一个组播组。
  • public void leaveGroup(InetAddress mcastaddr) throws IOException :如果不想接收组播包了,就调用leaveGroup方法。程序就发信息到组播路由器,通知它停止向此用户发送数据。
  • public void send(DatagramPacket p) throws IOException :和DatagramSocket发送数据的方法相似。
  • public synchronized void receive(DatagramPacket p) throws IOException :和DatagramSocket接收数据的方法相似。
    @Deprecated
  • public void send(DatagramPacket p, byte ttl) throws IOException:和DatagramSocket发送数据的方法相似,其中ttl是生存时间,大小在0~255之间。
  • public void setTimeToLive(int ttl) throws IOException :设置套接字发出的组播包中的默认ttl数值。
  • public int getTimeToLive() throws IOException :返回ttl数值。
    MultiSocket比DatagramSocket多了setTimeToLive(int ttl)方法,该ttl参数设置数据报包最多可以跨过多少个网络:
    当ttl为0时,指定数据报包应停留在本地主机
    当ttl为1时,指定数据报包应发送到本地局域网;(默认情况下)
    当ttl为32时,意味着数据报包应发送到本站点的网络上
    当ttl为64时,意味着数据报包应保留在本地区
    当ttl为128时,意味着数据报包应保留在本大洲
    当ttl为255时,意味着数据报包可以发送到所有地方

三 组播套接字编程

3.1 使用组播套接字发送数据的过程

  • 调用MulticastSocket()创建一个组播套接字。
  • 创建DatagramPacket数据报。
  • 调用MulticastSocket类的send()方法发送组播包。
  • 关闭组播套接字。
    发送送组播包的代码如下:
package _5_3组播套接字;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;

public class MCServer {

	public static void main(String[] args) throws IOException {

		System.out.println("Server starting...");
		MulticastSocket s = new MulticastSocket();
		InetAddress group = InetAddress.getByName("231.0.0.1");
		byte[] dummy = new byte[0];
		DatagramPacket dgp = new DatagramPacket(dummy, 0, group, 10000);
		for (int i = 0; i < 30000; i++) {
			byte[] buffer = ("Video line " + i).getBytes();
			dgp.setData(buffer);
			dgp.setLength(buffer.length);
			s.send(dgp);
		}
	}
}

##3.2 使用组播套接字接收数据的过程##

  • 调用MulticastSocket()创建一个组播套接字。
  • 调用MulticastSocket类的joinGroup()方法加入一个组播组。
  • 创建DatagramPacket数据报。
  • 调用MulticastSocket类的receive()方法接收组播包。
  • 调用MulticastSocket类的leaveGroup()方法离开该组播组。
  • 关闭组播套接字。
    接收送组播包的代码如下:
package _5_3组播套接字;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;

public class MCClient {

	public static void main(String[] args) throws IOException {

		MulticastSocket s = new MulticastSocket(10000);
		InetAddress group = InetAddress.getByName("231.0.0.1");
		s.joinGroup(group);
		for (int i = 0; i < 10; i++) {
			byte[] buffer = new byte[256];
			DatagramPacket dgp = new DatagramPacket(buffer, buffer.length);
			s.receive(dgp);
			byte[] buffer2 = new byte[dgp.getLength()];
			System.arraycopy(dgp.getData(), 0, buffer2, 0, dgp.getLength());
			System.out.println(new String(buffer2));
		}
		s.leaveGroup(group);
		s.close();

	}

}

四 组播套接字编程示例

4.1 组播套接字发送和接收程序

发送端发送的中文数据要用UTF-8格式,否则接收端将会收到乱码。
sender
receiver

4.1.1 发送端

package _07实验七_组播编程.MulticastProject2.test;

import java.net.DatagramPacket;  
import java.net.InetAddress;  
import java.net.MulticastSocket;  
import java.util.Date;  
  
/**
 * Copyright ? 2016 Authors. All rights reserved.
 *
 * FileName: .java
 * @author : Wu_Being <1040003585@qq.com>
 * Date/Time: 2016-6-14/下午08:46:39
 * Description: 组播的服务端 
 */
public class MulticastSender_UTF8 {  
      
    public static void server() throws Exception{  
        InetAddress group = InetAddress.getByName("239.1.2.3");//组播地址  
        int port = 22363;  
        MulticastSocket mss = null;  
        try {  
            mss = new MulticastSocket(port);  
            mss.joinGroup(group);  
            System.out.println("发数据包启动!(启动时"+new Date()+")");  
              
            while(true){  
                String message = "Hello,你的电脑已中毒##"+new Date();  
                byte[] buffer = message.getBytes();  
                DatagramPacket dp = new DatagramPacket(buffer, buffer.length,group,port);  
                mss.send(dp);  
                System.out.println("发数据("+message+")包给 "+group+":"+port);  
                Thread.sleep(1);  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        }finally{  
            try {  
                if(mss!=null){  
                    mss.leaveGroup(group);  
                    mss.close();  
                }  
            } catch (Exception e2) {  
                // TODO: handle exception  
            }  
        }  
    }  
      
    public static void main(String[] args) throws Exception {  
        server();  
    }  
}  

4.1.2 接收端

package _07实验七_组播编程.MulticastProject2.test;

import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.util.Date;

/**
 * 
 * Copyright ? 2016 Authors. All rights reserved.
 *
 * FileName: .java
 * @author : Wu_Being <1040003585@qq.com>
 * Date/Time: 2016-6-14/下午10:16:44
 * Description:
 */
public class MulticastReceive_UTF8 {
    
    public static void main(String[] args) throws Exception {  
        test();  
    }  
      
    public static void test() throws Exception{  
        InetAddress group = InetAddress.getByName("239.1.2.3");//组播地址  
        int port = 22363;  
       MulticastSocket msr = null;//创建组播套接字  
        try {  
            msr = new MulticastSocket(port);  
            msr.joinGroup(group);//加入连接  
            byte[] buffer = new byte[8192];  
            System.out.println("接收数据包启动!(启动时间: "+new Date()+")");  
            while(true){  
                //建立一个指定缓冲区大小的数据包  
                DatagramPacket dp = new DatagramPacket(buffer, buffer.length);  
                msr.receive(dp);  
                String s = new String(dp.getData(),0,dp.getLength());  
                //解码组播数据包  
                System.out.println("收到"+dp.getSocketAddress()+"数据("+s+")");  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        }finally{  
            if(msr!=null){  
                try {  
                    msr.leaveGroup(group);  
                    msr.close();  
                } catch (Exception e2) {  
                    // TODO: handle exception  
                }  
            }  
        }  
    }  
      
 
}  

4.2 组播应用:英汉词典

broadcastwords

4.2.1 广播端

package _5_4组播套接字编程示例._5_4_2组播应用_英汉词典;


import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Timer;

/**
 *
 * @author geek
 */
@SuppressWarnings("serial")
public class BroadCastWord extends Frame implements ActionListener {
    
    int port;
    InetAddress group = null;
    MulticastSocket socket = null;
    Timer time = null;
    FileDialog open = null;
    Button select, startBroadCast, stopBroadCast;
    File file = null;
    String fileDir = null, fileName = null;
    FileReader in = null;
    BufferedReader br = null;
    int token = 0;
    TextArea showPlaying, showPlayed;
    
    public BroadCastWord() {
        super("单词广播系统");
        select = new Button("Select to broadcast file");
        startBroadCast = new Button("start broadcast");
        stopBroadCast = new Button("stop broadcast");
        startBroadCast.addActionListener(this);
        startBroadCast.setEnabled(false);
        select.addActionListener(this);
        stopBroadCast.addActionListener(this);
        stopBroadCast.setEnabled(false);
        time = new Timer(2000, this);
        open = new FileDialog(this, "选择要广播的文件", FileDialog.LOAD);
        showPlaying = new TextArea(10, 10);
        showPlaying.setForeground(Color.blue);
        showPlayed = new TextArea(10, 10);
        Panel north = new Panel();
        north.add(select);
        north.add(startBroadCast);
        north.add(stopBroadCast);
        add(north, BorderLayout.NORTH);
        Panel center = new Panel();
        center.setLayout(new GridLayout(1, 2));
        center.add(showPlaying);
        center.add(showPlayed);
        add(center, BorderLayout.CENTER);
        validate();
        port = 5000;
        try {
            group = InetAddress.getByName("239.255.0.0");
            socket = new MulticastSocket(port);
            socket.setTimeToLive(1);
            socket.joinGroup(group);
        } catch (UnknownHostException ex) {
            Logger.getLogger(Receive.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Receive.class.getName()).log(Level.SEVERE, null, ex);
        }
        setBounds(100, 50, 360, 380);
        setVisible(true);
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
            
        });
    }
    
    public static void main(String[] args) {
        new BroadCastWord();
    }
    
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == select) {
            showPlayed.setText(null);
            open.setVisible(true);
            fileName = open.getFile();
            fileDir = open.getDirectory();
            file = new File(fileDir, fileName);
            try {
                in = new FileReader(file);
                br = new BufferedReader(in);
                startBroadCast.setEnabled(true);
            } catch (FileNotFoundException ex) {
                Logger.getLogger(BroadCastWord.class.getName()).log(Level.SEVERE, null, ex);
            }
        } else if (e.getSource() == startBroadCast) {
            time.start();
            startBroadCast.setEnabled(false);
            stopBroadCast.setEnabled(true);
        } else if (e.getSource() == time) {
            String s = null;
            try {
                if (token == -1) {
                    file = new File(fileDir, fileName);
                    in = new FileReader(file);
                    br = new BufferedReader(in);
                }
                s = br.readLine();
                if (s != null) {
                    token = 0;
                    showPlaying.setText("正在广播的内容:\n" + s);
                    showPlayed.append(s + "\n");
                    byte buf[] = s.getBytes();
                    DatagramPacket packet = new DatagramPacket(buf, buf.length, group, port);
                    socket.send(packet);
                } else {
                    token = -1;
                }
            } catch (Exception ex) {
                
            }
            
        } else if (e.getSource()
                == stopBroadCast) {
            time.stop();
            stopBroadCast.setEnabled(false);
            startBroadCast.setEnabled(true);
        }
    }
    
}

4.2.2 接收端

package _5_4组播套接字编程示例._5_4_2组播应用_英汉词典;


import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 
 * Copyright ? 2016 Authors. All rights reserved.
 *
 * FileName: .java
 * @author : Wu_Being <1040003585@qq.com>
 * Date/Time: 2016-6-14/下午10:51:10
 * Description:
 */
@SuppressWarnings("serial")
public class Receive extends Frame implements Runnable, ActionListener {

    int port;
    InetAddress group = null;
    MulticastSocket socket = null;
    Button startRece, stopRece;
    Thread thread = null;
    TextArea showReceiving, showReceived;
    boolean stoped = false;

    public Receive() {
        super("定时接收信息");
        thread = new Thread(this);
        startRece = new Button("start receive");
        stopRece = new Button("stop receive");
        startRece.addActionListener(this);
        stopRece.addActionListener(this);
        showReceiving = new TextArea(10, 10);
        showReceiving.setForeground(Color.blue);
        showReceived = new TextArea(10, 10);
        Panel north = new Panel();
        north.add(startRece);
        north.add(stopRece);
        add(north, BorderLayout.NORTH);
        Panel center = new Panel();
        center.setLayout(new GridLayout(1, 2));
        center.add(showReceiving);
        center.add(showReceived);
        add(center, BorderLayout.CENTER);
        validate();
        port = 5000;
        try {
            group = InetAddress.getByName("239.255.0.0");
            socket = new MulticastSocket(port);
            socket.joinGroup(group);
        } catch (UnknownHostException ex) {
            Logger.getLogger(Receive.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Receive.class.getName()).log(Level.SEVERE, null, ex);
        }
        setBounds(100, 50, 360, 380);
        setVisible(true);
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }

        });
    }

    public static void main(String[] args) {
        new Receive();
    }

    public void run() {
        while (true) {
            byte[] data = new byte[8192];
            DatagramPacket packet = null;
            packet = new DatagramPacket(data, data.length);
            try {
                socket.receive(packet);
                String message = new String(packet.getData(), 0, packet.getLength());
                showReceiving.setText("正在接收的内容\n" + message);
                showReceived.append(message + "\n");
            } catch (IOException ex) {
                Logger.getLogger(Receive.class.getName()).log(Level.SEVERE, null, ex);
            }
            if (stoped) {
                break;
            }
        }
    }

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == startRece) {
            startRece.setBackground(Color.blue);
            stopRece.setBackground(Color.gray);
            if (!(thread.isAlive())) {
                thread = new Thread(this);
            }
            thread.start();
            stoped = false;
        }
        if (e.getSource() == stopRece) {
            startRece.setBackground(Color.gray);
            stopRece.setBackground(Color.blue);
            thread.interrupt();
            stoped = true;
        }
    }

}

文中所有源代码链接

Wu_Being博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢!
《Java组播套接字》:
http://blog.csdn.net/u014134180/article/details/51675461


  1. 返回到目录 ↩︎

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值