java通过org.eclipse.milo实现OPCUA客户端进行连接和订阅

前言

之前写过一篇关于MQTT的方式进行物理访问的文章:SpringBoot集成MQTT,WebSocket返回前端信息_springboot mqtt websocket-CSDN博客

最近又接触到OPCUA协议,想通过java试试看能不能实现。

软件

在使用java实现之前,想着有没有什么模拟器作为服务器端能够进行发送opcua数据,网上搜到好多都是使用KEPServerEX6,下载了之后,发现学习成本好大,这个软件都不会玩,最后终于找到了Prosys OPC UA Simulation Server,相对来说,这个软件的学习成本很低。但是也有一个弊端,只能进行本地模拟。

下载地址:Prosys OPC - OPC UA Simulation Server Downloads

下载安装完成之后,打开页面就可以看到,软件生成的opcua测试地址

为了方便操作,把所有的菜单全部暴露出来,点击Options下的Switch to Basic Mode

如果需要修改这个默认的连接地址,可通过 Endpoints 菜单进行设置(我这里用的是默认的地址)。也可以在这个菜单下修改连接方式和加密方式。

也可以在Users下添加用户名和密码

Objects上自带了一些函数能够帮助我们快速进行测试,也可以自己创建(我使用的是自带的)

接下来就是代码

代码

引入依赖

        <dependency>
            <groupId>org.eclipse.milo</groupId>
            <artifactId>sdk-client</artifactId>
            <version>0.6.9</version>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcpkix-jdk15on</artifactId>
            <version>1.70</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.milo</groupId>
            <artifactId>sdk-server</artifactId>
            <version>0.6.9</version>
        </dependency>

目前实现了两种方式:匿名方式、用户名加证书方式,还有仅用户名方式后续继续研究

匿名方式:

import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.milo.opcua.sdk.client.api.identity.AnonymousProvider;
import org.eclipse.milo.opcua.sdk.client.api.identity.UsernameProvider;
import org.eclipse.milo.opcua.sdk.server.Session;
import org.eclipse.milo.opcua.stack.core.AttributeId;
import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy;
import org.eclipse.milo.opcua.stack.core.types.builtin.*;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
import org.eclipse.milo.opcua.stack.core.types.enumerated.MonitoringMode;
import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn;
import org.eclipse.milo.opcua.stack.core.types.structured.MonitoredItemCreateRequest;
import org.eclipse.milo.opcua.stack.core.types.structured.MonitoringParameters;
import org.eclipse.milo.opcua.stack.core.types.structured.ReadValueId;
import org.eclipse.milo.opcua.stack.core.types.structured.UserNameIdentityToken;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;


/**
 * 无密码无证书无安全认证模式
 * @Author: majinzhong
 * @Data:2024/8/30
 */
public class OpcUaTest {
    //opc ua服务端地址
    private final static String endPointUrl = "opc.tcp://Administrator:53530/OPCUA/SimulationServer";
//    private final static String endPointUrl = "opc.tcp://192.168.24.13:4840";

