物联网服务器搭建及部署详细说明:掌握 Node.js、MongoDB、Socket.IO 和 JWT 的实用指南

news2025/1/10 17:17:51

关键知识点目录

1. 环境准备

1.1 硬件要求

1.2 软件要求

2. 搭建步骤

3. 数据处理与存储

3.1 数据存储

3.2 数据实时处理

3.2.1 安装 Socket.IO

3.2.2 修改服务器代码

4. 安全性

4.1 身份验证与授权

4.2 加密通信

4.2.1 生成自签名证书(开发环境)

4.2.2 修改服务器以支持 HTTPS

5. 数据分析和可视化

5.1 集成 Grafana

5.2.2 图表数据更新

6. 事件处理与报警

6.1 事件检测

7. 接口与集成

7.1 提供 RESTful API

7.1.1 获取所有设备数据

8. 日志与监控

8.1 日志记录

8.2 系统监控

9. 用户管理

9.1 用户角色和权限管理

9.1.1 修改用户模型

9.1.2 修改用户注册接口

9.2 权限控制

9.2.1 创建中间件进行权限检查

9.2.2 修改删除设备接口

9.3 审计和跟踪

9.3.1 修改用户注册接口

9.3.2 修改用户登录接口


物联网(IoT)正在以惊人的速度发展,越来越多的设备连接到互联网。搭建一个物联网服务器是实现设备管理、数据处理和安全性的关键。本文将详细介绍搭建物联网服务器的过程,包括所需的步骤、代码示例和相关工具。

1. 环境准备

在开始搭建物联网服务器之前,确保你的开发环境已准备好。

1.1 硬件要求

  • 服务器:可以使用物理服务器或云服务器(如AWS、Azure、阿里云)。
  • 开发设备:可以是树莓派、Arduino等物联网设备。

1.2 软件要求

  • 操作系统:Ubuntu 20.04或更高版本。
  • 数据库:MySQL或MongoDB。
  • 编程语言:Node.js、Python或Java。
  • 工具:Docker(可选)、Postman(用于测试API)。

2. 搭建步骤

2.1 安装必要的软件

首先,更新系统并安装Node.js和MongoDB。

# 更新系统
sudo apt update && sudo apt upgrade -y

# 安装 Node.js
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt install -y nodejs

# 安装 MongoDB
sudo apt install -y mongodb

2.2 创建项目目录

创建一个项目目录并初始化Node.js应用。

# 创建项目目录
mkdir IoTServer
cd IoTServer

# 初始化Node.js项目
npm init -y

2.3 安装依赖包

安装必要的依赖包,如Express.js(用于构建API)和Mongoose(用于MongoDB交互)。

npm install express mongoose body-parser cors

2.4 编写服务器代码

创建一个名为server.js的文件,并编写基础的Express.js服务器代码。

// server.js
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const cors = require('cors');

const app = express();
const PORT = process.env.PORT || 3000;

// 连接到MongoDB数据库
mongoose.connect('mongodb://localhost:27017/iot', {
    useNewUrlParser: true,
    useUnifiedTopology: true
}).then(() => {
    console.log('MongoDB connected');
}).catch(err => {
    console.error('MongoDB connection error:', err);
});

// 中间件
app.use(cors());
app.use(bodyParser.json());

// 设备模型
const DeviceSchema = new mongoose.Schema({
    name: String,
    type: String,
    status: String
});
const Device = mongoose.model('Device', DeviceSchema);

// 设备注册接口
app.post('/api/devices', async (req, res) => {
    const device = new Device(req.body);
    await device.save();
    res.status(201).send(device);
});

// 启动服务器
app.listen(PORT, () => {
    console.log(`Server is running on http://localhost:${PORT}`);
});

2.5 启动服务器

运行服务器代码,确保没有错误。

node server.js

你应该会看到“Server is running on http://localhost:3000”的消息。

2.6 测试设备注册接口

使用Postman或curl测试设备注册接口。

Postman配置

  • 方法:POST
  • URLhttp://localhost:3000/api/devices
  • Body(JSON格式):
{
    "name": "温度传感器",
    "type": "传感器",
    "status": "在线"
}

