简介
单播有TCP和UDP两种实现,组播(多播)和广播只有UDP一种实现。单播和广播基本一样,只是广播的数据包IP为广播IP。
 
单播
DatagramSocket和DatagramPacket
服务端:
import java.net.DatagramPacket;
import java.net.DatagramSocket;
 
public class UDPServer {
public static void main(String[] args) throws Exception {
System.out.println("启动UDP单播服务端");
// 构造DatagramSocket实例,指定本地端口6666
try (DatagramSocket datagramSocket = new DatagramSocket(6666)) {
//设置超时时间为10秒
datagramSocket.setSoTimeout(10000);
while (true) {
// 构造DatagramPacket实例,用来接收最大长度为512字节的数据包
byte[] data = new byte[512];
DatagramPacket receivePacket = new DatagramPacket(data, 512);
// 接收报文,此方法在接收到数据报前一直阻塞
datagramSocket.receive(receivePacket);
System.out.println("客户端地址:" + receivePacket.getAddress().getHostAddress());
System.out.println("客户端端口:" + receivePacket.getPort());
System.out.println("接收到的数据长度:" + receivePacket.getLength());
System.out.println("接收到的数据:" + new String(receivePacket.getData(), 0, receivePacket.getLength(), "UTF-8"));
}
}
}
}
 
客户端:
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
 
public class UDPClient {
public static void main(String[] args) throws Exception {
{
// 构造DatagramSocket实例,指定本地端口8888
try (DatagramSocket datagramSocket = new DatagramSocket(8888)) {
for (int i = 0; i < 5; i++) {
String data = "当前循环:" + i;
// 构造数据报包,用来将data发送到指定主机上的指定端口号。
DatagramPacket sendPacket = new DatagramPacket(data.getBytes("UTF-8"), data.getBytes("UTF-8").length, new InetSocketAddress("10.206.16.67", 6666));
//发送报文
datagramSocket.send(sendPacket);
}
}
}
}
}
 
服务端打印:
启动UDP单播服务端
客户端地址:10.206.16.67
客户端端口:8888
接收到的数据长度:16
接收到的数据:当前循环:0
客户端地址:10.206.16.67
客户端端口:8888
接收到的数据长度:16
接收到的数据:当前循环:1
客户端地址:10.206.16.67
客户端端口:8888
接收到的数据长度:16
接收到的数据:当前循环:2
客户端地址:10.206.16.67
客户端端口:8888
接收到的数据长度:16
接收到的数据:当前循环:3
客户端地址:10.206.16.67
客户端端口:8888
接收到的数据长度:16
接收到的数据:当前循环:4
Exception in thread "main" java.net.SocketTimeoutException: Receive timed out
at java.net.DualStackPlainDatagramSocketImpl.socketReceiveOrPeekData(Native Method)
at java.net.DualStackPlainDatagramSocketImpl.receive0(DualStackPlainDatagramSocketImpl.java:120)
at java.net.AbstractPlainDatagramSocketImpl.receive(AbstractPlainDatagramSocketImpl.java:144)
at java.net.DatagramSocket.receive(DatagramSocket.java:812)
at UDPServer.main(UDPServer.java:16)
 
Socket和ServerSocket
服务端:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
 
public class TCPServer {
public static void main(String[] args) throws Exception {
System.out.println("启动单播TCP服务端");
//构造ServerSocket实例,指定监听的本地端口为6666
try (ServerSocket serverSocket = new ServerSocket(6666)) {
//设置超时时间为10秒
serverSocket.setSoTimeout(10000);
while (true) {
//侦听并接收到此套接字的连接,此方法在连接传入之前一直阻塞。
Socket socket = serverSocket.accept();
TCPServerHandleThread tcpServerHandleThread = new TCPServerHandleThread(socket);
Thread thread = new Thread(tcpServerHandleThread);
thread.start();
}
}
}
}
 