    public static void main(String[] args) {
        try {
            //创建OPC UA客户端
            OpcUaClient opcUaClient = createClient();

            //开启连接
            opcUaClient.connect().get();
            // 订阅消息
            subscribe(opcUaClient);

            // 写入
//            writeValue(opcUaClient);

            // 读取
//            readValue(opcUaClient);

            // 关闭连接
            opcUaClient.disconnect().get();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 创建OPC UA客户端
     *
     * @return
     * @throws Exception
     */
    private static OpcUaClient createClient() throws Exception {
        Path securityTempDir = Paths.get(System.getProperty("java.io.tmpdir"), "security");
        Files.createDirectories(securityTempDir);
        if (!Files.exists(securityTempDir)) {
            throw new Exception("unable to create security dir: " + securityTempDir);
        }
            return OpcUaClient.create(endPointUrl,
                endpoints ->
                        endpoints.stream()
                                .filter(e -> e.getSecurityPolicyUri().equals(SecurityPolicy.None.getUri()))
                                .findFirst(),
                configBuilder ->
                        configBuilder
                                .setApplicationName(LocalizedText.english("OPC UA test")) // huazh-01
                                .setApplicationUri("urn:eclipse:milo:client") // ns=2:s=huazh-01.device1.data-huazh
                                //访问方式 new AnonymousProvider()
                                .setIdentityProvider(new AnonymousProvider())
                                .setRequestTimeout(UInteger.valueOf(5000))
                                .build()
        );
    }

    private static void subscribe(OpcUaClient client) throws Exception {
        //创建发布间隔1000ms的订阅对象
        client.getSubscriptionManager()
                .createSubscription(1000.0)
                .thenAccept(t -> {
                    //节点ns=2;s=test.device2.test2
//                    NodeId nodeId = new NodeId(4, 322);
                    NodeId nodeId = new NodeId(3, 1003);
                    ReadValueId readValueId = new ReadValueId(nodeId, AttributeId.Value.uid(), null, null);
                    //创建监控的参数
                    MonitoringParameters parameters = new MonitoringParameters(UInteger.valueOf(1), 1000.0, null, UInteger.valueOf(10), true);
                    //创建监控项请求
                    //该请求最后用于创建订阅。
                    MonitoredItemCreateRequest request = new MonitoredItemCreateRequest(readValueId, MonitoringMode.Reporting, parameters);
                    List<MonitoredItemCreateRequest> requests = new ArrayList<>();
                    requests.add(request);
                    //创建监控项,并且注册变量值改变时候的回调函数。
                    t.createMonitoredItems(
                            TimestampsToReturn.Both,
                            requests,
                            (item, id) -> item.setValueConsumer((it, val) -> {
                                System.out.println("=====订阅nodeid====== :" + it.getReadValueId().getNodeId());
                                System.out.println("=====订阅value===== :" + val.getValue().getValue());
                            })
                    );
                }).get();

        //持续订阅
        Thread.sleep(Long.MAX_VALUE);
    }

    public static void readValue(OpcUaClient client) {
        try {
            NodeId nodeId = new NodeId(3, 1002);

            DataValue value = client.readValue(0.0, TimestampsToReturn.Both, nodeId).get();

            System.out.println("=====读取ua1====:" + value.getValue().getValue());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void writeValue(OpcUaClient client) {
        try {

            //创建变量节点 test.device2.test2
            NodeId nodeId = new NodeId(2, "test.device2.test2");

            //uda3 boolean
            Short value = 11;
            //创建Variant对象和DataValue对象
            Variant v = new Variant(value);
            DataValue dataValue = new DataValue(v, null, null);

            StatusCode statusCode = client.writeValue(nodeId, dataValue).get();
            System.out.println(statusCode);
            System.out.println("=====写入ua1====:" + statusCode.isGood());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

用户名加正式认证方式:

import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.milo.opcua.sdk.client.api.identity.UsernameProvider;
import org.eclipse.milo.opcua.stack.core.AttributeId;
import org.eclipse.milo.opcua.stack.core.security.SecurityPolicy;
import org.eclipse.milo.opcua.stack.core.types.builtin.*;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
import org.eclipse.milo.opcua.stack.core.types.enumerated.MonitoringMode;
import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn;
import org.eclipse.milo.opcua.stack.core.types.structured.MonitoredItemCreateRequest;
import org.eclipse.milo.opcua.stack.core.types.structured.MonitoringParameters;
import org.eclipse.milo.opcua.stack.core.types.structured.ReadValueId;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;


/**
 * 有密码有证书有安全认证模式
 * @Author: majinzhong
 * @Data:2024/8/30
 */
public class OpcUaTest2 {
    //opc ua服务端地址
    private final static String endPointUrl = "opc.tcp://Administrator:53530/OPCUA/SimulationServer";
//    private final static String endPointUrl = "opc.tcp://192.168.24.13:4840";

    public static void main(String[] args) {
        try {
            //创建OPC UA客户端
            OpcUaClient opcUaClient = createClient();

            //开启连接
            opcUaClient.connect().get();
            // 订阅消息
            subscribe(opcUaClient);

            // 写入
//            writeValue(opcUaClient);

            // 读取
//            readValue(opcUaClient);

            // 关闭连接
            opcUaClient.disconnect().get();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 创建OPC UA客户端
     *
     * @return
     * @throws Exception
     */
    private static OpcUaClient createClient() throws Exception {
        Path securityTempDir = Paths.get(System.getProperty("java.io.tmpdir"), "security");
        Files.createDirectories(securityTempDir);
        if (!Files.exists(securityTempDir)) {
            throw new Exception("unable to create security dir: " + securityTempDir);
        }

        KeyStoreLoader loader = new KeyStoreLoader().load(securityTempDir);

        return OpcUaClient.create(endPointUrl,
                endpoints ->
                        endpoints.stream()
                                .filter(e -> e.getSecurityPolicyUri().equals(SecurityPolicy.Basic256Sha256.getUri()))
//                                .filter(e -> e.getSecurityPolicyUri().equals(SecurityPolicy.None.getUri()))
                                .findFirst(),
                configBuilder ->
                        configBuilder
                                .setApplicationName(LocalizedText.english("OPC UA test")) // huazh-01
                                .setApplicationUri("urn:eclipse:milo:client") // ns=2:s=huazh-01.device1.data-huazh
                                //访问方式 new AnonymousProvider()
                                .setCertificate(loader.getClientCertificate())
                                .setKeyPair(loader.getClientKeyPair())
                                .setIdentityProvider(new UsernameProvider("TOPNC", "TOPNC123"))
                                .setRequestTimeout(UInteger.valueOf(5000))
                                .build()
        );
    }

    private static void subscribe(OpcUaClient client) throws Exception {
        //创建发布间隔1000ms的订阅对象
        client.getSubscriptionManager()
                .createSubscription(1000.0)
                .thenAccept(t -> {
                    //节点ns=2;s=test.device2.test2
//                    NodeId nodeId = new NodeId(3, "unit/Peri_I_O.gs_ComToRM.r32_A1_Axis_ActValue");
                    NodeId nodeId = new NodeId(3, 1003);
                    ReadValueId readValueId = new ReadValueId(nodeId, AttributeId.Value.uid(), null, null);
                    //创建监控的参数
                    MonitoringParameters parameters = new MonitoringParameters(UInteger.valueOf(1), 1000.0, null, UInteger.valueOf(10), true);
                    //创建监控项请求
                    //该请求最后用于创建订阅。
                    MonitoredItemCreateRequest request = new MonitoredItemCreateRequest(readValueId, MonitoringMode.Reporting, parameters);
                    List<MonitoredItemCreateRequest> requests = new ArrayList<>();
                    requests.add(request);
                    //创建监控项,并且注册变量值改变时候的回调函数。
                    t.createMonitoredItems(
                            TimestampsToReturn.Both,
                            requests,
                            (item, id) -> item.setValueConsumer((it, val) -> {
                                System.out.println("=====订阅nodeid====== :" + it.getReadValueId().getNodeId());
                                System.out.println("=====订阅value===== :" + val.getValue().getValue());
                            })
                    );
                }).get();

        //持续订阅
        Thread.sleep(Long.MAX_VALUE);
    }

    public static void readValue(OpcUaClient client) {
        try {
            NodeId nodeId = new NodeId(3, 1002);

            DataValue value = client.readValue(0.0, TimestampsToReturn.Both, nodeId).get();

            System.out.println("=====读取ua1====:" + value.getValue().getValue());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void writeValue(OpcUaClient client) {
        try {

            //创建变量节点 test.device2.test2
            NodeId nodeId = new NodeId(2, "test.device2.test2");

            //uda3 boolean
            Short value = 11;
            //创建Variant对象和DataValue对象
            Variant v = new Variant(value);
            DataValue dataValue = new DataValue(v, null, null);

            StatusCode statusCode = client.writeValue(nodeId, dataValue).get();
            System.out.println(statusCode);
            System.out.println("=====写入ua1====:" + statusCode.isGood());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

证书加密类

import org.eclipse.milo.opcua.sdk.server.util.HostnameUtil;
import org.eclipse.milo.opcua.stack.core.util.SelfSignedCertificateBuilder;
import org.eclipse.milo.opcua.stack.core.util.SelfSignedCertificateGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.*;
import java.security.cert.X509Certificate;
import java.util.regex.Pattern;

/**
 * Created by Cryan on 2021/8/4.
 * TODO.OPCUA  证书生成
 */

class KeyStoreLoader {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private static final Pattern IP_ADDR_PATTERN = Pattern.compile(
            "^(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])$");

    // 证书别名
    private static final String CLIENT_ALIAS = "client-ai";
    // 获取私钥的密码
    private static final char[] PASSWORD = "password".toCharArray();
    // 证书对象
    private X509Certificate clientCertificate;
    // 密钥对对象
    private KeyPair clientKeyPair;

    KeyStoreLoader load(Path baseDir) throws Exception {
        // 创建一个使用`PKCS12`加密标准的KeyStore。KeyStore在后面将作为读取和生成证书的对象。
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        // PKCS12的加密标准的文件后缀是.pfx,其中包含了公钥和私钥。
        // 而其他如.der等的格式只包含公钥,私钥在另外的文件中。
        Path serverKeyStore = baseDir.resolve("example-client.pfx");

        logger.info("Loading KeyStore at {}", serverKeyStore);
        // 如果文件不存在则创建.pfx证书文件。
        if (!Files.exists(serverKeyStore)) {
            keyStore.load(null, PASSWORD);
            // 用2048位的RAS算法。`SelfSignedCertificateGenerator`为Milo库的对象。
            KeyPair keyPair = SelfSignedCertificateGenerator.generateRsaKeyPair(2048);
            // `SelfSignedCertificateBuilder`也是Milo库的对象,用来生成证书。
            // 中间所设置的证书属性可以自行修改。
            SelfSignedCertificateBuilder builder = new SelfSignedCertificateBuilder(keyPair)
                    .setCommonName("Eclipse Milo Example Client test")
                    .setOrganization("mjz")
                    .setOrganizationalUnit("dev")
                    .setLocalityName("mjz")
                    .setStateName("CA")
                    .setCountryCode("US")
                    .setApplicationUri("urn:eclipse:milo:client")
                    .addDnsName("localhost")
                    .addIpAddress("127.0.0.1");

            // Get as many hostnames and IP addresses as we can listed in the certificate.
            for (String hostname : HostnameUtil.getHostnames("0.0.0.0")) {
                if (IP_ADDR_PATTERN.matcher(hostname).matches()) {
                    builder.addIpAddress(hostname);
                } else {
                    builder.addDnsName(hostname);
                }
            }
            // 创建证书
            X509Certificate certificate = builder.build();
            // 设置对应私钥的别名,密码,证书链
            keyStore.setKeyEntry(CLIENT_ALIAS, keyPair.getPrivate(), PASSWORD, new X509Certificate[]{certificate});
            try (OutputStream out = Files.newOutputStream(serverKeyStore)) {
                // 保存证书到输出流
                keyStore.store(out, PASSWORD);
            }
        } else {
            try (InputStream in = Files.newInputStream(serverKeyStore)) {
                // 如果文件存在则读取
                keyStore.load(in, PASSWORD);
            }
        }
        // 用密码获取对应别名的私钥。
        Key serverPrivateKey = keyStore.getKey(CLIENT_ALIAS, PASSWORD);
        if (serverPrivateKey instanceof PrivateKey) {
            // 获取对应别名的证书对象。
            clientCertificate = (X509Certificate) keyStore.getCertificate(CLIENT_ALIAS);
            // 获取公钥
            PublicKey serverPublicKey = clientCertificate.getPublicKey();
            // 创建Keypair对象。
            clientKeyPair = new KeyPair(serverPublicKey, (PrivateKey) serverPrivateKey);
        }
        return this;
    }
    // 返回证书
    X509Certificate getClientCertificate() {
        return clientCertificate;
    }

    // 返回密钥对
    KeyPair getClientKeyPair() {
        return clientKeyPair;
    }
}

代码讲解

仔细阅读代码不难发现,匿名方式和用户名加正式方式仅仅只有这一块不太一样

配置完成之后,需要修改想要订阅的节点,进行读取数据,匿名方式和用户名加证书方式一致,都是在代码的NodeId nodeId = new NodeId(3, 1003);进行修改,其中的3和1003对应软件上Objects上的

运行

一切配置好并且修改好之后,先运行匿名方式!匿名方式!匿名方式!!!(用户名加证书方式还有一个点,下面再说)

可以看到已经能够读取到节点的数据了

第一次运行用户名加证书方式的时候,会报java.lang.RuntimeException: java.util.concurrent.ExecutionException: UaException: status=Bad_SecurityChecksFailed, message=Bad_SecurityChecksFailed (code=0x80130000, description="An error occurred verifying security.")的错误,这是因为证书没有被添加信任

在Certificates下找到自己的证书,将Reject改成Trust即可。

因为代码中setApplicationUri时写的是urn:eclipse:milo:client,所以这个就是刚刚代码创建的证书。

运行用户名加证书方式

已经可以正常读取到节点数据了

补充

问题一:运行代码时,可能会遇见java.lang.RuntimeException: UaException: status=Bad_ConfigurationError, message=no endpoint selected的错误,这是因为,OPCUA服务器端没有允许这种方式(OPCUA目前我看到的有三种方式:匿名、用户名、用户名加证书),所以需要修改OPCUA服务器端添加这种方式,添加在 Endpoints菜单下,或者查看服务器端支持哪种方式,修改代码。

问题二:org.eclipse.milo.opcua.stack.core.UaException: no KeyPair configured

这种是因为没有配置密钥,代码方面出现了问题,需要在创建客户端的时候setKeyPair()

问题三:org.eclipse.milo.opcua.stack.core.UaException: no certificate configured

这种时因为没有配置证书,代码方面出现了问题,需要在创建客户端的时候setCertificate()

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JVM 基础知识(基础组成 )

使用场景 线上系统突然宕机,系统无法访问,甚至直接 O0M;线上系统响应速度太慢,优化系统性能过程中发现 CPU 占用过高,原因也许是因为 JVM的 GC 次数过于频繁;新项目上线,需要设置 JVM的各种参数;等 JDK / JRE / JVM JDK JDK 全称 ( Java Development Kit ) &#xff0c;是 Ja…

react + antDesign封装图片预览组件(支持多张图片)

需求场景&#xff1a;最近在开发后台系统时经常遇到图片预览问题&#xff0c;如果一个一个的引用antDesign的图片预览组件就有点繁琐了&#xff0c;于是在antDesign图片预览组件的基础上二次封装了一下&#xff0c;避免重复无用代码的出现 效果 公共预览组件代码 import React…

Llama 3.2来了,多模态且开源!AR眼镜黄仁勋首批体验,Quest 3S头显价格低到离谱

如果说 OpenAI 的 ChatGPT 拉开了「百模大战」的序幕&#xff0c;那 Meta 的 Ray-Ban Meta 智能眼镜无疑是触发「百镜大战」的导火索。自去年 9 月在 Meta Connect 2023 开发者大会上首次亮相&#xff0c;短短数月&#xff0c;Ray-Ban Meta 就突破百万销量&#xff0c;不仅让马…

xpath在爬虫中的应用、xpath插件的安装及使用

安装 1、打开谷歌浏览器进入扩展程序安装页面(右上角会有"开发者模式按钮")默认是关闭的&#xff0c;当安装此插件时需要把开发者模式打开。 2、下载下来的xpath_helper是zip格式的&#xff0c;需要解压缩即可安装。 3、重启浏览器&#xff0c;再次点击扩展程序即…

解密 Python 的 staticmethod 函数:静态方法的全面解析!

更多Python学习内容&#xff1a;ipengtao.com 在 Python 中&#xff0c;staticmethod 函数是一种装饰器&#xff0c;用于将函数转换为静态方法。静态方法与实例方法和类方法不同&#xff0c;它们不需要类实例作为第一个参数&#xff0c;也不需要类作为第一个参数&#xff0c;因…

微型丝杆的行业应用!

微型丝杆作为一种高精度、小尺寸的机械传动元件&#xff0c;在现代工业中扮演着重要角色&#xff0c;在多个行业中都有广泛的应用‌&#xff0c;主要包括以下几个方面&#xff1a; 1、医疗设备&#xff1a;在手术机器人中&#xff0c;微型丝杆能够实现精准定位和操作&#xff0…

二叉树进阶

目录 1. 二叉搜索树实现 1.1 二叉搜索树概念 2.2 二叉搜索树操作 ​编辑 ​编辑 2.3 二叉搜索树的实现 2.3.0 Destroy() 析构 2.3.1 Insert&#xff08;&#xff09;插入 2.3.2 InOrder&#xff08;&#xff09; 打印搜索二叉树 ​编辑​编辑 2.3.3 Find() 查找 …

GaussDB关键技术原理:高弹性(五)

书接上文GaussDB关键技术原理&#xff1a;高弹性&#xff08;四&#xff09;从扩容流程框架方面对hashbucket扩容技术进行了解读&#xff0c;本篇将从日志多流和事务相关方面继续介绍GaussDB高弹性技术。 目录 4.2 日志多流 4.2.1 日志多流总体流程 4.2.2 基线数据传输 4.…

fiddler抓包07_抓IOS手机请求

课程大纲 前提&#xff1a;电脑和手机连接同一个局域网 &#xff08;土小帽电脑和手机都连了自己的无线网“tuxiaomao”。&#xff09; 原理如下&#xff1a; 电脑浏览器抓包时&#xff0c;直接就是本机网络。手机想被电脑Fiddler抓包&#xff0c;就要把Fiddler变成手机和网络…

PMP与CMMI:两种管理方法的对比

PMP与CMMI&#xff1a;两种管理方法的对比 PMP&#xff1a;专注于项目管理CMMI&#xff1a;组织过程改进的框架总结&#xff1a;互补而非替代 在现代企业管理中&#xff0c;项目管理和组织能力成熟度模型集成&#xff08;CMMI&#xff09;是两个经常被提及的概念。虽然它们都是…

vue3中echarts柱状图横轴文字太多放不下怎么解决

问题&#xff1a;在做数据展示的时候&#xff0c;使用的是echarts&#xff0c;遇到了个问题&#xff0c;就是数据过多&#xff0c;但是设置的x轴的文字名称又太长&#xff0c;往往左边第一个或右边最后一个的名称展示不全&#xff0c;只有半个。 从网上找到了几种办法&#xff…

项目实战:Qt+OSG爆破动力学仿真三维引擎测试工具v1.1.0(加载.K模型,子弹轨迹模拟动画,支持windows、linux、国产麒麟系统)

若该文为原创文章&#xff0c;转载请注明出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/142454993 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、Op…

Vue74 路由的props配置

笔记 ​ 作用&#xff1a;让路由组件更方便的收到参数 {name:xiangqing,path:detail/:id,component:Detail,//第一种写法&#xff1a;props值为对象&#xff0c;该对象中所有的key-value的组合最终都会通过props传给Detail组件// props:{a:900}//第二种写法&#xff1a;props…

edu某智慧平台 ExpDownloadService.aspx接口任意文件读取漏洞复现 [附POC]

文章目录 edu某智慧平台 ExpDownloadService.aspx接口任意文件读取漏洞复现 [附POC]0x01 前言0x02 漏洞环境0x03 漏洞复现1.访问漏洞环境2.构造POC3.复现edu某智慧平台 ExpDownloadService.aspx接口任意文件读取漏洞复现 [附POC] 0x01 前言 免责声明:请勿利用文章内的相关技…

统信服务器操作系统进入【单用户模式】

统信服务器操作系统D版、E版、A版进入单用户模式的方式。 文章目录 前言一、问题现象二、问题原因三、解决方案1. D版问题解决方案2. E版及A版问题解决方案前言 D版又称企业版、E版又称欧拉版、A版又称龙蜥版。 单用户模式主要是在 grub2 引导时编辑内核引导,一般用于修改用…

makefile和CMakeLists/C++包管理器

make 大家可能会很奇怪&#xff0c;都什么年代了&#xff0c;还学makefile&#xff0c;cmake都有些过时了&#xff0c;为什么还要再学这个呢&#xff1f; 我是这么看待这个问题的&#xff0c;cmake跨平台性还是很有有优势的&#xff0c;有着多年积累的底蕴&#xff0c;借助大模…

英伟达:AI时代的领跑者,引领智能计算的未来@附149页PDF文件下载

在人工智能的浪潮中&#xff0c;英伟达&#xff08;NVIDIA&#xff09;以其卓越的GPU技术&#xff0c;成为了这个时代的领跑者。从游戏显卡的霸主到AI计算的领导者&#xff0c;英伟达的转型之路充满了创新与突破。今天&#xff0c;我们将深入探讨2024年英伟达如何通过其战略布局…

Apache CVE-2021-41773 漏洞攻略

漏洞简介 该漏洞是由于Apache HTTP Server 2.4.49版本存在⽬录穿越漏洞,在路径穿越⽬录 <Directory/>Require all granted</Directory>允许被访问的的情况下&#xff08;默认开启&#xff09;&#xff0c;攻击者可利⽤该路径穿越漏洞读取到Web⽬录之外的其他⽂件在…

DPDK 简易应用开发之路 2:UDP数据包发送及实现

本机环境为 Ubuntu20.04 &#xff0c;dpdk-stable-20.11.10 发送数据包的通用步骤 初始化DPDK环境&#xff1a; 调用 rte_eal_init() 来初始化DPDK的EAL&#xff08;环境抽象层&#xff09;&#xff0c;这是所有DPDK应用程序的第一步&#xff0c;用于初始化硬件、内存和逻辑核…

[Linux]:线程(一)

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;Linux学习 贝蒂的主页&#xff1a;Betty’s blog 1. 初识线程 1.1 线程的概念 在操作系统中&#xff0c;进程与线程一直是我们…