常用的发现方式
1. Wi-Fi配网 + mDNS/Bonjour发现
典型流程:
- 设备开启AP模式或SmartConfig配网
- 连接到家庭Wi-Fi后,通过mDNS广播服务信息
- 手机App扫描局域网内的mDNS服务
- 发现设备后进行配对绑定
Java实现示例:
mDNS/DNS-SD java及Avahi 实现服务发布和服务发现_java mdns-优快云博客
2. 蓝牙发现(BLE)
适用场景:
- 智能手环、手表等穿戴设备
- 近距离配对场景
发现方式:
- BLE广播包携带设备信息
- 手机蓝牙扫描发现设备
- 通过特征UUID识别设备类型
- 提供一个静态网页发现蓝牙的示例(使用 Chrome 浏览器(或基于 Chromium 内核的浏览器,如 Edge)而且需要https才能使用)
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>H5 蓝牙扫描</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
padding: 20px;
background-color: #f4f4f9;
}
.container {
max-width: 600px;
margin: auto;
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
h1 {
color: #333;
}
#scanButton {
background-color: #007bff;
color: white;
border: none;
padding: 10px 20px;
font-size: 16px;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s;
}
#scanButton:hover {
background-color: #0056b3;
}
#deviceList {
margin-top: 20px;
text-align: left;
border-top: 1px solid #eee;
padding-top: 10px;
}
#deviceList p {
background-color: #e9ecef;
padding: 10px;
border-radius: 5px;
margin-bottom: 5px;
word-wrap: break-word;
}
#status {
color: #666;
margin-top: 10px;
}
</style>
</head>
<body>
<div class="container">
<h1>H5 蓝牙扫描器</h1>
<button id="scanButton">开始扫描</button>
<p id="status">点击按钮开始扫描附近的蓝牙设备。</p>
<div id="deviceList"></div>
</div>
<script>
const scanButton = document.getElementById('scanButton');
const deviceList = document.getElementById('deviceList');
const statusElement = document.getElementById('status');
scanButton.addEventListener('click', async () => {
try {
if (!('bluetooth' in navigator)) {
throw new Error('您的浏览器不支持 Web Bluetooth API,请使用 Chrome 等浏览器。');
}
statusElement.textContent = '正在扫描...';
deviceList.innerHTML = '';
// 修改:不使用 services 过滤,而是直接使用 `acceptAllDevices: true`
// 这样可以发现所有附近的 BLE 设备,包括那些没有标准服务 UUID 的设备。
const device = await navigator.bluetooth.requestDevice({
acceptAllDevices: true,
// 将您的设备可能使用的服务作为 optionalServices 添加
optionalServices: ['heart_rate', 'battery_service']
});
if (device) {
statusElement.textContent = `已连接设备:${device.name || '未知设备'} - ${device.id}`;
displayDevice(device.name || '未知设备', device.id);
} else {
statusElement.textContent = '没有发现设备或用户取消了。';
}
} catch (error) {
statusElement.textContent = `扫描失败: ${error.message}`;
console.error(error);
}
});
function displayDevice(name, id) {
const p = document.createElement('p');
p.textContent = `设备名称: ${name}, 设备ID: ${id}`;
deviceList.appendChild(p);
}
</script>
</body>
</html>
3. UDP广播发现
实现方式:
- 设备定期发送UDP广播包
- 包含设备ID、类型、IP等信息
- 客户端监听特定端口接收广播
Java实现(基于Netty框架):
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.31.Final</version>
<scope>compile</scope>
</dependency>
// ==================== 服务端 ====================
package cn.fuzhi.service;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;
import java.net.InetSocketAddress;
/**
* UDP广播服务端
* 监听8888端口,接收广播消息并回复
*/
@Slf4j
public class UdpBroadcastServer {
private final int port;
private EventLoopGroup group;
private Channel channel;
public UdpBroadcastServer(int port) {
this.port = port;
}
/**
* 启动服务端
*/
public void start() {
group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioDatagramChannel.class)
.option(ChannelOption.SO_BROADCAST, true)
.option(ChannelOption.SO_RCVBUF, 2048)
.option(ChannelOption.SO_SNDBUF, 2048)
.handler(new ChannelInitializer<NioDatagramChannel>() {
@Override
protected void initChannel(NioDatagramChannel ch) {
ch.pipeline().addLast(new ServerHandler());
}
});
ChannelFuture future = bootstrap.bind(port).sync();
channel = future.channel();
log.info("UDP广播服务端启动成功,监听端口: {}", port);
// 等待服务器关闭
channel.closeFuture().sync();
} catch (InterruptedException e) {
log.error("UDP服务端异常", e);
Thread.currentThread().interrupt();
} finally {
shutdown();
}
}
/**
* 关闭服务端
*/
public void shutdown() {
if (channel != null) {
channel.close();
}
if (group != null) {
group.shutdownGracefully();
}
log.info("UDP服务端已关闭");
}
/**
* 服务端消息处理器
*/
private static class ServerHandler extends SimpleChannelInboundHandler<DatagramPacket> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) {
// 读取接收到的数据
ByteBuf buf = packet.content();
String message = buf.toString(CharsetUtil.UTF_8);
InetSocketAddress sender = packet.sender();
log.info("收到来自 {}:{} 的消息: {}",
sender.getAddress().getHostAddress(),
sender.getPort(),
message);
// 回复消息
String response = "服务器收到: " + message + " | 时间: " + System.currentTimeMillis();
ByteBuf responseBuf = Unpooled.copiedBuffer(response, CharsetUtil.UTF_8);
DatagramPacket responsePacket = new DatagramPacket(responseBuf, sender);
ctx.writeAndFlush(responsePacket).addListener((ChannelFutureListener) future -> {
if (future.isSuccess()) {
log.info("已回复消息给 {}:{}", sender.getAddress().getHostAddress(), sender.getPort());
} else {
log.error("回复消息失败", future.cause());
}
});
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
log.error("UDP服务端处理异常", cause);
}
@Override
public void channelActive(ChannelHandlerContext ctx) {
log.info("UDP Channel 激活: {}", ctx.channel().localAddress());
}
}
/**
* 主方法 - 启动服务端
*/
public static void main(String[] args) {
UdpBroadcastServer server = new UdpBroadcastServer(8888);
// 添加关闭钩子,优雅关闭
Runtime.getRuntime().addShutdownHook(new Thread(server::shutdown));
server.start();
}
}
// ==================== 客户端 ====================
package cn.fuzhi.service;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;
import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;
/**
* UDP广播客户端测试
* 发送广播消息并接收服务端响应
*/
@Slf4j
public class UdpBroadcastClient {
private final String broadcastAddress;
private final int serverPort;
private EventLoopGroup group;
private Channel channel;
public UdpBroadcastClient(String broadcastAddress, int serverPort) {
this.broadcastAddress = broadcastAddress;
this.serverPort = serverPort;
}
/**
* 启动客户端
*/
public void start() {
group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioDatagramChannel.class)
.option(ChannelOption.SO_BROADCAST, true)
.option(ChannelOption.SO_RCVBUF, 2048)
.option(ChannelOption.SO_SNDBUF, 2048)
.handler(new ChannelInitializer<NioDatagramChannel>() {
@Override
protected void initChannel(NioDatagramChannel ch) {
ch.pipeline().addLast(new ClientHandler());
}
});
// 绑定任意端口(0表示系统自动分配)
channel = bootstrap.bind(0).sync().channel();
log.info("UDP客户端启动成功,本地端口: {}", channel.localAddress());
} catch (InterruptedException e) {
log.error("UDP客户端启动异常", e);
Thread.currentThread().interrupt();
}
}
/**
* 发送广播消息
*/
public void sendBroadcast(String message) {
if (channel == null || !channel.isActive()) {
log.error("Channel未激活,无法发送消息");
return;
}
ByteBuf buf = Unpooled.copiedBuffer(message, CharsetUtil.UTF_8);
InetSocketAddress broadcast = new InetSocketAddress(broadcastAddress, serverPort);
DatagramPacket packet = new DatagramPacket(buf, broadcast);
channel.writeAndFlush(packet).addListener((ChannelFutureListener) future -> {
if (future.isSuccess()) {
log.info("广播消息发送成功: {} -> {}:{}", message, broadcastAddress, serverPort);
} else {
log.error("广播消息发送失败", future.cause());
}
});
}
/**
* 关闭客户端
*/
public void shutdown() {
if (channel != null) {
channel.close();
}
if (group != null) {
group.shutdownGracefully();
}
log.info("UDP客户端已关闭");
}
/**
* 客户端消息处理器
*/
private static class ClientHandler extends SimpleChannelInboundHandler<DatagramPacket> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) {
ByteBuf buf = packet.content();
String message = buf.toString(CharsetUtil.UTF_8);
InetSocketAddress sender = packet.sender();
log.info("收到来自 {}:{} 的响应: {}",
sender.getAddress().getHostAddress(),
sender.getPort(),
message);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
log.error("UDP客户端处理异常", cause);
}
@Override
public void channelActive(ChannelHandlerContext ctx) {
log.info("UDP客户端 Channel 激活: {}", ctx.channel().localAddress());
}
}
/**
* 主方法 - 测试客户端
*/
public static void main(String[] args) throws InterruptedException {
UdpBroadcastClient client = new UdpBroadcastClient("255.255.255.255", 8888);
// 启动客户端
client.start();
// 等待1秒确保启动完成
TimeUnit.SECONDS.sleep(1);
// 发送多条广播消息测试
client.sendBroadcast("DISCOVER_REQUEST");
TimeUnit.SECONDS.sleep(2);
client.sendBroadcast("PING");
TimeUnit.SECONDS.sleep(2);
client.sendBroadcast("HELLO_SERVER");
// 等待10秒接收响应
log.info("等待接收响应,10秒后自动关闭...");
TimeUnit.SECONDS.sleep(10);
// 关闭客户端
client.shutdown();
}
}
服务端日志:

客户端端日志:

4. 二维码 + 云端注册
流程:
- 设备生成包含设备ID的二维码
- 用户扫码获取设备信息
- App通过云端API查询设备状态和连接信息
- 建立P2P连接或通过云端中转
5. NFC近场发现
应用场景:
- 高端穿戴设备
- 需要物理接触的安全配对
6. 音频配网发现
声波配网:
- 设备通过扬声器发出特定频率声波
- 手机麦克风接收解析获得设备信息
- 常见于智能音箱等设备
实际产品案例
小米摄像头:
- Wi-Fi配网 + mDNS发现
- 手机热点直连模式
Apple Watch:
- 蓝牙配对 + 二维码辅助
海康威视摄像头:
- SADP协议(基于UDP广播)
- 设备发现和参数配置
大疆无人机:
- Wi-Fi Direct连接
- UDP广播设备信息
技术选择建议
摄像头类设备:
- 首选:mDNS + Wi-Fi配网
- 备选:UDP广播发现
- 辅助:二维码配置
穿戴设备:
- 首选:BLE广播发现
- 辅助:NFC配对(高端设备)
智能家居设备:
- mDNS/Bonjour(局域网内)
- 云端注册表(跨网络访问)
这些方案通常会组合使用,比如先通过蓝牙或二维码建立初始连接,再通过Wi-Fi进行数据传输,最后通过云端服务实现远程访问。
按连接方式分类的应用场景
Wi-Fi连接设备 → mDNS/Bonjour发现
适用设备:
- 智能摄像头(小米、海康威视、大华等)
- 智能音箱(天猫精灵、小度、Echo)
- 智能电视、投影仪
- 路由器、网络存储设备
蓝牙连接设备 → BLE广播发现
适用设备:
- 穿戴设备(Apple Watch、小米手环、华为手表)
- 蓝牙耳机、音箱
- 智能门锁(部分配对阶段)
- 健康监测设备
技术特点: 蓝牙在IoT中扮演关键角色,帮助设备更容易地相互通信,使我们的家庭更智能,健康监测更高效
NFC连接设备 → NFC近场发现
适用设备:
- 高端智能手表(Apple Watch Ultra)
- 智能门锁(高端型号)
- 支付设备、门禁卡
- 智能标签
应用场景: 主要用于安全配对和快速配置
有线连接设备 → mDNS/SSDP发现
适用设备:
- 网络摄像头(PoE供电)
- 工业IoT设备
- 智能网关
- 网络存储设备
市场主流选择分析
消费级设备(占市场70%+)
-
智能家居设备:90%采用Wi-Fi + mDNS
- 小米全家桶、华为HiLink、天猫精灵生态
-
穿戴设备:95%采用蓝牙发现
- Apple Watch、华为GT系列、小米手环
-
智能音箱:混合方式
- 初始配对:蓝牙
- 正常使用:Wi-Fi + mDNS
企业级设备(占市场30%)
- 安防监控:有线网络 + ONVIF协议
- 工业IoT:有线为主,无线为辅
- 智能办公:Wi-Fi + 企业级发现协议
实际产品选择策略
按设备类型分类
固定式设备(摄像头、音箱)
Wi-Fi配网 → mDNS发现 → 云端注册
成功率:95%+
移动式设备(手表、耳机)
蓝牙配对 → 服务发现 → 数据同步
成功率:90%+
安全要求高的设备
NFC配对 → 蓝牙/Wi-Fi传输 → 云端验证
成功率:99%+
技术组合使用
典型组合1:智能摄像头
- 配网:Wi-Fi SmartConfig
- 发现:mDNS/Bonjour
- 远程访问:云端P2P
典型组合2:智能手表
- 初始配对:NFC(高端)或二维码
- 数据传输:蓝牙BLE
- 云端同步:Wi-Fi/蜂窝网络
典型组合3:智能门锁
- 近场配置:NFC
- 日常通信:蓝牙
- 远程管理:Wi-Fi
java场景模拟
创建一个完整的Java模拟系统,包含设备端、云端服务发现和数据传输功能。我为你创建了一个完整的IoT设备云端发现与数据传输模拟系统。这个系统包含以下核心组件:
系统架构
1. 云端服务注册中心 (CloudServiceRegistry)
- 设备注册管理
- 设备发现功能
- 心跳检测机制
- 在线状态维护
2. 云端数据服务器 (CloudDataServer)
- 处理设备连接
- 接收传感器数据
- 设备注册处理
- 服务发现响应
3. IoT设备模拟器 (IoTDeviceSimulator)
- 模拟真实IoT设备
- 自动注册到云端
- 定期发送心跳
- 传输传感器数据
主要功能特性
设备发现机制
- 设备启动时自动注册到云端
- 支持按设备类型过滤发现
- 实时状态监控(在线/离线)
数据传输
- JSON格式数据交换
- 多种传感器数据类型
- 异步数据处理
- 历史数据存储
心跳监控
- 定期心跳检测
- 自动离线检测
- 连接状态管理
模拟设备类型
系统预设了5种常见IoT设备:
- 摄像头 - 发送运动检测数据
- 温度传感器 - 发送温度数据
- 智能手表 - 发送心率数据
- 智能门锁 - 发送锁定状态
运行效果
系统运行时会显示:
- 设备注册成功消息
- 实时传感器数据接收
- 定期设备状态列表
- 心跳和连接状态
技术要点
- 并发处理:使用线程池处理多设备连接
- JSON通信:使用Gson进行数据序列化
- 心跳机制:确保设备连接可靠性
- 状态管理:实时监控设备在线状态
这个系统完整模拟了IoT设备从发现、注册到数据传输的全流程,是学习和理解IoT云端架构的很好示例。可以基于这个框架扩展更多功能,比如设备控制、数据分析、告警机制等。
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;
import java.text.SimpleDateFormat;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
// 设备信息模型
class DeviceInfo {
private String deviceId;
private String deviceType;
private String name;
private String ipAddress;
private int port;
private String status;
private long lastHeartbeat;
private Map<String, Object> properties;
public DeviceInfo(String deviceId, String deviceType, String name, String ipAddress, int port) {
this.deviceId = deviceId;
this.deviceType = deviceType;
this.name = name;
this.ipAddress = ipAddress;
this.port = port;
this.status = "online";
this.lastHeartbeat = System.currentTimeMillis();
this.properties = new HashMap<>();
}
// Getters and Setters
public String getDeviceId() { return deviceId; }
public String getDeviceType() { return deviceType; }
public String getName() { return name; }
public String getIpAddress() { return ipAddress; }
public int getPort() { return port; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public long getLastHeartbeat() { return lastHeartbeat; }
public void setLastHeartbeat(long lastHeartbeat) { this.lastHeartbeat = lastHeartbeat; }
public Map<String, Object> getProperties() { return properties; }
}
// 传感器数据模型
class SensorData {
private String deviceId;
private String dataType;
private Object value;
private long timestamp;
public SensorData(String deviceId, String dataType, Object value) {
this.deviceId = deviceId;
this.dataType = dataType;
this.value = value;
this.timestamp = System.currentTimeMillis();
}
// Getters
public String getDeviceId() { return deviceId; }
public String getDataType() { return dataType; }
public Object getValue() { return value; }
public long getTimestamp() { return timestamp; }
}
// 云端服务注册中心
class CloudServiceRegistry {
private Map<String, DeviceInfo> registeredDevices;
private ExecutorService executor;
private Gson gson;
private static final long HEARTBEAT_TIMEOUT = 30000; // 30秒超时
public CloudServiceRegistry() {
this.registeredDevices = new ConcurrentHashMap<>();
this.executor = Executors.newCachedThreadPool();
this.gson = new GsonBuilder().setPrettyPrinting().create();
// 启动心跳检查定时任务
startHeartbeatChecker();
}
// 设备注册
public synchronized boolean registerDevice(DeviceInfo device) {
try {
registeredDevices.put(device.getDeviceId(), device);
System.out.println("✅ 设备注册成功: " + device.getName() + " [" + device.getDeviceId() + "]");
System.out.println(" 类型: " + device.getDeviceType() + ", 地址: " + device.getIpAddress() + ":" + device.getPort());
return true;
} catch (Exception e) {
System.err.println("❌ 设备注册失败: " + e.getMessage());
return false;
}
}
// 设备发现
public List<DeviceInfo> discoverDevices(String deviceType) {
List<DeviceInfo> devices = new ArrayList<>();
for (DeviceInfo device : registeredDevices.values()) {
if (deviceType == null || deviceType.equals("all") || device.getDeviceType().equals(deviceType)) {
if ("online".equals(device.getStatus())) {
devices.add(device);
}
}
}
return devices;
}
// 更新设备心跳
public void updateHeartbeat(String deviceId) {
DeviceInfo device = registeredDevices.get(deviceId);
if (device != null) {
device.setLastHeartbeat(System.currentTimeMillis());
device.setStatus("online");
}
}
// 心跳检查器
private void startHeartbeatChecker() {
executor.submit(() -> {
while (true) {
try {
long currentTime = System.currentTimeMillis();
for (DeviceInfo device : registeredDevices.values()) {
if (currentTime - device.getLastHeartbeat() > HEARTBEAT_TIMEOUT) {
if ("online".equals(device.getStatus())) {
device.setStatus("offline");
System.out.println("⚠️ 设备离线: " + device.getName() + " [" + device.getDeviceId() + "]");
}
}
}
Thread.sleep(10000); // 每10秒检查一次
} catch (InterruptedException e) {
break;
}
}
});
}
// 获取设备列表
public void printDeviceList() {
System.out.println("\n📋 当前注册设备列表:");
System.out.println("----------------------------------------");
if (registeredDevices.isEmpty()) {
System.out.println("暂无注册设备");
} else {
for (DeviceInfo device : registeredDevices.values()) {
String statusIcon = "online".equals(device.getStatus()) ? "🟢" : "🔴";
System.out.printf("%s %s [%s] - %s:%d (%s)\n",
statusIcon, device.getName(), device.getDeviceId(),
device.getIpAddress(), device.getPort(), device.getDeviceType());
}
}
System.out.println("----------------------------------------\n");
}
}
// 云端数据服务器
class CloudDataServer {
private int port;
private ServerSocket serverSocket;
private CloudServiceRegistry registry;
private ExecutorService executor;
private List<SensorData> dataHistory;
private Gson gson;
public CloudDataServer(int port, CloudServiceRegistry registry) {
this.port = port;
this.registry = registry;
this.executor = Executors.newCachedThreadPool();
this.dataHistory = Collections.synchronizedList(new ArrayList<>());
this.gson = new GsonBuilder().setPrettyPrinting().create();
}
public void start() {
try {
serverSocket = new ServerSocket(port);
System.out.println("☁️ 云端数据服务器启动,监听端口: " + port);
while (!serverSocket.isClosed()) {
Socket clientSocket = serverSocket.accept();
executor.submit(new ClientHandler(clientSocket));
}
} catch (IOException e) {
if (!serverSocket.isClosed()) {
System.err.println("❌ 云端服务器错误: " + e.getMessage());
}
}
}
private class ClientHandler implements Runnable {
private Socket socket;
private BufferedReader reader;
private PrintWriter writer;
public ClientHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
writer = new PrintWriter(socket.getOutputStream(), true);
String message;
while ((message = reader.readLine()) != null) {
handleMessage(message);
}
} catch (IOException e) {
System.err.println("客户端连接异常: " + e.getMessage());
} finally {
try {
socket.close();
} catch (IOException e) {
// ignore
}
}
}
private void handleMessage(String message) {
try {
Map<String, Object> data = gson.fromJson(message, Map.class);
String type = (String) data.get("type");
switch (type) {
case "register":
handleDeviceRegistration(data);
break;
case "heartbeat":
handleHeartbeat(data);
break;
case "data":
handleSensorData(data);
break;
case "discovery":
handleDeviceDiscovery(data);
break;
default:
writer.println(gson.toJson(Map.of("status", "error", "message", "Unknown message type")));
}
} catch (Exception e) {
writer.println(gson.toJson(Map.of("status", "error", "message", e.getMessage())));
}
}
private void handleDeviceRegistration(Map<String, Object> data) {
String deviceId = (String) data.get("deviceId");
String deviceType = (String) data.get("deviceType");
String name = (String) data.get("name");
String ipAddress = socket.getInetAddress().getHostAddress();
int port = ((Double) data.get("port")).intValue();
DeviceInfo device = new DeviceInfo(deviceId, deviceType, name, ipAddress, port);
boolean success = registry.registerDevice(device);
Map<String, Object> response = new HashMap<>();
response.put("status", success ? "success" : "error");
response.put("message", success ? "Device registered successfully" : "Registration failed");
writer.println(gson.toJson(response));
}
private void handleHeartbeat(Map<String, Object> data) {
String deviceId = (String) data.get("deviceId");
registry.updateHeartbeat(deviceId);
writer.println(gson.toJson(Map.of("status", "ok")));
}
private void handleSensorData(Map<String, Object> data) {
String deviceId = (String) data.get("deviceId");
String dataType = (String) data.get("dataType");
Object value = data.get("value");
SensorData sensorData = new SensorData(deviceId, dataType, value);
dataHistory.add(sensorData);
// 限制历史数据数量
if (dataHistory.size() > 1000) {
dataHistory.remove(0);
}
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
System.out.println("📊 收到数据: [" + deviceId + "] " + dataType + " = " + value +
" (时间: " + sdf.format(new Date(sensorData.getTimestamp())) + ")");
writer.println(gson.toJson(Map.of("status", "received")));
}
private void handleDeviceDiscovery(Map<String, Object> data) {
String deviceType = (String) data.get("deviceType");
List<DeviceInfo> devices = registry.discoverDevices(deviceType);
Map<String, Object> response = new HashMap<>();
response.put("status", "success");
response.put("devices", devices);
writer.println(gson.toJson(response));
}
}
public void stop() {
try {
if (serverSocket != null && !serverSocket.isClosed()) {
serverSocket.close();
}
executor.shutdown();
} catch (IOException e) {
System.err.println("停止服务器时出错: " + e.getMessage());
}
}
}
// IoT设备模拟器
class IoTDeviceSimulator {
private String deviceId;
private String deviceType;
private String name;
private String cloudServerHost;
private int cloudServerPort;
private int localPort;
private Socket cloudSocket;
private PrintWriter cloudWriter;
private BufferedReader cloudReader;
private ScheduledExecutorService scheduler;
private Random random;
private Gson gson;
private boolean isConnected;
public IoTDeviceSimulator(String deviceId, String deviceType, String name,
String cloudServerHost, int cloudServerPort, int localPort) {
this.deviceId = deviceId;
this.deviceType = deviceType;
this.name = name;
this.cloudServerHost = cloudServerHost;
this.cloudServerPort = cloudServerPort;
this.localPort = localPort;
this.scheduler = Executors.newScheduledThreadPool(2);
this.random = new Random();
this.gson = new GsonBuilder().setPrettyPrinting().create();
this.isConnected = false;
}
public void start() {
try {
// 连接到云端服务器
connectToCloud();
// 注册设备
registerToCloud();
// 启动心跳
startHeartbeat();
// 启动数据发送
startDataTransmission();
System.out.println("🔌 设备启动成功: " + name + " [" + deviceId + "]");
} catch (Exception e) {
System.err.println("❌ 设备启动失败: " + e.getMessage());
}
}
private void connectToCloud() throws IOException {
cloudSocket = new Socket(cloudServerHost, cloudServerPort);
cloudWriter = new PrintWriter(cloudSocket.getOutputStream(), true);
cloudReader = new BufferedReader(new InputStreamReader(cloudSocket.getInputStream()));
isConnected = true;
}
private void registerToCloud() throws IOException {
Map<String, Object> registerData = new HashMap<>();
registerData.put("type", "register");
registerData.put("deviceId", deviceId);
registerData.put("deviceType", deviceType);
registerData.put("name", name);
registerData.put("port", localPort);
cloudWriter.println(gson.toJson(registerData));
String response = cloudReader.readLine();
System.out.println("📝 注册响应: " + response);
}
private void startHeartbeat() {
scheduler.scheduleAtFixedRate(() -> {
if (isConnected) {
try {
Map<String, Object> heartbeatData = new HashMap<>();
heartbeatData.put("type", "heartbeat");
heartbeatData.put("deviceId", deviceId);
cloudWriter.println(gson.toJson(heartbeatData));
cloudReader.readLine(); // 读取响应
} catch (Exception e) {
System.err.println("💓 心跳发送失败: " + e.getMessage());
isConnected = false;
}
}
}, 5, 10, TimeUnit.SECONDS);
}
private void startDataTransmission() {
scheduler.scheduleAtFixedRate(() -> {
if (isConnected) {
try {
sendSensorData();
} catch (Exception e) {
System.err.println("📡 数据发送失败: " + e.getMessage());
}
}
}, 2, 5, TimeUnit.SECONDS);
}
private void sendSensorData() throws IOException {
Map<String, Object> sensorData = new HashMap<>();
sensorData.put("type", "data");
sensorData.put("deviceId", deviceId);
// 根据设备类型生成不同的传感器数据
switch (deviceType) {
case "camera":
sensorData.put("dataType", "motion_detected");
sensorData.put("value", random.nextBoolean());
break;
case "temperature_sensor":
sensorData.put("dataType", "temperature");
sensorData.put("value", 20 + random.nextDouble() * 15); // 20-35度
break;
case "smart_watch":
sensorData.put("dataType", "heart_rate");
sensorData.put("value", 60 + random.nextInt(40)); // 60-100 BPM
break;
case "smart_lock":
sensorData.put("dataType", "lock_status");
sensorData.put("value", random.nextBoolean() ? "locked" : "unlocked");
break;
default:
sensorData.put("dataType", "status");
sensorData.put("value", "active");
}
cloudWriter.println(gson.toJson(sensorData));
cloudReader.readLine(); // 读取响应
}
public void stop() {
try {
isConnected = false;
scheduler.shutdown();
if (cloudSocket != null && !cloudSocket.isClosed()) {
cloudSocket.close();
}
System.out.println("🔌 设备已停止: " + name);
} catch (IOException e) {
System.err.println("停止设备时出错: " + e.getMessage());
}
}
}
// 主程序
public class IoTCloudSystem {
public static void main(String[] args) {
System.out.println("🌐 IoT设备云端发现与数据传输模拟系统");
System.out.println("=====================================");
// 创建云端服务注册中心
CloudServiceRegistry registry = new CloudServiceRegistry();
// 创建云端数据服务器
CloudDataServer cloudServer = new CloudDataServer(8080, registry);
// 在新线程中启动云端服务器
new Thread(() -> cloudServer.start()).start();
// 等待服务器启动
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// 创建并启动IoT设备模拟器
List<IoTDeviceSimulator> devices = new ArrayList<>();
// 摄像头设备
devices.add(new IoTDeviceSimulator("CAM_001", "camera", "客厅摄像头", "localhost", 8080, 9001));
devices.add(new IoTDeviceSimulator("CAM_002", "camera", "门口摄像头", "localhost", 8080, 9002));
// 温度传感器
devices.add(new IoTDeviceSimulator("TEMP_001", "temperature_sensor", "卧室温度传感器", "localhost", 8080, 9003));
// 智能手表
devices.add(new IoTDeviceSimulator("WATCH_001", "smart_watch", "小明的智能手表", "localhost", 8080, 9004));
// 智能门锁
devices.add(new IoTDeviceSimulator("LOCK_001", "smart_lock", "前门智能门锁", "localhost", 8080, 9005));
// 启动所有设备
for (IoTDeviceSimulator device : devices) {
device.start();
try {
Thread.sleep(1000); // 间隔启动
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
// 定期显示设备列表
ScheduledExecutorService statusScheduler = Executors.newScheduledThreadPool(1);
statusScheduler.scheduleAtFixedRate(() -> {
registry.printDeviceList();
}, 10, 15, TimeUnit.SECONDS);
// 运行30秒后停止
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("\n🛑 正在停止系统...");
// 停止所有设备
for (IoTDeviceSimulator device : devices) {
device.stop();
}
// 停止服务器
cloudServer.stop();
statusScheduler.shutdown();
System.out.println("✅ 系统已停止");
}
}
2984

被折叠的 条评论
为什么被折叠?