/**
* 为每个连接进来的请求单独起一个处理线程
*/
class TCPServerHandleThread implements Runnable {
private Socket socket;
 
public TCPServerHandleThread(Socket socket) {
this.socket = socket;
}
 
@Override
public void run() {
try {
try (BufferedInputStream inputStream = new BufferedInputStream(socket.getInputStream()); BufferedOutputStream outputStream = new BufferedOutputStream(socket.getOutputStream())) {
//每次读取的最大字节数,为了演示特地写小一点
byte[] bytes = new byte[8];
//每次读取的有效字节数
int count;
//结果数组
byte[] result = new byte[0];
while ((count = inputStream.read(bytes)) != -1) {
//本次读取的有效字节数组
byte[] temp1 = Arrays.copyOfRange(bytes, 0, count);
//复制结果数组到新数组,新数组长度为结果数组的长度加上本次读取的有效字节数,用0填充
byte[] temp2 = Arrays.copyOf(result, result.length + count);
// 将本次读取的有效字节数组放到新数组里
System.arraycopy(temp1, 0, temp2, result.length, count);
result = temp2;
}
InetSocketAddress inetSocketAddress = (InetSocketAddress) socket.getRemoteSocketAddress();
System.out.println("客户端的ip和端口:" + inetSocketAddress.getAddress() + " " + inetSocketAddress.getPort());
InetSocketAddress inetSocketAddressL = (InetSocketAddress) socket.getLocalSocketAddress();
System.out.println("本地绑定的ip和端口:" + inetSocketAddressL.getAddress() + " " + inetSocketAddressL.getPort());
System.out.println("接收到的数据长度:" + result.length);
System.out.println("接收到的数据:" + new String(result, "UTF-8"));
//关闭此socket输入流
socket.shutdownInput();
outputStream.write("接收完毕".getBytes("UTF-8"));
outputStream.flush();
//关闭此socket输出流
socket.shutdownOutput();
} finally {
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
 
客户端:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
 
public class TCPClient {
public static void main(String[] args) throws Exception {
// 构造Socket实例
try (Socket socket = new Socket("10.206.16.67", 6666); BufferedInputStream inputStream = new BufferedInputStream(socket.getInputStream()); BufferedOutputStream outputStream = new BufferedOutputStream(socket.getOutputStream())) {
InetSocketAddress inetSocketAddress = (InetSocketAddress) socket.getRemoteSocketAddress();
System.out.println("服务端的ip和端口:" + inetSocketAddress.getAddress() + " " + inetSocketAddress.getPort());
InetSocketAddress inetSocketAddressL = (InetSocketAddress) socket.getLocalSocketAddress();
System.out.println("本地绑定的ip和端口:" + inetSocketAddressL.getAddress() + " " + inetSocketAddressL.getPort());
outputStream.write("abcdefg测试数据1234567890".getBytes("UTF-8"));
outputStream.flush();
//关闭此socket输出流
socket.shutdownOutput();
byte[] bytes = new byte[1024];
int count;
if ((count = inputStream.read(bytes)) != -1) {
System.out.println(new String(bytes, 0, count, "UTF-8"));
}
//关闭此socket输入流
socket.shutdownInput();
}
}
}
 
服务端打印:
启动单播TCP服务端
客户端的ip和端口:/10.206.16.67 62414
本地绑定的ip和端口:/10.206.16.67 6666
接收到的数据长度:29
接收到的数据:abcdefg测试数据1234567890
Exception in thread "main" java.net.SocketTimeoutException: Accept timed out
at java.net.DualStackPlainSocketImpl.waitForNewConnection(Native Method)
at java.net.DualStackPlainSocketImpl.socketAccept(DualStackPlainSocketImpl.java:135)
at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:404)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:199)
at java.net.ServerSocket.implAccept(ServerSocket.java:545)
at java.net.ServerSocket.accept(ServerSocket.java:513)
at TCPServer.main(TCPServer.java:17)
 
客户端打印:
服务端的ip和端口:/10.206.16.67 6666
本地绑定的ip和端口:/10.206.16.67 62414
接收完毕
 
客户端还可以采用如下方式设置连接超时时间为10秒:
Socket socket = new Socket();
socket.connect(new InetSocketAddress("10.206.16.67", 6666), 10000);
 
组播(多播)
组播是一对多的通信,允许同时向大量的接收方发送数据包。一个主机可以有多个组播进程,这些进程可以加入到同一个组播组也可以加入到不同的组播组,主机会跟踪记录当前哪些进程属于哪个组播组。进程随时可以要求主机主动告诉路由器加入和退出哪个组播组,而且每隔一段时间(大概1分钟)路由器也会向它所在的LAN发送一个查询数据包,要求主机告诉路由器它自己属于哪个组播组。支持组播的路由器负责向所有组内成员发送数据包,但不确保每个成员一定会收到。目的地址是组播ip的数据包会被路由器转发到对应组播组内的主机。
组播ip地址是D类地址,可以使用224.0.2.0~238.255.255.255这个范围的ip地址,组播进程根据组播ip进行分组。组播进程监听某端口并通过此端口接收数据,当一个组播数据包被转发到主机上的时候,主机会根据数据包的目的端口将数据包交给监听此目的端口的组播进程。
如果主机是多网卡,那么此时就需要注意了,一定要设置用哪个网卡发送和接受数据,因为组播是无法跨网段的,否则会导致数据接收不到。
MulticastSocket继承于DatagramSocket,因此可以发送也可以接收数据包。MulticastSocket绑定的端口是接收和发送数据的,如果数据包目的端口和此端口一致,则这个程序就能接收到数据包。setNetworkInterface方法是用来绑定网卡的。joinGroup告诉主机该程序要加入到哪个组播组,leaveGroup则是退出组播组。其他用法和DatagramSocket基本一致。
 
发送端:
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.NetworkInterface;
 
public class MultiCastSender {
public static void main(String[] args) throws Exception {
InetAddress inetAddress = InetAddress.getByName("228.0.0.8");
MulticastSocket multicastSocket = new MulticastSocket();
multicastSocket.setNetworkInterface(NetworkInterface.getByInetAddress(InetAddress.getByName("10.206.16.67")));
multicastSocket.joinGroup(inetAddress);
int count = 0;
while (true) {
if (count == 5) {
multicastSocket.leaveGroup(inetAddress);
return;
}
String message = "时间戳:" + System.currentTimeMillis();
byte[] bytes = message.getBytes("UTF-8");
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length,
inetAddress, 8888);
multicastSocket.send(datagramPacket);
count++;
}
}
}
 
接收端:
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.NetworkInterface;
 
public class MultiCastReceiver {
public static void main(String[] args) throws Exception {
InetAddress inetAddress = InetAddress.getByName("228.0.0.8");
MulticastSocket multicastSocket = new MulticastSocket(8888);
multicastSocket.setNetworkInterface(NetworkInterface.getByInetAddress(InetAddress.getByName("10.206.16.67")));
multicastSocket.joinGroup(inetAddress);
int count = 0;
while (true) {
if (count == 5) {
multicastSocket.leaveGroup(inetAddress);
return;
}
 
// 构造DatagramPacket实例,用来接收最大长度为512字节的数据包
byte[] data = new byte[512];
DatagramPacket receivePacket = new DatagramPacket(data, 512);
// 接收报文,此方法在接收到数据报前一直阻塞
multicastSocket.receive(receivePacket);
System.out.println("第" + (count + 1) + "次接收");
System.out.println("客户端地址:" + receivePacket.getAddress().getHostAddress());
System.out.println("客户端端口:" + receivePacket.getPort());
System.out.println("接收到的数据长度:" + receivePacket.getLength());
System.out.println("接收到的数据:" + new String(receivePacket.getData(), 0, receivePacket.getLength(), "UTF-8"));
count++;
}
}
}
 
接收端打印:
第1次接收
客户端地址:10.206.16.67
客户端端口:54214
接收到的数据长度:25
接收到的数据:时间戳:1559133639107
第2次接收
客户端地址:10.206.16.67
客户端端口:54214
接收到的数据长度:25
接收到的数据:时间戳:1559133639108
第3次接收
客户端地址:10.206.16.67
客户端端口:54214
接收到的数据长度:25
接收到的数据:时间戳:1559133639108
第4次接收
客户端地址:10.206.16.67
客户端端口:54214
接收到的数据长度:25
接收到的数据:时间戳:1559133639108
第5次接收
客户端地址:10.206.16.67
客户端端口:54214
接收到的数据长度:25
接收到的数据:时间戳:1559133639108
 
广播
服务端:
import java.net.DatagramPacket;
import java.net.DatagramSocket;
 
public class UDPServer {
public static void main(String[] args) throws Exception {
System.out.println("启动UDP广播服务端");
// 构造DatagramSocket实例,指定本地端口6666
try (DatagramSocket datagramSocket = new DatagramSocket(6666)) {
//设置超时时间为10秒
datagramSocket.setSoTimeout(10000);
while (true) {
// 构造DatagramPacket实例,用来接收最大长度为512字节的数据包
byte[] data = new byte[512];
DatagramPacket receivePacket = new DatagramPacket(data, 512);
// 接收报文,此方法在接收到数据报前一直阻塞
datagramSocket.receive(receivePacket);
System.out.println("客户端地址:" + receivePacket.getAddress().getHostAddress());
System.out.println("客户端端口:" + receivePacket.getPort());
System.out.println("接收到的数据长度:" + receivePacket.getLength());
System.out.println("接收到的数据:" + new String(receivePacket.getData(), 0, receivePacket.getLength(), "UTF-8"));
}
}
}
}
 
客户端:
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
 
public class UDPClient {
public static void main(String[] args) throws Exception {
{
// 构造DatagramSocket实例,指定本地端口8888
try (DatagramSocket datagramSocket = new DatagramSocket(8888)) {
for (int i = 0; i < 5; i++) {
String data = "当前循环:" + i;
// 构造数据报包,指定数据包的IP为广播地址,端口为6666。
DatagramPacket sendPacket = new DatagramPacket(data.getBytes("UTF-8"), data.getBytes("UTF-8").length, new InetSocketAddress("255.255.255.255", 6666));
//发送报文
datagramSocket.send(sendPacket);
}
}
}
}
}
 
服务端打印:
启动UDP广播服务端
客户端地址:192.168.56.1
客户端端口:8888
接收到的数据长度:16
接收到的数据:当前循环:0
客户端地址:192.168.56.1
客户端端口:8888
接收到的数据长度:16
接收到的数据:当前循环:1
客户端地址:192.168.56.1
客户端端口:8888
接收到的数据长度:16
接收到的数据:当前循环:2
客户端地址:192.168.56.1
客户端端口:8888
接收到的数据长度:16
接收到的数据:当前循环:3
客户端地址:192.168.56.1
客户端端口:8888
接收到的数据长度:16
接收到的数据:当前循环:4
Exception in thread "main" java.net.SocketTimeoutException: Receive timed out
at java.net.DualStackPlainDatagramSocketImpl.socketReceiveOrPeekData(Native Method)
at java.net.DualStackPlainDatagramSocketImpl.receive0(DualStackPlainDatagramSocketImpl.java:120)
at java.net.AbstractPlainDatagramSocketImpl.receive(AbstractPlainDatagramSocketImpl.java:144)
at java.net.DatagramSocket.receive(DatagramSocket.java:812)
at UDPServer.main(UDPServer.java:17)

Java单播、组播(多播)、广播的简单实现的更多相关文章

