单播、组播、广播介绍:https://blog.csdn.net/ahou2468/article/details/86526509
目录
1.单播、组播、广播关键类说明
2.单播和广播的具体实现
2.1定义套接字管理类
2.2单播或者广播发送数据包类
2.3.单播或者广播接收数据包监听
3.组播的具体实现
3.1定义套接字管理类
3.2组播发送数据包类
3.3组播接收数据包监听
DatagramSocket:此类表示用于发送和接收数据报包的套接字。数据报套接字是包传递服务的发送或接收点。在数据报套接字上发送或接收的每个数据包都是单独寻址和路由的。从一台机器发送到另一台机器的多个数据包的路由可能不同,并且可能以任何顺序到达。
在可能的情况下,新构造的DatagramSocket启用了So_Broadcast Socket选项,以允许传输广播数据报。为了接收广播数据包,数据报套接字应该绑定到通配符地址。在某些实现中,当数据报套接字绑定到更具体的地址时,也可能接收广播数据包。
示例:DatagramSocket s=new DatagramSocket(null);s.bind(new InetSocketAddress(8888));相当于:DatagramSocket s=new DatagramSocket(8888);这两种情况都将创建一个可以在UDP端口8888上接收广播的DatagramSocket。
注意:DatagramSocket主要用于单播和广播的套接字;
DatagramPacket:此类表示数据报包,用于发送和接收信息的载体。
数据包用于实现无连接数据包传递服务。每个消息都是基于包中包含的信息从一台机器路由到另一台机器的。从一台机器发送到另一台机器的多个数据包的路由可能不同,并且可能以任何顺序到达。不保证包的传送。
MulticastSocket:多播(组播)数据报套接字类对于发送和接收IP多播(组播)数据包很有用。多播(组播)套接字是一个(UDP)数据报套接字,具有附加的功能,可以加入Internet上其他多播(组播)主机的“组”。
多播(组播)组由D类IP地址和标准UDP端口号指定。D类IP地址的范围为224.0.0.0到239.255.255.255(含)。地址224.0.0.0是保留的,不应使用。
当一个人向多播组发送消息时,所有订阅该主机和端口的接收者都会接收该消息(在数据包的生存时间范围内,请参见下文)。套接字不需要是多播组的成员就可以向其发送消息。
当一个套接字订阅一个多播组/端口时,它接收由其他主机发送到该组/端口的数据报,以及该组和端口的所有其他成员。套接字通过leaveGroup(InetAddress addr)方法放弃组中的成员身份。多个多播套接字可以同时订阅多播组和端口,它们都将接收组数据报。
当前不允许小程序(applets)使用多播套接字。
注意:MulticastSocket用于组播的套接字
InetAddress:此类表示Internet协议(IP)地址。
IP地址是由IP使用的32位或128位无符号数字,这是一个较低级别的协议,在该协议上构建诸如UDP和TCP等协议。IP地址体系结构由 RFC 790: Assigned Numbers, RFC 1918: Address Allocation for Private Internets, RFC 2365: Administratively Scoped IP Multicast, and RFC 2373: IP Version 6 Addressing Architecture定义。InetAddress的实例由一个IP地址和它相应的主机名组成(取决于它是用主机名构造的,还是已经执行了反向主机名解析)。
a.创建套接字DatagramSocket,并制定本地绑定的端口号
socket = new DatagramSocket(Constants.UNICAST_PORT);
/**
* 单播或者广播管理类
*/
public class Unicast {
//单播或者广播socket
private DatagramSocket socket;
private static final Unicast unicast = new Unicast();
private Unicast(){
try {
socket = new DatagramSocket(Constants.UNICAST_PORT);
} catch (SocketException e) {
e.printStackTrace();
}
}
public static Unicast getUnicast(){
return unicast;
}
public DatagramSocket getSocket(){
return socket;
}
/**
* 释放资源
*/
public void free(){
if(socket != null){
socket.close();
socket = null;
}
}
}
广播地址应用于网络内的所有主机
1)受限广播
它不被路由发送,但会被送到相同物理网络段上的所有主机
IP地址的网络字段和主机字段全为1就是地址255.255.255.255
2)直接广播
网络广播会被路由,并会发送到专门网络上的每台主机
IP地址的网络字段定义这个网络,主机字段通常全为1,如 192.168.10.255
单播地址:具体要发送的目的IP地址;
a.创建数据包,指定发送的内容和地址,单播或者广播地址
DatagramPacket datagramPacket = new DatagramPacket(data,
data.length, 单播或者组播地址,
Constants.UNICAST_PORT);
b.调用套接字发送数据包
Unicast.getUnicast().getSocket().send(datagramPacket);
public class SignInAndOutReq extends JobHandler(Thread){
private String command;
public SignInAndOutReq(Handler handler){
super(handler);
}
public void setCommand(String command){
this.command = command;
}
@Override
public void run() {
if(command != null){
byte[] data = command.getBytes();
if(Command.DISC_REQUEST.equals(command)){
data = (command+IPUtil.getLocalIPAddress()).getBytes();
}
DatagramPacket datagramPacket = new DatagramPacket(data,
data.length, 单播或者广播地址,
Constants.UNICAST_PORT);
try {
Unicast.getUnicast().getSocket().send(datagramPacket);
} catch (IOException e) {
e.printStackTrace();
}
if(command.equals(Command.DISC_REQUEST)){
sendMsg2MainThread();
}else if(command.equals(Command.DISC_LEAVE)){
setCommand(Command.DISC_REQUEST);
}
}
}
private void sendMsg2MainThread(){
Message message = new Message();
message.what = IntercomService.DISCOVERING_SEND;
handler.sendMessage(message);
}
}
a.设置接收缓冲区
byte[] receivedData = new byte[512];
DatagramPacket datagramPacket = new DatagramPacket(receivedData, receivedData.length);
b.调用套接字接收数据报文监听,等待接收数据包
Unicast.getUnicast().getSocket().receive(datagramPacket);
c.程序退出以后释放资源,调用free()方法;
public class Receiver extends JobHandler(Thread) {
public Receiver(Handler handler){
super(handler);
}
@Override
public void run() {
while (true)
{
//设置接收缓冲区
byte[] receivedData = new byte[512];
DatagramPacket datagramPacket = new DatagramPacket(receivedData, receivedData.length);
// 接收数据报文
try {
Unicast.getUnicast().getSocket().receive(datagramPacket);
} catch (IOException e) {
e.printStackTrace();
}
// 判断数据报文类型,并做相应处理
if(datagramPacket.getLength() == Command.DISC_REQUEST.getBytes().length
|| datagramPacket.getLength() == Command.DISC_RESPONSE.getBytes().length
|| datagramPacket.getLength() == Command.DISC_LEAVE.getBytes().length){
handleCommandData(datagramPacket);
}else{
handleOptData(datagramPacket);
}
}
}
@Override
public void free() {
// Multicast.getMulticast().free();
Unicast.getUnicast().free();
}
}
a.创建组播套接字,绑定本地端口
multicastSocket = new MulticastSocket(Constants.MULTI_BROADCAST_PORT);
b.创建InetAddress对象,使用组播地址,多播(组播)IP地址就是D类IP地址,即224.0.0.0至239.255.255.255之间的IP地址。
inetAddress = InetAddress.getByName(Constants.MULTI_BROADCAST_IP);
c.加入组播地址
multicastSocket.joinGroup(inetAddress);
当主机不想接收组播信息时,则移除组播地址并关闭套接字
multicastSocket.leaveGroup(inetAddress);
multicastSocket.close();
/**
* 组播管理类
*/
public class Multicast {
//组播Socket
private MulticastSocket multicastSocket;
//IPV4地址
private InetAddress inetAddress;
private static final Multicast multicast = new Multicast();
private Multicast(){
try {
inetAddress = InetAddress.getByName(Constants.MULTI_BROADCAST_IP);
multicastSocket = new MulticastSocket(Constants.MULTI_BROADCAST_PORT);
multicastSocket.setLoopbackMode(true);
multicastSocket.joinGroup(inetAddress);
multicastSocket.setTimeToLive(4);
} catch (IOException e) {
e.printStackTrace();
}
}
public static Multicast getMulticast(){
return multicast;
}
public MulticastSocket getMulticastSocket(){
return multicastSocket;
}
public InetAddress getInetAddress(){
return inetAddress;
}
public void free(){
if(multicastSocket != null){
try {
multicastSocket.leaveGroup(inetAddress);
multicastSocket.close();
multicastSocket = null;
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
a.创建数据包,指定发送的内容和地址,使用组播地址
DatagramPacket datagramPacket = new DatagramPacket(data, data.length,
Multicast.getMulticast().getInetAddress(), //组播地址
Constants.MULTI_BROADCAST_PORT);
b.套接字发送数据包
Multicast.getMulticast().getMulticastSocket().send(datagramPacket);
a.设置接收缓冲区
DatagramPacket sendPacket = new DatagramPacket(feedback, feedback.length,
packet.getAddress(), Constants.MULTI_BROADCAST_PORT);
b.套接字接收数据报文监听,等待接收数据包
Multicast.getMulticast().getMulticastSocket().send(sendPacket);