这篇博文是本文学习《Java网络程序设计》书中第5章中组播套接字的学习总结。所有源代码都在文章后面我的github链接代码中。
——惠州学院13网络工程 吴成兵 20160612
目录 1
- 目录 1
- 一 组播套接字概述
- 二 MulticastSocket
- 21 MulticastSocket构造方法
- 22MulticastSocket常用方法
- 三 组播套接字编程
- 31 使用组播套接字发送数据的过程
- 32 使用组播套接字接收数据的过程
- 四 组播套接字编程示例
- 41 组播套接字发送和接收程序
- 411 发送端
- 412 接收端
- 42 组播应用英汉词典
- 421 广播端
- 422 接收端
- 41 组播套接字发送和接收程序
一 组播套接字概述
前面两篇博客介绍了发送端程序线程发送单一的消息(通过流套接字和数据报套接字)给唯一的接收端程序,这种行为被称为单点传送(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
如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。
- 返回到目录