  1. netty的Udp单播、组播、广播实例+Java的Udp单播、组播、广播实例

    网络上缺乏netty的udp的单播.组播案例,经过一番学习总结之后终于把这两个案例调通,下面把这两个案例的代码放在这里分享一下. 首先推荐博文: http://colobu.com/2014/10/2 ...

  2. 组播和广播的概念,IGMP的用途

    1.组播和广播的概念 1) 组播 主机之间的通讯模式,也就是加入了同一个组的主机可以接收到此组内的所有数据,网络中的交换机和路由器只向有需求者复制并转发其所需数据. 主机可以向路由器请求加入或退出某个 ...

  3. 浅谈Android中的组播(多播)

    组播使用UDP对一定范围内的地址发送相同的一组Packet,即一次可以向多个接受者发出信息,其与单播的主要区别是地址的形式.IP协议分配了一定范围的地址空间给多播(多播只能使用这个范围内的IP),IP ...

  4. 【VS开发】组播(多播)的C程序实战

    每个人都有不同的认知规律和习惯, 有的人喜欢搞一套严密的大理论, 论述起来滔滔不绝, 不管自己懂不懂, 反正读者/听者是没搞懂. 有的人喜欢从实践出发, 没看到代码, 不运行一下, 不看到结果, 就不 ...

  5. <转>单播,广播,组播的缺点与优点

    原文链接:http://apje.blog.163.com/blog/static/145345252007101175714761/ 当前的网络中有三种通讯模式:单播.广播.组播(多播),其中的组播 ...

  6. Android开发:组播(多播)与广播

    近期由于需要编写能够使同一局域网中的Android客户端与PC端进行自动匹配通信功能的程序,学习并试验了JAVA组播与广播的内容,记录一些理解如下: 一.组播(多播) 背景知识:组播使用UDP对一定范 ...

  7. MAC地址的介绍(单播、广播、组播、数据收发)

    MAC地址组成 网络设备的MAC地址是全球唯一的.MAC地址长度为48比特,通常用十六进制表示.MAC地址包含两部分:前24比特是组织唯一标识符(OUI,OrganizationallyUniqueI ...

  8. TCP/IP 笔记 - 广播和本地组播

    在之前第二章介绍IP寻址的时候有介绍到,IP地址有4种:单播.组播.广播.任播. 单播,客户端与服务器之间点到点连接通信: 组播,在发送者和多个接收者(如某个特定的分组)之间实现点对多点的连接通信: ...

  9. Ztack学习笔记(6)-广播组播点播

    Zigbee网络中进行数据通信主要有三种类型:单播.组播.广播.那这三种方式如何设置呢,在哪里设置呢, 一. 广播 当应用程序需要将数据包发送给网络的每一个设备时,使用这种模式.广播的短地址有三种 0 ...

  10. MAC 地址(单播、组播、广播地址分类)

    简介 一个制造商在生产制造网卡之前,必须先向 IEEE 注册,以获取到一个长度为 24bit 的厂商代码,也称为 OUI(Organizationally-Unique Identifier).制造商 ...

随机推荐

  1. MPI组操作

    进程组的创建 MPI_Comm_Group int MPI_Comm_group( MPI_Comm comm, MPI_Group *group ); 把相同的通信子进程放到一个组内. #inclu ...

  2. mysql图形化工具基本操作

    一.DataType 常见的数据类型: - `int` 整数 - `varchar(len)` 字符串 - `tinyint(1)`布尔值 二.设置字段的特殊标识 - `PK`(`Primary Ke ...

  3. ssm-springboot实现修排名再顺序排的主要代码

    排序改为2,结果如下: package com.zhetang.controller; import com.core.vo.JsonResult; import com.utils.PageResu ...

  4. 如何发挥微博客在seo营销中的作用

    http://www.wocaoseo.com/thread-158-1-1.html 我们知道,现在微博客已经发展的相当成熟,普通一个人,只要会上网,就能开通属于自己的博客,进而可以时时地通过微博客 ...

  5. python_选择排序

    #选择排序 def insert_sort(li): for i in range (1,len(li)): # i表示摸到牌的下标 tem = li[i] j = i - 1 # j 是初始手中的牌 ...

  6. 力扣Leetcode 33. 搜索旋转排序数组

    33. 搜索旋转排序数组 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 搜索一个给定的目标值, ...

  7. 攻防世界——web新手练习区解题记录<1>(1-4题)

    web新手练习区一至四题 第一题view_source: 题目说右键不管用了,我们先获取在线场景来看一看,我们看到这样一个网页,并且右键确实点了没什么反应,而用到右键一般就是查看网页源码 用快捷键(F ...

  8. 小程序开发-Canvas画布组件

    Canvas画布 基本使用方法: 在wxml中添加canvas组件 <canvas canvas-id='canvasDemo' class='demo'></canvas> ...

  9. 非构造函数方式创建DbContext实例的方法

    using Microsoft.EntityFrameworkCore;using Microsoft.EntityFrameworkCore.Design;using Microsoft.Entit ...

  10. Kubernetes 初体验(先占个坑)