点击“Send”,如果一切正常,你将收到新设备的响应。

3. 数据处理与存储

3.1 数据存储

在上述代码中,我们已经使用MongoDB存储设备数据。你可以根据需求添加更多数据处理的功能。

3.2 数据实时处理

为了实现实时数据处理功能,我们将使用 Socket.IO 来实现设备与服务器之间的双向通信。这允许设备在数据发生变化时立即将数据发送到服务器,服务器也可以实时向设备推送消息。

3.2.1 安装 Socket.IO

如果你还没有安装 Socket.IO,可以通过以下命令进行安装:

npm install socket.io

3.2.2 修改服务器代码

在 server.js 文件中,我们已经导入了 Socket.IO。接下来,我们需要修改服务器代码以支持实时数据传输。以下是更新后的代码:

const http = require('http');
const socketIo = require('socket.io');

// 创建 HTTP 服务器
const server = http.createServer(app);
const io = socketIo(server);

// 监听连接
io.on('connection', (socket) => {
    console.log('A device connected:', socket.id);
    
    // 监听来自设备的数据
    socket.on('data', async (data) => {
        console.log('Received data:', data);
        
        // 在这里可以进行数据处理或存储
        // 例如:将数据存入数据库
        const deviceData = new Device(data);
        await deviceData.save();
        
        // 向所有连接的客户端广播接收到的数据
        io.emit('data', deviceData);
    });

    // 监听断开连接
    socket.on('disconnect', () => {
        console.log('Device disconnected:', socket.id);
    });
});

// 启动服务器
server.listen(PORT, () => {
    console.log(`Server is running on http://localhost:${PORT}`);
});

3.2.3 客户端代码示例

为了让设备能够发送数据并接收实时更新,我们需要在设备端实现Socket.IO客户端。以下是一个简单的客户端示例代码(假设设备使用 Node.js):

// device.js
const io = require('socket.io-client');
const socket = io('http://localhost:3000');

// 模拟设备数据
setInterval(() => {
    const deviceData = {
        name: '温度传感器',
        type: '传感器',
        status: '在线',
        value: Math.random() * 100 // 随机生成温度值
    };
    
    // 发送数据到服务器
    socket.emit('data', deviceData);
}, 5000); // 每5秒发送一次数据

// 监听服务器广播的数据
socket.on('data', (data) => {
    console.log('Data received from server:', data);
});

3.2.4 启动设备客户端

在设备端运行上述代码,以便模拟设备向服务器发送数据。你可以在多个终端中运行多个设备客户端,以模拟多个设备同时连接。

node device.js

这将每5秒随机发送一次温度数据到服务器,并在接收到服务器的广播消息时输出信息。

4. 安全性

安全性是物联网系统非常重要的一部分。为了确保系统的安全性,我们可以实现身份验证、加密通信和定期更新。

4.1 身份验证与授权

为确保只有授权设备能够连接到服务器,可以使用 JWT(JSON Web Token)进行身份验证。以下是如何实现基本的 JWT 身份验证。

首先,安装必要的库:

npm install jsonwebtoken bcryptjs

然后,在 server.js 中添加以下代码:

const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');

const SECRET_KEY = 'your_secret_key'; // 应该存储在环境变量中

// 用户模型(示例)
const UserSchema = new mongoose.Schema({
    username: String,
    password: String
});
const User = mongoose.model('User', UserSchema);

// 用户注册接口
app.post('/api/register', async (req, res) => {
    const { username, password } = req.body;
    const hashedPassword = await bcrypt.hash(password, 10);
    const user = new User({ username, password: hashedPassword });
    await user.save();
    res.status(201).send('User registered');
});

// 用户登录接口
app.post('/api/login', async (req, res) => {
    const { username, password } = req.body;
    const user = await User.findOne({ username });
    if (!user || !await bcrypt.compare(password, user.password)) {
        return res.status(401).send('Invalid credentials');
    }
    const token = jwt.sign({ id: user._id }, SECRET_KEY, { expiresIn: '1h' });
    res.status(200).json({ token });
});

