阿里云物联网智能视频服务接入

news2024/11/16 13:28:27

物联网视频服务(LinkVisual)支持视频流上云、存储、转发、告警事件等视频基础能力,提供丰富的视频算法以及云边协同(算法云端训练、云端下发、边缘计算推理)服务。旨在帮助视频设备厂商、方案商与服务提供商,快速将存量或者新增的视频设备上云。

文章目录

  • 前言
  • 一、购买企业版实例
  • 二、使用步骤
    • 1.新增设备
    • 2.服务器端开发
      • 主动触发IPC设备拍摄图片并上传至云端
      • 服务器端订阅AMQP
  • 总结


前言

提示:主要记录物联网智能视频服务的接入过程:

后端服务主要是微服务Springcloud。
云平台主要是阿里云物联网智能视频服务-企业版实例

主要业务场景是,户外版4G摄像头,在无人观看是不产生上行流量,在有人观看是再进行推流查看直播画面,以及支持设备主动抓图。


提示:以下是本篇文章正文内容,下面案例可供参考

一、购买企业版实例

首先在物联网平台-购买企业版实例。下面的视频服务一定要开启
企业版实例
视频服务开启

二、使用步骤

1.新增设备

主要在购买的实例上进行新增产品-新增设备,以及设备端烧录,设备端开发一般都摄像头厂商进行对接,此处不在进行记录。

2.服务器端开发

主要记录服务器端与阿里云平台的对接

主动触发IPC设备拍摄图片并上传至云端

官网文档api 可以参考官方对接文档,其他相关接口和此接口对接方式相同,不在粘贴代码了

 /**
     * 调用该接口查询IPC设备获取的图片信息。。
     * @param iotInstanceId 实例id
     * @param productKey 产品key
     * @param deviceName 设备名称
     * @param captureId 图片id
     * @return
     * @throws Exception
     */
    public QueryDevicePictureFileResponseBody.QueryDevicePictureFileResponseBodyData queryDevicePictureFileWithOptions(String iotInstanceId, String productKey, String deviceName, String captureId) throws Exception {
        // 调用该接口主动触发IPC设备拍摄图片并上传至云端
        Client client = getClient();
        QueryDevicePictureFileRequest queryLiveStreamingRequest = new QueryDevicePictureFileRequest();
        queryLiveStreamingRequest.setDeviceName(deviceName);
        queryLiveStreamingRequest.setProductKey(productKey);
        queryLiveStreamingRequest.setIotInstanceId(iotInstanceId);
        queryLiveStreamingRequest.setCaptureId(captureId);
        com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();

        try {
            // 复制代码运行请自行打印 API 的返回值
            log.info("调用该接口查询IPC设备获取的图片信息,入参:{}",JSON.toJSONString(queryLiveStreamingRequest));
            QueryDevicePictureFileResponse queryDevicePictureFileResponse = client.queryDevicePictureFileWithOptions(queryLiveStreamingRequest, runtime);
            log.info("调用该接口查询IPC设备获取的图片信息,结果:{}",JSON.toJSONString(queryDevicePictureFileResponse));
            // {"body":{"code":"200","data":{"iotId":"Z50Qxs5BSuUoxO06mKRUi3rb00","picCreateTime":1672135564877,"picId":"WGJmWkYxU2dNaE5HSmpEWDJiQjY3T3ZnT2dNdl90LTlSVXhBVjU5SjJ5WS9lZmVmYzc0YmU2OTY0ZWY2YmVjNzg1MWM5MTA5YmY0Y18xNjcyMTM1NTY0ODc3","picUrl":"https://link-vision-picture-sh.oss-cn-shanghai.aliyuncs.com/XbfZF1SgMhNGJjDX2bB67OvgOgMv_t-9RUxAV59J2yY/efefc74be6964ef6bec7851c9109bf4c?Expires=1672139359&OSSAccessKeyId=LTAILduaCDAC561K&Signature=z3jXpII0Hjijbf8%2FGaJv%2FterhAw%3D","thumbUrl":"https://link-vision-picture-sh.oss-cn-shanghai.aliyuncs.com/XbfZF1SgMhNGJjDX2bB67OvgOgMv_t-9RUxAV59J2yY/efefc74be6964ef6bec7851c9109bf4c?Expires=1672139359&OSSAccessKeyId=LTAILduaCDAC561K&Signature=yZw6elXowc%2F2R3GQ753H8OR3E44%3D&x-oss-process=image%2Fauto-orient%2C1%2Fresize%2Cm_lfit%2Cw_400%2Climit_0%2Fquality%2Cq_90"},"requestId":"DCEAE36F-FBD2-5187-A035-317AFC1380A5","success":true},"headers":{"access-control-allow-origin":"*","date":"Tue, 27 Dec 2022 10:09:19 GMT","content-length":"866","x-acs-request-id":"DCEAE36F-FBD2-5187-A035-317AFC1380A5","connection":"keep-alive","content-type":"application/json;charset=utf-8","x-acs-trace-id":"853464dc94d2787fef2e9b5d5fc21556"},"statusCode":200}
            QueryDevicePictureFileResponseBody body = queryDevicePictureFileResponse.getBody();
            if(body.getSuccess()){
                return body.getData();
            }else {
                log.error("调用该接口查询IPC设备获取的图片信息 有误,{}", JSON.toJSONString(queryDevicePictureFileResponse));
                throw new ServiceWarnException(body.getErrorMessage() == null ? "查询IPC设备获取的图片有误,请联系管理员。" : body.getErrorMessage());
            }
        } catch (TeaException error) {
            // 如有需要,请打印 error
            log.error("调用该接口查询IPC设备获取的图片信息,{}", error.message);
        } catch (Exception _error) {
            TeaException error = new TeaException(_error.getMessage(), _error);
            // 如有需要,请打印 error
            log.error("调用该接口查询IPC设备获取的图片信息,{}", error.message);
        }
        return null;
    }
    private Client getClient() throws Exception {
        Config config = new Config().setAccessKeyId(aliiotConfig.getAccessKeyId()).setAccessKeySecret(aliiotConfig.getAccessKeySecret());
        config.endpoint = aliiotConfig.getEndpoint();
        return new Client(config);
    }

