文章目录

  • UDP是什么?
  • UDP核心API
    • DatagramSocket构造方法介绍
    • DatagramSocket常用方法
    • DatagramPacket的构造方法
    • DatagramPacket的常用方法
  • 单播、广播、多播
  • 案例介绍
  • 测试

UDP是什么?

它是一种用户数据报协议,又称用户数据报文协议,是一个简单的面向数据报的传输层协议,正式规范为RFC 768;UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据报的方法

UDP核心API

  • DatagramSocket:用于接收与发送UDP信息的类(发送/接收UDP包),不同于TCP, UDP没有合并到Socket api中, 该类即是服务器也是客户端.
  • DatagramPacket:即UDP报文封装类,用于处理报文, 将byte数组、目标地址、目标端口等数据包装成报文或将报文解为byte数组,它是UDP的发送实体和接收实体。
    至于目标地址、目标端口的具体含义取决于该数据报文是被发送还是被接收。若是要发送的数据报文,则表示接收端的ip和端口;若是接收到的数据报文,则表示发送端的ip和端口。

DatagramSocket构造方法介绍

  • DatagramSocket():创建简单实例,不指定端口与IP,让系统自动分配
  • DatagramSocket(int port):创建监听固定端口的实例
  • DatagramSocket(int port,InetAddress localAddr):创建固定端口指定IP的实例

DatagramSocket常用方法

  • receive(DatagramPacket d):接收一个数据报文
  • send(DatagramPacket d):发送一个数据报文
  • setSoTimeout(int timeout):设置超时时间,单位毫秒
  • close():关闭、释放资源

DatagramPacket的构造方法

  • DatagramPacket(byte buf[], int length, InetAddress address, int port):通常用于发送数据报文时使用,前2个参数指定buf的使用区间,后面2个参数指定目标机器的地址与端口.
  • DatagramPacket(byte[]buf,int offset, int length,InetAddress address,int port):通常用于发送数据报文时使用,前3个参数指定buf的使用区间,后面2个参数指定目标机器的地址与端口.
  • DatagramPacket(byte[buf,int length,SocketAddress address]):通常用于发送数据报文时使用,前2个参数指定buf的使用区间,SocketAddress 相当于InetAddress+Port.
  • DatagramPacket(byte buf[], int length) :通常用于接收数据报文时使用,参数用于指定buf和buf的长度.

DatagramPacket的常用方法

  • setData(byte[]buf,int offset,int length):设置指定长度的数据
  • setData(byte[]buf):设置buf的完整数据
  • setLength(int length):设置buf数据的长度
  • getData():获取报文中的数据
  • getOffset():获取报文中数据buf的偏移量
  • getLength():获取报文中数据buf的长度
  • setAddress(InetAddress iaddr):设置目标地址(发送端用于设置数据报的接收端地址)
  • setPort(int port):设置目标端口(发送端用于设置数据报的接收端端口)
  • getAddress():获取目标地址(发送端地址)
  • getPort():获取目标端口(发送端端口)
  • setSocketAddress(SocketAddress adress):设置目标地址+端口
  • getSocketAddress():获取目标地址+端口

通常get方法用于获取该数据报的发送者信息,而set方法用于设置数据报的接收端信息,当然如果你使用多参数的构造方法的话,可以减少set方法的使用。

单播、广播、多播

  • 单播:就是点对点发送信息,不被其他点所感知。
  • 广播:给所有端发送信息,会受到路由器的隔离限制,仅仅在同一局域网内有效。
  • 多播:也称为组播,是向一组点发送信息。

案例介绍

该案例分为UDP提供者(即被搜索的设备,例如局域网中的智能设备)和UDP搜索者(例如局域网中的手机)。

需要完成的功能是通过手机查找局域网中智能设备的唯一标识,假设唯一标识是一串UUID值,查找后打印出来。

UDP提供者需要实现的功能是循环的监听特定端口,然后解析收到的数据,判断该数据是否符合预定的格式,从中获取到发送者的响应端口,并将唯一标识UUID值响应给UDP的搜索者。