// 中间件:验证JWT
const authenticateJWT = (req, res, next) => {
    const token = req.headers['authorization'];
    if (token) {
        jwt.verify(token, SECRET_KEY, (err, user) => {
            if (err) {
                return res.sendStatus(403);
            }
            req.user = user;
            next();
        });
    } else {
        res.sendStatus(401);
    }
};

// 保护的设备注册接口
app.post('/api/devices', authenticateJWT, async (req, res) => {
    const device = new Device(req.body);
    await device.save();
    res.status(201).send(device);
});

4.2 加密通信

为了确保数据在传输过程中的安全性,我们将使用 HTTPS。以下是如何设置 HTTPS 的步骤。

首先,您需要 SSL 证书。可以使用自签名证书来进行开发和测试,或者使用 Let's Encrypt 获取免费的证书。

4.2.1 生成自签名证书(开发环境)
# 生成 SSL 证书和密钥
openssl req -nodes -new -x509 -keyout server.key -out server.cert
4.2.2 修改服务器以支持 HTTPS

在 server.js 中,我们将使用HTTPS模块来创建服务器。

const https = require('https');
const fs = require('fs');

// 读取证书和密钥
const privateKey = fs.readFileSync('server.key', 'utf8');
const certificate = fs.readFileSync('server.cert', 'utf8');

const credentials = { key: privateKey, cert: certificate };

// 创建 HTTPS 服务器
const httpsServer = https.createServer(credentials, app);

// 启动 HTTPS 服务器
httpsServer.listen(PORT, () => {
    console.log(`Server is running on https://localhost:${PORT}`);
});

5. 数据分析和可视化

在物联网应用中,数据分析和可视化可以帮助用户理解和利用数据。我们可以使用第三方库或工具来实现数据分析和可视化,以下是一些常用的工具:

  • Grafana:用于监控和可视化时序数据。
  • Chart.js:在前端展示实时数据图表。
  • D3.js:用于复杂的数据可视化。
5.1 集成 Grafana

Grafana 是一个开源的分析和监控平台,可以通过连接到数据库(如 MongoDB)来可视化数据。

  1. 安装 Grafana

    sudo apt install -y grafana
    
  2. 启动 Grafana

    sudo systemctl start grafana-server
    sudo systemctl enable grafana-server
    
  3. 访问 Grafana:在浏览器中访问 http://localhost:3000,默认用户名和密码均为 admin

  4. 添加数据源:在 Grafana 中添加 MongoDB 数据源,并配置它以连接到你的 MongoDB 实例。

  5. 创建仪表盘:通过查询 MongoDB 数据,创建可视化面板,展示传感器数据。

5.2 使用 Chart.js

如果你希望在前端应用中可视化数据,可以使用 Chart.js。以下是一个简单的示例,展示如何使用 Chart.js 来展示实时数据。

在前端应用中,我们将创建一个实时更新的图表,展示从服务器接收到的温度数据。

5.2.1 创建HTML结构

在你的HTML文件中,添加一个<canvas>元素来显示图表。以下是一个完整的HTML示例:

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>实时温度数据可视化</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
    <h1>实时温度数据</h1>
    <canvas id="myChart" width="400" height="200"></canvas>
    
    <script src="/socket.io/socket.io.js"></script>
    <script>
        const socket = io('http://localhost:3000'); // 连接到服务器
        const ctx = document.getElementById('myChart').getContext('2d');
        
        const labels = []; // 存储时间标签
        const dataPoints = []; // 存储实时数据

        const myChart = new Chart(ctx, {
            type: 'line',
            data: {
                labels: labels,
                datasets: [{
                    label: '温度数据',
                    data: dataPoints,
                    borderColor: 'rgba(75, 192, 192, 1)',
                    borderWidth: 1,
                    fill: false
                }]
            },
            options: {
                scales: {
                    x: {
                        type: 'linear',
                        position: 'bottom'
                    }
                }
            }
        });

        // 监听服务器发送的数据
        socket.on('data', (data) => {
            // 假设数据格式为 { value: 温度值, timestamp: 时间戳 }
            const timestamp = new Date().toLocaleTimeString();
            labels.push(timestamp);
            dataPoints.push(data.value);

            // 更新图表
            myChart.update();
        });
    </script>