主要引入的包

import com.aliyun.iot20180120.models.BatchGetDeviceStateRequest;
import com.aliyun.iot20180120.models.BatchGetDeviceStateResponse;
import com.aliyun.iot20180120.models.BatchGetDeviceStateResponseBody;
import com.aliyun.linkvisual20180120.Client;
import com.aliyun.linkvisual20180120.models.*;
import com.aliyun.tea.TeaException;
import com.aliyun.teaopenapi.models.Config;

服务器端订阅AMQP

官方文档
官方文档介绍
官方文档介绍的AmqpClient.java,主要是main方法运行,肯定不适用咱们微服务启动的,所以还需要单独调整或者修改方式,接入自己的代码平台中。

改版后:
AmqpClient.java

package com.dindo.monitoring.mq;

import cn.hutool.core.util.IdUtil;
import com.dindo.monitoring.config.AliiotConfig;
import com.dindo.monitoring.mq.aliiot.JmsConnectionImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.qpid.jms.JmsConnection;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.jms.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;

/**
 * @author GMaya
 * @create 2022/12/28 17:26
 * @Description 类描述: TODO 当正式环境使用时, 测试环境不在进行消息订阅,避免和正式环境消息订阅产生冲突
 */
@Slf4j
@Component
public class AmqpClient {

    @Resource
    private AliiotConfig aliiotConfig;
    // 告警消息
    private static String consumerGroupId_alarm = "xxxxxxxxx";
    // 设备运行状态消息
    private static String consumerGroupId_run = "xxxxxxxxx";
    // 设备基本信息消费组
    private static String consumerGroupId_info = "xxxxxxxxxxxx";