UDP搜索者需要实现的功能就是监听特定端口和发送局域网广播,发送广播的时候将监听端口设置在数据中,因此需要先开启监听完成后,才能发送广播,一旦收到响应数据,就可以解析设备信息了。

下面开始编码,首先来一个MessageCreator类,用于封装和解析端口以及设备唯一标识

/*** 消息创建者*/
public class MessageCreator {private static final String SN_HEADER = "Receive Port I'm UDPProvider (SN):"; //UDPProvider 回复的snprivate static final String PORT_HEADER = "I'm UDPSearcher,Please send to (Port):"; //UDPSearcher的响应端口public static String buildWithPort(int port) {return PORT_HEADER + port;}public static int parsePort(String data){if (data.startsWith(PORT_HEADER)) {return Integer.parseInt(data.substring(PORT_HEADER.length()));}return -1;}public static String buildWithSn(String sn) {return SN_HEADER + sn;}public static String parseSn(String data){if (data.startsWith(SN_HEADER)) {return data.substring(SN_HEADER.length());}return null;}
}

然后是UDPProvider类

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.UUID;/*** UDP 提供者,用于提供服务*/
public class UDPProvider {public static void main(String[] args) throws IOException {//生成一份唯一标识String sn = UUID.randomUUID().toString();Provider provider = new Provider(sn);provider.start();//读取任意字符退出System.in.read();provider.exit();}private static class Provider extends Thread {private final String sn;private boolean done = false;private DatagramSocket ds = null;public Provider(String sn) {super();this.sn = sn;}@Overridepublic void run() {super.run();System.out.println("UDPProvider Started");try {// 作为接收者,指定一个端口用于数据接收ds = new DatagramSocket(20000);while (!done) {//构建接收实体final byte[] buf = new byte[512];DatagramPacket receivePack = new DatagramPacket(buf, buf.length);//开始接收ds.receive(receivePack);//打印接收到的信息与发送者的信息String ip = receivePack.getAddress().getHostAddress();//发送者的ipint port = receivePack.getPort();//发送者的端口int dataLen = receivePack.getLength();//数据包长度String data = new String(receivePack.getData(), 0, dataLen);//数据内容//打印发送者ip/端口/数据System.out.println("UDPProvider receive from ip:" + ip + "\tport:" + port + "\tdata:" + data);//解析响应端口号int responsePort = MessageCreator.parsePort(data);if (responsePort != -1) {//构建一份回送数据将设备的sn返回给搜索者String responseData = MessageCreator.buildWithSn(sn);byte[] responseDataBytes = responseData.getBytes();//直接根据发送者构建一份回送信息DatagramPacket responsePacket = new DatagramPacket(responseDataBytes,responseDataBytes.length,receivePack.getAddress(),//发送者的ip拿来指定为接收端ipresponsePort); //回送到指定端口ds.send(responsePacket);}}} catch (Exception ignored) {} finally {close();}//完成System.out.println("UDPProvider Finished");}private void close() {if (null != ds) {ds.close();ds = null;}}/*** 结束*/void exit() {done = true;close();}}
}

最后是UDPSearcher类

import java.io.IOException;
import java.net.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;/*** UDP 搜索者*/
public class UDPSearcher {//监听回送端口号private static final int LISTENER_PORT = 30000;public static void main(String[] args) throws IOException, InterruptedException {System.out.println("UDPSearcher  Started");//开启监听30000端口Listener listener = listen();//发送广播sendBroadcast();//读取任意信息结束System.in.read();List<Device> devices = listener.getDevicesAndClose();for (Device device : devices) {System.out.println("Device:" + device.toString());}System.out.println("UDPSearcher  Finished");}/*** 监听UDP提供者的回应*/private static Listener listen() throws InterruptedException {System.out.println("UDPSearcher  start listen");CountDownLatch countDownLatch = new CountDownLatch(1);Listener listener = new Listener(LISTENER_PORT, countDownLatch);listener.start();countDownLatch.await(); //等待监听启动完成,这里是阻塞的return listener;//启动完成就返回监听}/*** 发送广播开始搜索UDP提供者** @throws IOException*/private static void sendBroadcast() throws IOException {System.out.println("UDPSearcher sendBroadcast Started");// 作为搜索方,无需指定端口,让系统自动分配DatagramSocket ds = new DatagramSocket();//发送一份请求数据,暴露监听端口String requestData = MessageCreator.buildWithPort(LISTENER_PORT);byte[] requestDataBytes = requestData.getBytes();//创建一个DatagramPacketDatagramPacket requestPacket = new DatagramPacket(requestDataBytes,requestDataBytes.length);//指定接收方的ip地址,由于用的是本机接收,所以可以用localhost//requestPacket.setAddress(InetAddress.getLocalHost());//或者指定接收端具体ip也可以,这里用的是受限的广播地址//requestPacket.setAddress(InetAddress.getByName("255.255.255.255"));//给特定网段广播地址发送requestPacket.setAddress(InetAddress.getByName("192.168.1.255"));//指定接收方的端口号requestPacket.setPort(20000);//开始发送广播ds.send(requestPacket);ds.close();//发送广播完成System.out.println("UDPSearcher sendBroadcast Finished");}/*** 目标设备(UDP提供者)*/private static class Device {final int port;final String ip;final String sn;public Device(int port, String ip, String sn) {this.port = port;this.ip = ip;this.sn = sn;}@Overridepublic String toString() {return "Device{" +"port=" + port +", ip='" + ip + '\'' +", sn='" + sn + '\'' +'}';}}//监听线程private static class Listener extends Thread {private final int listenPort;private final CountDownLatch countDownLatch;private final List<Device> devices = new ArrayList<>();private boolean done = false;private DatagramSocket ds = null;public Listener(int listenPort, CountDownLatch countDownLatch) {super();this.listenPort = listenPort;this.countDownLatch = countDownLatch;}@Overridepublic void run() {super.run();//通知已启动countDownLatch.countDown();try {//监听回送端口ds = new DatagramSocket(listenPort);while (!done) {//构建接收实体final byte[] buf = new byte[512];DatagramPacket receivePack = new DatagramPacket(buf, buf.length);//开始接收ds.receive(receivePack);//打印接收到的信息与发送者的信息String ip = receivePack.getAddress().getHostAddress();//发送者的ipint port = receivePack.getPort();//发送者的端口int dataLen = receivePack.getLength();//数据包长度String data = new String(receivePack.getData(), 0, dataLen);//数据内容System.out.println("UDPSearcher receive from ip:" + ip + "\tport:" + port + "\tdata:" + data);//解析sn并添加设备String sn = MessageCreator.parseSn(data);if (null != sn) {Device device = new Device(port, ip, sn);devices.add(device);}}} catch (Exception e) {} finally {close();}System.out.println("UDPSearcher listener finished");}private void close() {if (null != ds) {ds.close();ds = null;}}List<Device> getDevicesAndClose() {done = true;close();return devices;}}
}

测试

首先开启UDPProvider,用于监听广播并将设备信息发送给搜索者

然后在开启UDPSearcher,用于发送广播并监听自己的特定端口来获取设备信息

可以看到,同时搜索到了2台设备。

UDP之广播搜索局域网内设备信息相关推荐