</body>
</html>

5.2.2 图表数据更新

这个示例中,我们使用 Socket.IO 实时接收数据,并将其添加到图表中。我们假设服务器发送的数据的格式如下:

{
    "value": 25.5 // 温度值
}

在客户端代码中,我们通过监听 socket.on('data', ...) 来接收服务器发送的实时数据,并将数据点和时间标签添加到 Chart.js 图表的数据集中。调用 myChart.update() 方法来更新图表。

6. 事件处理与报警

为了确保系统能够及时处理异常事件并进行报警,我们可以实现一个简单的事件处理系统。

6.1 事件检测

在服务端,我们可以设置一个阈值,并在接收到数据后检查数据是否超出这个阈值。

// 设定温度阈值
const TEMPERATURE_THRESHOLD = 75;

// 监听来自设备的数据
socket.on('data', async (data) => {
    console.log('Received data:', data);

    // 检查温度是否超出阈值
    if (data.value > TEMPERATURE_THRESHOLD) {
        console.log('Warning: Temperature exceeds threshold!', data.value);
        // 发送报警通知
        io.emit('alert', { message: 'Temperature exceeds threshold!', value: data.value });
    }

    // 存储数据
    const deviceData = new Device(data);
    await deviceData.save();

    // 向所有连接的客户端广播接收到的数据
    io.emit('data', deviceData);
});
6.2 报警系统

在客户端,我们也可以监听 alert 事件,并根据需要做出响应。

// 监听报警事件
socket.on('alert', (alert) => {
    alertUser(alert.message, alert.value);
});

// 简单的报警通知函数
function alertUser(message, value) {
    alert(`报警: ${message} 当前温度: ${value}`);
}

7. 接口与集成

为了让第三方系统能够集成到我们的物联网平台,我们需要提供丰富的 API 接口。

7.1 提供 RESTful API

我们已经实现了一些基础的 API 接口,接下来我们将添加获取所有设备、更新设备状态和删除设备的接口。

7.1.1 获取所有设备数据

添加一个 API 接口以获取所有已注册设备的数据。我们将在 server.js 中添加如下代码:

// 获取所有设备数据
app.get('/api/devices', authenticateJWT, async (req, res) => {
    try {
        const devices = await Device.find();
        res.status(200).json(devices);
    } catch (error) {
        res.status(500).json({ message: 'Error fetching devices', error });
    }
});
7.1.2 更新设备状态

添加一个 API 接口以更新特定设备的状态。我们将使用设备的 ID 作为参数:

// 更新设备状态
app.put('/api/devices/:id', authenticateJWT, async (req, res) => {
    const { id } = req.params;
    const { status } = req.body;

    try {
        const device = await Device.findByIdAndUpdate(id, { status }, { new: true });
        if (!device) {
            return res.status(404).json({ message: 'Device not found' });
        }
        res.status(200).json(device);
    } catch (error) {
        res.status(500).json({ message: 'Error updating device', error });
    }
});
7.1.3 删除设备

添加一个 API 接口以删除特定设备。我们同样使用设备的 ID 作为参数:

// 删除设备
app.delete('/api/devices/:id', authenticateJWT, async (req, res) => {
    const { id } = req.params;

    try {
        const device = await Device.findByIdAndDelete(id);
        if (!device) {
            return res.status(404).json({ message: 'Device not found' });
        }
        res.status(204).send(); // 返回 204 No Content
    } catch (error) {
        res.status(500).json({ message: 'Error deleting device', error });
    }
});

8. 日志与监控

为了确保系统的稳定性和安全性,我们需要实现日志记录和系统监控。可以使用 morgan 中间件来记录 HTTP 请求,并使用其他工具来监控系统性能。

8.1 日志记录

首先,安装 morgan

npm install morgan

然后在 server.js 中添加以下代码,以便记录每个请求的信息:

const morgan = require('morgan');

// 使用 morgan 记录 HTTP 请求日志
app.use(morgan('combined'));