    private static String clientId = IdUtil.simpleUUID();

    private static int connectionCount = 1;

    @Resource
    @Qualifier("MessageListenerImpl")
    private MessageListener messageListenerImpl;
    @Resource
    private JmsConnectionImpl jmsConnectionImpl;

    @PostConstruct
    public void init() throws Exception {
        List<Connection> connections = new ArrayList<>();
        List<String> consumerGroupIdList = new ArrayList<>();
        consumerGroupIdList.add(consumerGroupId_alarm);
        consumerGroupIdList.add(consumerGroupId_run);
        consumerGroupIdList.add(consumerGroupId_info);

        for (String consumerGroupId : consumerGroupIdList) {
            //参数说明,请参见AMQP客户端接入说明文档。
            for (int i = 0; i < connectionCount; i++) {
                long timeStamp = System.currentTimeMillis();
                //签名方法:支持hmacmd5、hmacsha1和hmacsha256。
                String signMethod = "hmacsha1";

                //userName组装方法,请参见AMQP客户端接入说明文档。
                String userName = clientId + "-" + i + "|authMode=aksign"
                        + ",signMethod=" + signMethod
                        + ",timestamp=" + timeStamp
                        + ",authId=" + aliiotConfig.getAccessKeyId()
                        + ",iotInstanceId=" + aliiotConfig.getIotInstanceId()
                        + ",consumerGroupId=" + consumerGroupId
                        + "|";
                //计算签名,password组装方法,请参见AMQP客户端接入说明文档。
                String signContent = "authId=" + aliiotConfig.getAccessKeyId() + "&timestamp=" + timeStamp;
                String password = doSign(signContent, aliiotConfig.getAccessKeySecret(), signMethod);
                String connectionUrl = "failover:(amqps://" + aliiotConfig.getAmqpHost() + ":5671?amqp.idleTimeout=80000)"
                        + "?failover.reconnectDelay=30";

                Hashtable<String, String> hashtable = new Hashtable<>();
                hashtable.put("connectionfactory.SBCF", connectionUrl);
                hashtable.put("queue.QUEUE", "default");
                hashtable.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.qpid.jms.jndi.JmsInitialContextFactory");
                Context context = new InitialContext(hashtable);
                ConnectionFactory cf = (ConnectionFactory) context.lookup("SBCF");
                Destination queue = (Destination) context.lookup("QUEUE");
                // 创建连接。
                Connection connection = cf.createConnection(userName, password);
                connections.add(connection);

                ((JmsConnection) connection).addConnectionListener(jmsConnectionImpl);
                // 创建会话。
                // Session.CLIENT_ACKNOWLEDGE: 收到消息后,需要手动调用message.acknowledge()。
                // Session.AUTO_ACKNOWLEDGE: SDK自动ACK(推荐)。
                Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
                connection.start();
                // 创建Receiver连接。
                MessageConsumer consumer = session.createConsumer(queue);
                consumer.setMessageListener(messageListenerImpl);
            }
        }


    }


    /**
     * 计算签名,password组装方法,请参见AMQP客户端接入说明文档。
     */
    private String doSign(String toSignString, String secret, String signMethod) throws Exception {
        SecretKeySpec signingKey = new SecretKeySpec(secret.getBytes(), signMethod);
        Mac mac = Mac.getInstance(signMethod);
        mac.init(signingKey);
        byte[] rawHmac = mac.doFinal(toSignString.getBytes());
        return Base64.encodeBase64String(rawHmac);
    }
}

JmsConnectionImpl.java

package com.dindo.monitoring.mq.aliiot;

import lombok.extern.slf4j.Slf4j;
import org.apache.qpid.jms.JmsConnectionListener;
import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
import org.springframework.stereotype.Component;

import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Session;
import java.net.URI;

/**
 * @author GMaya
 * @create 2022/12/28 18:33
 * @Description 类描述:
 */
