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

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

目录 1

  • 目录 1
  • 一 组播套接字概述
  • 二 MulticastSocket   
    • 21 MulticastSocket构造方法
    • 22MulticastSocket常用方法
  • 三 组播套接字编程
    • 31 使用组播套接字发送数据的过程
    • 32 使用组播套接字接收数据的过程
  • 四 组播套接字编程示例
    • 41 组播套接字发送和接收程序
      • 411 发送端
      • 412 接收端
    • 42 组播应用英汉词典
      • 421 广播端
      • 422 接收端

一 组播套接字概述

  前面两篇博客介绍了发送端程序线程发送单一的消息(通过流套接字和数据报套接字)给唯一的接收端程序,这种行为被称为单点传送(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格式,否则接收端将会收到乱码。

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 组播应用:英汉词典

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. 返回到目录
时间: 2024-10-01 17:46:15

【网络编程3】Java组播套接字的相关文章

python socket网络编程步骤详解(socket套接字使用)_python

一.套接字套接字是为特定网络协议(例如TCP/IP,ICMP/IP,UDP/IP等)套件对上的网络应用程序提供者提供当前可移植标准的对象.它们允许程序接受并进行连接,如发送和接受数据.为了建立通信通道,网络通信的每个端点拥有一个套接字对象极为重要.套接字为BSD UNIX系统核心的一部分,而且他们也被许多其他类似UNIX的操作系统包括Linux所采纳.许多非BSD UNIX系统(如ms-dos,windows,os/2,mac os及大部分主机环境)都以库形式提供对套接字的支持.三种最流行的套接

【网络编程5】Java与Python套接字Socket通信的例子

今天看一本Python黑客相关的书的第一章部分,边看边在Linux Ubuntu Kylin 32位系统的终端打Python代码,就基本会用Python语言了,包括socket内容.刚好我之前学习Java Socket通信,今天就试着用Python写客户端,并与Java服务器端通信,经过一些调试,最后成功了.Github根链接是:https://github.com/1040003585/javanettextbook/tree/master/Java_Python --惠州学院13网络工程 吴

C++UDP组播编程中,组播地址(组播号)与组播地址的关系是什么?和TCP中IP和端口的关系一样吗?

问题描述 C++UDP组播编程中,组播地址(组播号)与组播地址的关系是什么?和TCP中IP和端口的关系一样吗? C++UDP组播编程中,组播地址(组播号)与组播地址的关系是什么?和TCP中IP和端口的关系一样吗?另外,一台计算机上(不经过路由器或交换机)只能有一个组播吗?急求!!! 解决方案 组播地址和多播地支的关系与TCP中IP和端口的关系不太一样. 首先,网卡查看由信道传送过来的帧,确定是否接收该帧,若接收后就将它传往设备驱动程序.通常网卡仅接收那些目的地址为网卡物理地址或广播地址的帧. 使

java网络编程错误java.net.ConnectException: Connection refused: connect求教

问题描述 java网络编程错误java.net.ConnectException: Connection refused: connect求教 刚开始学习java网络编程,在书上看到一段代码,就动手试一下,结果出现下面错误: java.net.ConnectException: Connection refused: connect 源代码如下: import java.io.*; import java.net.*; class lx01 { public static void main(S

《IP组播(第1卷)》一第2章 网络访问和二层组播2.1 层的封装

第2章 网络访问和二层组播 IP组播(第1卷)第 1 章讨论了单播消息.广播消息和组播消息之间的区别.本章将深入探讨二层IP组播消息,以及它们是如何在二层域中传输的.本章的内容将包含二层域中组播功能的基本组成部分,以及组播的部署. 2.1 层的封装 在学习二层组播之前,我们必须先讨论数据包转发的基础概念,这样才能为这一过程建立一条基线.封装是OSI模型中的重要概念,在数据通信尤其是IP网络中起到重要的作用.封装是指通过一种方式,在OSI参考模型的每一层上添加相关信息,这些信息的作用是处理和转发数

java组播MulticastSocket

在单播模式中有服务器端和客户端之分,而组播模式与单播模式不同,每个端都是以路由器或交换机做为中转广播站,任意一端向路由器或交换机发送消息,路由或交换机负责发送其他节点,每个节点都是同等的.所以在编程模式上用同一个类表示即可--MulticastSocket.     MulticastSocket属于jdk提供的类,类路径为java.net.MulticastSocket,利用此类可以很方便地实现组播功能,下面展示一个简单例子,两个节点之间通过组播传输消息. ①节点一,指定组播地址为228.0.

网络-关于多级路由组播问题

问题描述 关于多级路由组播问题 请教问题,请高手不吝赐教 在一个局域网中有两个路由器Rouer-A和Router-B(假设都不支持组播功能),两个路由器下面分别有两台主机PC-A和PC-B,PC-A和PC-B是不是就不可能实现组播通信? 原始套接字可以解决这个网络环境的组播问题吗? 如果组播不行,我怎么能让它们在局域网中进行通信?

关于几个网络编程的java开源框架

主要有: quick server apache mina hessian      

处理Linux网络编程中的IP地址

 Linux网络服务能力非常强大,它的TCP/IP代码是最高级的.Linux的网络实现是模仿FreeBSD的,它支持FreeBSD的带有扩展的Sockets(套接字)和TCP/IP协议.它支持两个主机间的网络连接和Sockets通讯模型,实现了两种类型的Sockets:BSD Sockets和INET Sockets.它为不同的通信模型和服务质量提供了两种传输协议,即不可靠的.基于消息的UDP传输协议和可靠的.基于流的传输协议TCP,并且都是在IP网络协议上实现的.INET sockets是在以