  1. 利用Messager信使服务在局域网内发信息

    利用Messager信使服务在局域网内发信息在局域网中,我们常常想将一些消息告诉在附近房间的人,除了跑过去说或打电话外,一般情况下,我们都使用QQ类软件,或发电子邮件.但两者都有缺点,电子邮件不是实时 ...

  2. 基于 P2P 技术的 Android 局域网内设备通信实践

    Android 局域网内的多设备通信方式有多种,其中常见的方式有: 基于 TCP/UDP 的 Socket 通信 基于 Bluetooth 的近场通信 基于 Wifi 的 Wi-Fi Direct 连 ...

  3. 利用SMB协议实现局域网内设备文件的共享

    文章目录 参考资料 说明 步骤1:[windows]开启SMB协议 步骤2:[windows]创建新的用户账号 步骤3:[windows]共享文件夹 属性-共享-共享 属性-共享-高级共享 步骤4:[ ...

  4. 使用UDP协议构建简易局域网内聊天室

    实现功能: 客户端 1.开启时输入昵称并往服务器端发送带有客户端昵称 2.开启后能随时往服务器端发送聊天内容 3.收到服务器发来的数据时判别是否为自己发送的数据,若不是则输出num编号所指引的内容 4 ...

  5. Hyper-V虚拟Openwrt软路由拨号后局域网内设备访问上级光猫的方法

    在笔者的另一篇文章<Hyper-V安装lede软路由历程及注意事项>中详细叙述了我在Hyper-V中安装lede(openwrt)软路由的经历.当时部署是通过dhcp方式从上级路由获取ip ...

  6. 获取局域网内服务器信息,使用Java代码获取服务器性能信息及局域网内主机名.pdf...

    使使用用Java代代码码获获取取服服务务器器性性能能信信息息及及局局域域网网内内主主机机名名 最近做个项目,就是要取 cpu 占有率等等的系统信息,一开始以为要用动态链接库了,但后来发现可以像下面这样 ...

  7. Kindle接入HomeAssistant:实现锁屏壁纸显示HA内设备信息并在HA内获取Kindle电量

    快捷目录 前言&前提 文章前提 实现效果 准备工具 HA内设置 创建长期Token 辅助类实体 创建webhook 锁屏壁纸渲染 Docker容器 容器启动参数 OnlineScreensav ...

  8. 搜索局域网内电脑共享文件的方法

    问题: 在本电脑A中网络适配无法找到对方电脑B共享的文件. 解决方法: 在电脑B中按win + R 键,输入cmd,在命令行中输入ipconfig查看IP地址 在电脑B中按win + R 键,输入\你 ...

  9. iOS 局域网内搜索硬件设备

    iOS 局域网搜索可以使用两种方式.第一种方式局域网广播方式.此方式一般在3秒内就会相应.第二种方式也是比较笨拙的方式通过ping方式.这种方式一般是在硬件本身并不支持广播功能.此方法弊端:搜索时间长 ...

最新文章

  1. 后赛门铁克时代Veritas加强数据保护应对欧盟法规
  2. linux tomcat 清空war,Linux下tomcat部署war包
  3. wxWidgets:wxDirPickerCtrl类用法
  4. Java8学习笔记(三)--方法引入
  5. c语言统计数据,数据统计
  6. 新的JMetro JavaFX 11兼容版本
  7. 请编写一个程序,请将字符串中所有字母全部向后移一位,最后一个字母放在字符串的开头,最后将新的字符串输出。
  8. apache ,php,mysql的安装
  9. leetcode3. Longest Substring Without Repeating Characters
  10. 属于我的黑名单公司-传播杀意的地方
  11. linux输入输出重定向详解
  12. Mac小白入门小技巧
  13. 商业洞察力_正在进行的寻求洞察力和远见卓识
  14. Java极简算法-二分查找(log n)
  15. 《离散数学》题库大全及答案
  16. 有趣的github项目
  17. c语言编程悬臂梁受力分析,悬臂梁受力的分析.doc
  18. 火爆全网,搜狐CEO张朝阳手推E=mc²,CEO当太久都忘了他是MIT物理博士
  19. mysql对单引号的模糊查询_SQL语句中的单引号处理以及模糊查询
  20. 简单七个步骤写一份策划方案(上)

热门文章

  1. STM32----FLASH掉电保存动态平衡方案
  2. 安装配置jdk--解压版
  3. c++/MFC CSocket仿QQ聊天软件,实现1对1聊天,群聊
  4. Android初学者仿QQ聊天软件APP (一) 登录界面
  5. 如何获取IMEI号和MEID号
  6. 智能手机 - 黑科技
  7. 小程序助力博物馆餐厅,用“艾”打造品牌
  8. 旧书网购_基于旧书的新工作簿
  9. 北大生命学院邓宏魁课题组最新成果:建立全新胰岛移植策略,解决干细胞治疗糖尿病的关键难题...
  10. 多页面分页打印功能实现