@Slf4j
@Component
public class JmsConnectionImpl implements JmsConnectionListener {
    /**
     * 连接成功建立。
     */
    @Override
    public void onConnectionEstablished(URI remoteURI) {
        log.info("连接成功建立。, remoteUri:{}", remoteURI);
    }

    /**
     * 尝试过最大重试次数之后,最终连接失败。
     */
    @Override
    public void onConnectionFailure(Throwable error) {
        log.error("尝试过最大重试次数之后,最终连接失败, {}", error.getMessage());
    }

    /**
     * 连接中断。
     */
    @Override
    public void onConnectionInterrupted(URI remoteURI) {
        log.info("连接中断。, remoteUri:{}", remoteURI);
    }

    /**
     * 连接中断后又自动重连上。
     */
    @Override
    public void onConnectionRestored(URI remoteURI) {
        log.info("连接中断后又自动重连上, remoteUri:{}", remoteURI);
    }

    @Override
    public void onInboundMessage(JmsInboundMessageDispatch envelope) {}

    @Override
    public void onSessionClosed(Session session, Throwable cause) {}

    @Override
    public void onConsumerClosed(MessageConsumer consumer, Throwable cause) {}

    @Override
    public void onProducerClosed(MessageProducer producer, Throwable cause) {}
}

MessageListenerImpl.java

package com.dindo.monitoring.mq.aliiot;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.jms.Message;
import javax.jms.MessageListener;

/**
 * @author GMaya
 * @create 2022/12/28 18:30
 * @Description 类描述: 消息消费类,订阅的消费组消息都会到此处
 */
@Component
@Slf4j
public class MessageListenerImpl implements MessageListener {

    @Resource
    private AliiotMessage aliiotMessage;

    @Override
    public void onMessage(Message message) {
        try {
            //1.收到消息之后一定要ACK。
            // 推荐做法:创建Session选择Session.AUTO_ACKNOWLEDGE,这里会自动ACK。
            // 其他做法:创建Session选择Session.CLIENT_ACKNOWLEDGE,这里一定要调message.acknowledge()来ACK。
            // message.acknowledge();
            //2.建议异步处理收到的消息,确保onMessage函数里没有耗时逻辑。
            // 如果业务处理耗时过程过长阻塞住线程,可能会影响SDK收到消息后的正常回调。
//            processMessage(message);
            aliiotMessage.processMessage(message);
        } catch (Exception e) {
            log.error("阿里物联网消息推送处理失败", e);
        }
    }

    private static void processMessage(Message message) {
        try {
            byte[] body = message.getBody(byte[].class);
            String content = new String(body);
            String topic = message.getStringProperty("topic");
            String messageId = message.getStringProperty("messageId");
            log.info("获取的阿里iot推送的相关消息 message"
                    + ",\n topic = " + topic
                    + ",\n messageId = " + messageId
                    + ",\n content = " + content);
        } catch (Exception e) {
            log.error("processMessage occurs error ", e);
        }
    }
}

具体的消费处理类
AliiotMessage.java

package com.dindo.monitoring.mq.aliiot;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.dindo.core.tool.utils.Func;
import com.dindo.monitoring.config.AliiotConfig;
import com.dindo.monitoring.constant.MonitorConstant;
import com.dindo.monitoring.entity.MonitorDeviceAliiotEntity;
import com.dindo.monitoring.mq.aliiot.entity.BasicInfoBean;
import com.dindo.monitoring.service.entity.IEntityMonitorDeviceAliiotService;
import com.dindo.monitoring.utils.AliYunInternetLinkVisualUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.jms.JMSException;
import javax.jms.Message;
import java.util.List;

/**
 * @author GMaya
 * @create 2022/12/29 10:02
 * @Description 类描述: 阿里iot物联网视频服务消息处理器
 *
 */
@Service
@Slf4j
public class AliiotMessage {

    /**
     * 运行状态topic
     */
    private static String runStats = "/as/mqtt/status";
    /**
     * 设备信息topic
     */
    private static String devInfo = "/user/property/post";
    /**
     * 告警topic
     */
    private static String eventIntell = "/thing/event/IntelligentAlarm/post";