这将记录所有请求的详细信息,包括请求方法、URL、状态码和请求时间。

8.2 系统监控

对于系统监控,可以使用工具如 Prometheus 和 Grafana 进行监控。通过收集和可视化系统指标(如 CPU 使用率、内存使用量等),您可以更好地理解和管理系统的性能。

# 安装 Prometheus
sudo apt install prometheus

然后配置 Prometheus 以监控您的 Node.js 应用。可以使用 prom-client 库在应用中导出指标。

npm install prom-client

在 server.js 中添加以下代码:

const client = require('prom-client');

// 创建一个 Registry 用于保存指标
const register = new client.Registry();

// 创建一个 Gauge 指标来监控请求数量
const httpRequestDurationMicroseconds = new client.Histogram({
    name: 'http_request_duration_seconds',
    help: 'Duration of HTTP requests in seconds',
    labelNames: ['method', 'route', 'code'],
    registers: [register],
});

// 中间件记录请求时间
app.use((req, res, next) => {
    const end = httpRequestDurationMicroseconds.startTimer();
    res.on('finish', () => {
        end({ method: req.method, route: req.path, code: res.statusCode });
    });
    next();
});

// 提供一个端点用于导出指标
app.get('/metrics', async (req, res) => {
    res.set('Content-Type', register.contentType);
    res.end(await register.metrics());
});

9. 用户管理

用户管理是物联网系统的重要组成部分,确保只有授权用户可以访问系统的特定功能。我们将实现用户角色和权限管理,并记录用户操作以便审计和跟踪。

9.1 用户角色和权限管理

在我们的物联网系统中,用户可以具有不同的角色(例如,管理员、普通用户),并且每个角色可以拥有不同的权限。我们可以通过在用户模型中添加角色字段来实现这一点。

9.1.1 修改用户模型

首先,修改我们的用户模型以支持角色:

const UserSchema = new mongoose.Schema({
    username: String,
    password: String,
    role: {
        type: String,
        enum: ['admin', 'user'],
        default: 'user'
    }
});
9.1.2 修改用户注册接口

确保在用户注册时能够指定角色(可选):

// 用户注册接口
app.post('/api/register', async (req, res) => {
    const { username, password, role } = req.body;
    const hashedPassword = await bcrypt.hash(password, 10);
    const user = new User({ username, password: hashedPassword, role });
    await user.save();
    res.status(201).send('User registered');
});
9.2 权限控制

我们需要在 API 中实施权限控制,以确保只有特定角色的用户能够访问某些功能。例如,只有管理员可以删除设备。

9.2.1 创建中间件进行权限检查

我们可以创建一个中间件来检查用户的角色:

// 权限检查中间件
const authorizeRoles = (...allowedRoles) => {
    return (req, res, next) => {
        const { role } = req.user; // 从请求中获取用户角色
        if (!allowedRoles.includes(role)) {
            return res.status(403).json({ message: 'Access forbidden: insufficient rights' });
        }
        next();
    };
};
9.2.2 修改删除设备接口

使用角色检查中间件来保护删除设备的接口:

// 删除设备
app.delete('/api/devices/:id', authenticateJWT, authorizeRoles('admin'), async (req, res) => {
    const { id } = req.params;

    try {
        const device = await Device.findByIdAndDelete(id);
        if (!device) {
            return res.status(404).json({ message: 'Device not found' });
        }
        res.status(204).send(); // 返回 204 No Content
    } catch (error) {
        res.status(500).json({ message: 'Error deleting device', error });
    }
});

9.3 审计和跟踪

为了记录用户的操作,我们可以在每个敏感操作的 API 接口中添加日志记录。

9.3.1 修改用户注册接口

在用户注册接口中,我们已经记录了日志。以下是完整的用户注册接口代码:

// 用户注册接口
app.post('/api/register', async (req, res) => {
    const { username, password, role } = req.body;
    const hashedPassword = await bcrypt.hash(password, 10);
    const user = new User({ username, password: hashedPassword, role });
    await user.save();
    
    // 记录日志
    const log = new Log({ userId: user._id, action: `Registered user ${username}` });
    await log.save();

    res.status(201).send('User registered');
});
9.3.2 修改用户登录接口