    @Resource
    private IEntityMonitorDeviceAliiotService iEntityMonitorDeviceAliiotService;

    @Resource
    private AliiotConfig aliiotConfig;
    @Resource
    private AliYunInternetLinkVisualUtil aliYunInternetLinkVisualUtil;

    /**
     * 异步处理阿里云平台推送的相关消息
     * @param message 消息
     */
    @Async
    public void processMessage(Message message) throws JMSException {

        byte[] body = message.getBody(byte[].class);
        String content = new String(body);
        String topic = message.getStringProperty("topic");
        String messageId = message.getStringProperty("messageId");
        log.info("获取的阿里iot推送的相关消息,topic={},messageId={},content={}",topic,messageId,content);

        if(topic.contains(runStats)){
            // 设备运行状态变更,在线或者离线
            log.info("获取的阿里iot推送的相关消息,设备运行状态事件,topic={},messageId={},content={}",topic,messageId,content);
        }

        if(topic.contains(devInfo)){
            // 设备基本信息
            log.info("获取的阿里iot推送的相关消息,设备基本信息,topic={},messageId={},content={}",topic,messageId,content);
            this.devInfo(content);
        }

        if(topic.contains(eventIntell)){
            // 告警事件
            log.info("获取的阿里iot推送的相关消息,告警事件,topic={},messageId={},content={}",topic,messageId,content);
        }
    }

    public void devInfo(String content){

        BasicInfoBean basicInfoBean = JSON.parseObject(content, BasicInfoBean.class);

        List<MonitorDeviceAliiotEntity> list = iEntityMonitorDeviceAliiotService.list(Wrappers.<MonitorDeviceAliiotEntity>query().lambda()
                .eq(MonitorDeviceAliiotEntity::getDeviceName, basicInfoBean.getDeviceName()));

        if(Func.isEmpty(list)){
            // 如果数据库不存在此设备,则进行新增
            MonitorDeviceAliiotEntity deviceAliiot = new MonitorDeviceAliiotEntity();
            deviceAliiot.setDeviceName(basicInfoBean.getDeviceName());
            deviceAliiot.setProductKey(basicInfoBean.getProductKey());
            deviceAliiot.setSerialNo(basicInfoBean.getSerialNo());
            deviceAliiot.setIotInstanceId(aliiotConfig.getIotInstanceId());
            deviceAliiot.setDeviceFactory(MonitorConstant.ALIYUN_INTERNET);
            log.info("阿里物联网设备推送新增:{}", JSON.toJSONString(deviceAliiot));
            iEntityMonitorDeviceAliiotService.save(deviceAliiot);

            try {
                // 调用该接口设置IPC设备的云存储图片生命周期。
                aliYunInternetLinkVisualUtil.setDevicePictureLifeCycleWithOptions(aliiotConfig.getIotInstanceId(),basicInfoBean.getProductKey(),basicInfoBean.getDeviceName());
                // 如果后续有需要设置录像,此处设置IPC设备的录像生命周期
//                aliYunInternetLinkVisualUtil.setDeviceRecordLifeCycleRequest(aliiotConfig.getIotInstanceId(),basicInfoBean.getProductKey(),basicInfoBean.getDeviceName());
            } catch (Exception e) {
                log.info("设置过期时间失败:{}", JSON.toJSONString(basicInfoBean));
            }

        }
    }



}


总结

综上只是服务器端对接云端SDK。部分功能的实现, 具体业务还需要根据自己平台的业务进行处理和变更。

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

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

相关文章

Mac退出移动硬盘时显示“磁盘无法推出,因为一个或多个程序正在使用它”解决方案

解决方法1. 重启访达2. 重启电脑3. 终端命令行方法4. df -lh不显示移动磁盘名称时的解决方法1. 重启访达 按住option键&#xff0c;在底部程序坞的访达图标右键&#xff0c;选择重新启动。此时访达app会重启&#xff0c;之后尝试推出即可。 或&#xff1a;点击左上角苹果标&a…

CSDN 2021-2022年微博情感数据分析

微博情感分析是一种用于提取微博文本中的情感倾向的方法。它可以帮助企业了解人们对于某个主题的看法和态度。 如果要进行微博情感分析&#xff0c;需要准备一些微博数据。可以使用爬虫程序爬取相关微博数据&#xff0c;这里使用的 Scrapy 框架进行的数据爬虫。可以使用文本分…

JavaWeb:Servlet概述

1.1 简介 Servlet是JavaWeb最为核心的内容&#xff0c;它是Java提供的一门动态web资源开发技术。 使用Servlet就可以实现&#xff0c;根据不同的登录用户在页面上动态显示不同内容。 Servlet是JavaEE规范之一&#xff0c;其实就是一个接口&#xff0c;将来我们需要定义Servle…

产品经理的需求分析四个层次

产品经理的需求分析四个层次&#xff1a; 1、第一层次是实现需求&#xff0c;即客户要啥做啥。 2、第二层次是分析转换需求&#xff0c;即客户的真正需求&#xff0c;可能实际和他提的需求不一样&#xff0c;比如客户只是要过河&#xff0c;却提出造一个轮船。所以产品经理需要…

MPS | 简单易用的工业电源模块

工业与医疗应用中&#xff0c;在较高输入电压条件下&#xff0c;输出正压和负压的应用需求越来越多。 在应对输出负压条件时&#xff0c;传统解决方案电路复杂且体积庞大&#xff0c;研发周期较长。以半导体测试为例&#xff0c;新一代的测试机通常需要具备以下特点&#xff1…

TCP三次握手四次挥手详解

三次握手 第一次&#xff1a;客户端发送请求连接的报文&#xff1b;SYN1&#xff0c;表请求建立连接的报文&#xff1b;seq,序列号&#xff0c;随机。 第二次&#xff1a;服务端发送请求连接和同意连接的报文&#xff1b;ACK1&#xff0c;表示确认号有用&#xff1b;ackx1&am…

【一起从0开始学习人工智能】0x01机器学习基础+初次实践

从零开始----到敲出一个推荐系统 文章目录人工智能概述流派能做什么什么是机器学习数据集构成机器学习算法分类机器学习开发流程学习框架和资料怎么做机器学习库与框架可用数据集sklearn使用自带数据集sklearn数据集使用拿到的数据是否全部用来训练模型人工智能概述 人工智能-…

Linux下对文件权限的理解

一、权限的概念 Linux下有两种用户&#xff1a;超级用户&#xff08;root&#xff09;、普通用户。 超级用户&#xff1a;可以再linux系统下做任何事情&#xff0c;不受限制 普通用户&#xff1a;在linux下做有限的事情。 超级用户的命令提示符是“#”&#xff0c;普通用户的命…

【Python爬虫 • selenium】selenium4新版本自动获取驱动的常见问题

文章目录前言一、安装驱动二、使用步骤1.导入包2.生成驱动3.打开网站二、selenium闪退问题处理1. selenium版本与代码不匹配2. selenium代码异常三、代码示例1.selenium4代码示例1. Chrome2. Chromium3. Brave4. Firefox5. IE6. Edge7. Opera2.selenium3代码示例1. Chrome2. Ch…

蓄热式加热炉燃烧技术

通过阅读前辈们的一些文章&#xff0c;关于蓄热式加热炉燃烧技术方面进行了总结。 一个蓄热燃烧单元至少由两个烧嘴本体、两个体积紧凑的蓄热室、换向阀和与之配套的控制系统组成&#xff0c;即应用蓄热式 (高温空气 )燃烧技术的炉子烧嘴需成对安装&#xff0c;当烧嘴 A 工作时…

【云原生】K8s PSP 和 securityContext 介绍与使用