在用户登录接口中,我们可以记录用户的登录操作:

// 用户登录接口
app.post('/api/login', async (req, res) => {
    const { username, password } = req.body;
    const user = await User.findOne({ username });
    if (!user || !await bcrypt.compare(password, user.password)) {
        return res.status(401).send('Invalid credentials');
    }
    const token = jwt.sign({ id: user._id, role: user.role }, SECRET_KEY, { expiresIn: '1h' });

    // 记录登录日志
    const log = new Log({ userId: user._id, action: `User ${username} logged in` });
    await log.save();

    res.status(200).json({ token });
});
9.3.3 修改更新设备状态接口

在设备状态更新接口中记录日志:

// 更新设备状态
app.put('/api/devices/:id', authenticateJWT, async (req, res) => {
    const { id } = req.params;
    const { status } = req.body;

    try {
        const device = await Device.findByIdAndUpdate(id, { status }, { new: true });
        if (!device) {
            return res.status(404).json({ message: 'Device not found' });
        }

        // 记录日志
        const log = new Log({ userId: req.user.id, action: `Updated device ${id} status to ${status}` });
        await log.save();

        res.status(200).json(device);
    } catch (error) {
        res.status(500).json({ message: 'Error updating device', error });
    }
});
9.3.4 修改获取所有设备数据接口

在获取所有设备数据的接口中记录日志:

// 获取所有设备数据
app.get('/api/devices', authenticateJWT, async (req, res) => {
    try {
        const devices = await Device.find();
        
        // 记录日志
        const log = new Log({ userId: req.user.id, action: `Fetched all devices` });
        await log.save();

        res.status(200).json(devices);
    } catch (error) {
        res.status(500).json({ message: 'Error fetching devices', error });
    }
});

9.4 查看操作日志

为了方便审计和追踪,您可能需要一个接口来查看操作日志。我们可以添加一个新的 API 接口来获取所有日志记录:

// 获取所有日志记录
app.get('/api/logs', authenticateJWT, authorizeRoles('admin'), async (req, res) => {
    try {
        const logs = await Log.find().populate('userId', 'username'); // Populate userId to get username
        res.status(200).json(logs);
    } catch (error) {
        res.status(500).json({ message: 'Error fetching logs', error });
    }
});

10. 结论

通过上述步骤,我们已经搭建了一个完整的物联网服务器,涵盖了以下关键模块:

  • 设备管理:实现了设备的注册、更新、删除和查询功能,支持大规模设备的管理。这为物联网应用提供了基础设施,使得各种设备可以被有效地管理和控制。

  • 数据处理与存储:通过使用 MongoDB 等数据库高效存储设备数据,并实现实时数据处理功能,使得系统能够及时响应设备状态变化,支持边缘计算和云端计算的结合。

  • 安全性:使用 JWT 实现身份验证和权限管理,确保只有授权用户和设备能够访问系统,降低了安全隐患。此外,通过 HTTPS 加密通信,保护了数据在传输过程中的安全。

  • 可扩展性与高可用性:设计了可横向扩展的架构,保证随着设备数量的增加,系统能够稳定运行。同时,通过负载均衡和容错机制提高了系统的可用性。

  • 数据分析与可视化:集成了 Grafana 和 Chart.js 等工具,提供了丰富的数据可视化功能,使用户能够实时监控和分析数据,帮助用户做出更好的决策。

  • 事件处理与报警:实现了实时事件检测和报警系统,确保用户能够及时获知异常情况,提高了系统的可靠性。

  • 接口与集成:提供了丰富的 RESTful API 接口,使得第三方系统能够方便地与物联网平台进行集成,增强了系统的互操作性。

  • 日志与监控:通过记录用户操作日志和系统性能指标,提供了审计和监控功能,有助于系统的维护和安全审查。

  • 用户管理:实现了用户角色和权限管理,确保系统的安全性和可控性,并通过日志系统实现了用户操作的审计和跟踪。

10.1 参考资料

在搭建物联网服务器的过程中,可以参考以下资料和文档:

  • Node.js 官方文档
  • MongoDB 官方文档
  • Express.js 官方文档
  • Socket.IO 官方文档
  • JWT 官方文档
  • Grafana 官方文档
  • Chart.js 官方文档

非常感谢您阅读到这里!您的关注和支持是我不断前进的动力。搭建物联网服务器是一个充满挑战的旅程,但通过本指南,希望您能掌握关键步骤,构建出功能强大的物联网平台

——by 极客小张

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1960067.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

html必知必会-html内嵌JavaScript和文件路径

文章目录 HTML JavaScriptHTML <script> 标签JavaScript 的简单示例HTML <noscript> 标签HTML 文件路径绝对文件路径相对文件路径总结 HTML JavaScript JavaScript 使 HTML 页面更具动态性和交互性。 示例 <!DOCTYPE html> <html> <body><…

iOS18使用技巧:iPhone通话录音开启教程和注意事项

今日早些时候&#xff0c;苹果为iPhone 15 Pro系列的开发者预览版用户推送了iOS 18.1 Beta1测试版的更新&#xff0c;已经注册Apple Beta版软件计划的用户只需打开设置--通用--软件更新即可在线OTA升级至最新的iOS 18.1 Beta1测试版。 说起iOS 18.1最重磅的更新&#xff0c;莫过…

Redis7-入门-安装

1.Redis是什么 REmote Dictionary Server(远程字典服务器) Remote Dictionary Server(远程字典服务)是完全开源的&#xff0c;使用ANSIC语言编写遵守BSD协议&#xff0c;是一个高性能的Key-Value数据库提供了丰富的数据结构&#xff0c;例如String、Hash、List、set、Sorteds…

程序员学长 | 快速学会一个算法,ANN

本文来源公众号“程序员学长”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;快速学会一个算法&#xff0c;ANN 今天给大家分享一个强大的算法模型&#xff0c;ANN。 人工神经网络 (ANN) 是一种深度学习方法&#xff0c;源自人类…

【C++BFS】1020. 飞地的数量

本文涉及知识点 CBFS算法 LeetCode1020. 飞地的数量 给你一个大小为 m x n 的二进制矩阵 grid &#xff0c;其中 0 表示一个海洋单元格、1 表示一个陆地单元格。 一次 移动 是指从一个陆地单元格走到另一个相邻&#xff08;上、下、左、右&#xff09;的陆地单元格或跨过 gr…

html+css 炫酷的流边按钮

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享htmlcss 绚丽效果&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 文…

详细教程:在Octo Browser指纹浏览器中配置IPXProxy代理IP的步骤

​Octo Browser是一款反检测指纹浏览器&#xff0c;可防止在线跟踪并保护用户隐私的网络浏览器。用户可以在Octo Browser中设置代理IP&#xff0c;来进行多账户的管理&#xff0c;降低账户关联的风险。下面以IPXProxy代理IP为例&#xff0c;告诉大家如何在Octo Browser指纹浏览…

顺序栈*链栈

逻辑结构,存储结构,运算 栈的定义 栈是只能在一端进行插入,删除操作的线性表; 栈的操作特征为先进后出,栈的逻辑结果为线性结构,是一种特殊的线性表. 栈顶:允许插入,删除 栈底:不允许插入删除 存储结构--顺序存储 (1)定义 #include<stdio.h> #define MaxSize 10 /…

哪些洗地机比较好?揭晓中国十大名牌洗地机

在当今追求高效与品质生活的时代&#xff0c;洗地机作为现代家居清洁的得力助手&#xff0c;其重要性日益凸显。为了帮助大家在众多品牌中筛选出优质之选&#xff0c;我们精心揭晓中国洗地机领域的十大名牌。这些品牌凭借卓越的性能、创新的技术以及良好的用户口碑&#xff0c;…

开启mybatis-plus日志功能

第一部分&#xff1a;配置文件增添参数 增加如下&#xff1a; configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 第二部分&#xff1a;运行效果展示

大数据信用报告一般都是在哪里查询?