文章目录一、概述二、PodSecurityPolicy 的发展1&#xff09;以前为什么需要 PodSecurityPolicy&#xff1f;2&#xff09;现在为什么 PodSecurityPolicy 要消失&#xff1f;三、PSP 简单使用1&#xff09;开启PSP2&#xff09;示例演示1、没有PSP场景测试2、定义PSP【1】资源限…

C++中的多态(原理篇)

多态的原理 虚函数表 下面这一串代码 class A { public:virtual void func(){cout << "func1()" << endl;} private:int _a; };我们看到了a对象的大小是8bit大小&#xff0c;但是a对象里面不应该只是一个_a吗&#xff1f;当我们打开监视窗口发现 a对象…

C++STL-list的简易实现

文章目录1. list的介绍2. 迭代器的分类3. list的构造4. list的实现4.1 list的基本结构4.2 list的push_back函数4.2 list的迭代器4.2.1 operator- >4.2.2 const迭代器4.3 insert函数4.4 earse函数4.5 迭代器失效问题4.6 析构函数4.7 构造函数4.8 拷贝构造1. 传统写法2. 现代写…

【C++升级之路】第四篇:类和对象(下)

&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&#x1f31f; &#x1f36d;&#x1f36d;系列专栏&#xff1a;【C学习与应用】 ✒️✒️本篇内容&#xff1a;类与对象知识汇总&#xff0c;包括初始化列表的基本概念和使用的注意事项、explicit关键字、C/C中的static成…

Python【方法和返回值(Union)联合类型】注解

什么是类型注解&#xff1a;供调用者在使用函数&#xff08;方法&#xff09;时&#xff0c;如果没有完善的文档作为参考&#xff0c;开发者不知道要给定义的【变量、方法中的函数、】传入什么数据类型&#xff0c;以免减少编译错误。有了类型注解可以让 IDE 知道了数据类型后&…

C++语法2——for、while、do-while的语法及区别

C语言语法1详情请看这两篇博客&#xff1a;&#xff08;此号为本人小号&#xff09; 四则运算及基本语法 数据类型 接下来要讲得是循环语句 for循环 基本语法&#xff1a; for(表达式1&#xff1b;表达式2&#xff1b;表达式3) {内嵌语句&#xff1b; }执行顺序&#xff1a;…

js如何计算年龄?如何创建Javascript 年龄计算器?

如何创建年龄计算器? 要构建这个项目,我们需要HTML,CSS和Javascript。 让我们来看看这个项目是如何工作的。项目由输入日期组成。用户必须单击它并选择他们的出生日期或任何所需的日期。在此之后,用户必须单击计算按钮。用户单击计算按钮后,我们会根据他们输入的日期(…

深入理解ConcurrentLinkedQueue源码

1. 概述 在我们的日常开发中&#xff0c;经常会使用队列这种数据结构&#xff0c;需要它的队尾进、队头出的特点。于是&#xff0c;Doug Lea大师设计了一个线程安全的队列ConcurrentLinkedQueue&#xff0c;它是采用链表的形式构成的。我们接下来尝试通过代码去了解其中的设计…

S7-200SMART通过表格指令实现模拟量信号滑动平均值滤波的具体方法

S7-200SMART通过表格指令实现模拟量信号滑动平均值滤波的具体方法 当现场的模拟量信号波动太大,而通过硬件的方式尚无法实现平稳的信号输入时,可采用软件上的滤波进行信号处理, 本次和大家分享的即通过取多个信号值的平均值的方式实现模拟量滤波的具体方法示例,仅供大家参考…

DataNode节点下线速度优化

目录 一、节点掉线或退役 1.1区分节点掉线和节点退役的区别 1.2 如何处理节点掉线出现的各种风暴 1.2.1 Datanode的block复制 1.2.2 控制节点掉线RPC风暴的参数 二、如何快速节点下线 一、节点掉线或退役 背景&#xff1a;5台数据节点&#xff0c;存储40T数据 block数112…