相信现在有不少人都听说过大数据信用&#xff0c;其实早在几年前&#xff0c;大数据就已经作为银行和借贷机构审核申贷人的重要途径&#xff0c;因为传统的征信报告有一定的局限性&#xff0c;无法全方位的了解申贷人的隐形负债&#xff0c;大数据信用报告的作用就显现出来了&a…

Ansys Zemax|如何模拟复杂的菲涅尔透镜

附件下载 联系工作人员获取附件 概述 这篇文章介绍了如何模拟每个菲涅尔环都由不同数据定义的复杂菲涅尔透镜。这种方法也可以用于定义复杂物体。 介绍 菲涅尔透镜与普通透镜有所区别&#xff0c;它是将普通透镜连续、光滑的表面分成一系列同心圆环&#xff0c;这些同心圆环…

手机高清录屏,快速学会的2种绝妙方法!

在移动互联时代&#xff0c;手机不仅仅是通讯工具&#xff0c;更是我们记录生活、分享经验、创作内容的得力助手。而手机高清录屏功能&#xff0c;则为我们捕捉手机屏幕上的每一帧精彩提供了便捷的方式。无论是游戏直播、教学演示&#xff0c;还是视频制作&#xff0c;手机高清…

创建自己的 Omnigraph (python篇)

Omnigraph 是 Nvidia Omniverse 中一个强大的视觉化脚本工具&#xff0c;它让开发者能够以直观和灵活的方式创建复杂的行为和交互性。通过结合 Action Graphs 和 Push Graphs&#xff0c;以及利用丰富的节点库&#xff0c;用户可以在 Omniverse 平台上构建出令人惊叹的虚拟世界…

Ubuntu虚拟机扩容笔记(各种方法都不行版)

1.背景介绍 最近需要对ubuntu的虚拟机下面的挂载根目录上的文件系统对应的硬盘进行扩容&#xff0c;在虚拟机管理平台对磁盘进行扩容后&#xff0c;在图形界面上尝试扩容&#xff1a; 尝试教程主要采用下面教程的第三种方法&#xff1a; Ubuntu22.04 Linux磁盘扩容/硬盘扩展…

【C++】学习笔记——C++11_1

文章目录 十九、C111. 统一的列表初始化{}初始化std::initializer_list 2. 声明autodecltypenullptr 4. 范围for5. STL中的一些变化新容器新方法 6. 右值引用和移动语句左值引用和右值引用 未完待续 十九、C11 1. 统一的列表初始化 {}初始化 在C98中&#xff0c;标准允许使用…

C++ map/set 函数用法解析

一 . set 1.1 set 是什么、关联/非关联式容器 se是一种关联式容器&#xff0c;主要用进行查找的工作。采用了key模型&#xff0c;判断数据在不在。不支持修改的操作。 序列式容器&#xff08;线性表&#xff09;&#xff1a;vector / list /deque&#xff08;单纯存储数据&am…

top命令从入门到精通

top命令从入门到精通 linux平台上一个可以用于性能监控、排查的神器。 响应参数 up&#xff1a;运行时长users&#xff1a;当前登陆了几个用户load average&#xff1a;运行负载 sleeping&#xff1a;休眠进程stopped&#xff1a;终止进程zombie&#xff1a;僵尸进程 us&…

Neutralinojs教程项目实战初体验(踩坑指南),干翻 electron

Neutralinojs 项目实战初体验&#xff08;踩坑指南&#xff09;&#xff0c;干翻 electron Neutralinojs 官方文档 卧槽卧槽&#xff0c;&#xff01;这个年轻人居然用浏览器把电脑关机了_哔哩哔哩_bilibili正是在下 本教程搭建的是纯原生项目&#xff0c;没有和其它前端框架…

【C++BFS】959. 由斜杠划分区域

本文涉及知识点 CBFS算法 LeetCode959. 由斜杠划分区域 在由 1 x 1 方格组成的 n x n 网格 grid 中&#xff0c;每个 1 x 1 方块由 ‘/’、‘’ 或空格构成。这些字符会将方块划分为一些共边的区域。 给定网格 grid 表示为一个字符串数组&#xff0c;返回 区域的数量 。 请注…