OpenHarmony开发实例:【分布式游戏鉴权应用】

 1.介绍

本文将介绍分布式游戏鉴权应用。操作过程为:

  1. 设备A点击“开始游戏”按钮,开始搜索周边设备。

  2. 设备A显示周边设备,点击设备B并发起连接请求,远程拉起设备B的FA。

  3. 设备B收到请求后,选择是否允许“开启游戏”。

    • 选择允许,远程拉起设备A,并传递允许的信息,设备A解析了信息后自动开始游戏。
    • 选择不允许,远程拉起设备A,并传递不允许的信息,设备A回到最初的状态,并提示申请鉴权未通过。

效果图展示:

image.png

2.相关概念

gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md鸿蒙开发文档参考,点击或者复制转到。

3.搭建OpenHarmony环境

完成本篇Codelab我们首先要完成开发环境的搭建,本示例以RK3568开发板为例,参照以下步骤进行:

  1. [获取OpenHarmony系统版本]:标准系统解决方案(二进制)。

    以3.1版本为例:

  2. 搭建烧录环境。

    1. [完成DevEco Device Tool的安装]
    2. [完成RK3568开发板的烧录]

搜狗高速浏览器截图20240326151547.png

鸿蒙HarmonyOS与OpenHarmony籽料

 

mau123789是v直接拿取

  1. 搭建开发环境。

    1. 开始前请参考[工具准备] ,完成DevEco Studio的安装和开发环境配置。
    2. 开发环境配置完成后,请参考[使用工程向导] 创建工程(模板选择“Empty Ability”) ,选择JS或者eTS语言开发。
    3. 工程创建完成后,选择使用[真机进行调测] 。

4.分布式组网

本章节以系统自带的音乐播放器为例(具体以实际的应用为准),介绍如何完成两台设备的分布式组网。 

  1. 硬件准备:准备两台烧录相同的版本系统的RK3568开发板A、B。

  2. 开发板A、B连接同一个WiFi网络。

    打开设置-->WLAN-->点击右侧WiFi开关-->点击目标WiFi并输入密码。

image.png

  1. 将设备A,B设置为互相信任的设备。

    • 找到系统应用“音乐”。

    • 设备A打开音乐,点击左下角流转按钮,弹出列表框,在列表中会展示远端设备的id。

    • 选择远端设备B的id,另一台开发板(设备B)会弹出验证的选项框。

image.png

 - 设备B点击允许,设备B将会弹出随机PIN码,将设备B的PIN码输入到设备A的PIN码填入框中。

配网完毕。

5.代码结构解读

本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在参考中提供下载方式,整个工程的代码结构如下:

  • common:存放公共资源

  • pages:存放页面

    index.js:主页面

  • config.json:配置文件

6.初始化页面

在本章节中,您将学会如何进行页面初始化。

  1. 在data下定义需要使用的字段。

    data: {
      // 目标设备Id,用于记录申请过来的设备Id
      targetDeviceId: '',
      // 是否同意玩游戏
      isAgree: false,
      // 是否显示开始游戏图标
      showStart: false
    },

  2. 根据Ability启动参数来判断页面被拉起的状态。

    在拉起页面时候,设置requestType为分布式拉起页面的业务请求类型(申请鉴权或者回复鉴权结果),如果没有requestType参数,则为手动拉起本机Ability。然后通过分析requestType参数的值来进行不同的业务逻辑操作。

    onInit() {
      // 获取Ability启动参数
      featureAbility.getWant().then((want) => {
        if (want.parameters !== undefined && want.parameters !== null && want.parameters !== '') {
          // 如果是请求授权被拉起Ability(requestType === 0),则记录申请权限的设备id
          if (want.parameters.requestType === 0) {
            this.isGame = false;
            this.targetDeviceId = want.parameters.localDeviceId;
          } else if (want.parameters.requestType === 1) {
            // 如果是授权后被拉起Ability(requestType === 1),则根据授权情况判断是否进行游戏
            if (want.parameters.isAgree !== null) {
              this.isAgree = want.parameters.isAgree;
              if (this.isAgree === true) {
                this.isGame = true;
                this.isStart = true;
                this.startGame();
              } else {
                this.showStart = true;
                prompt.showToast({
                  message: '申请授权未被允许',
                  duration: 5000
                });
              }
            }
            this.targetDeviceId = want.parameters.localDeviceId;
          } else {
            // 如果没有请求类型字段(requestType),则表明是手动启动的Ability,此时显示启动游戏图标
            this.showStart = true;
          }
        }
      });

7.显示鉴权设备

在本章节中,您将学会如何显示需要鉴权的设备列表。效果图如下:

  1. 在index.js文件中,在data下定义deviceList数组,用来表示周边的设备。代码如下:

    export default {
      data: {
        //可授权的设备
        deviceList: []
      }
    }

  2. 在index.hml文件中:

    • 定义一个"开始游戏"的button组件,设置startFA的点击事件;
    • 显示周边设备的对话框dialog,使用list 、list-item实现设备列表的展示;
    • 通过for属性遍历deviceList数组,$item是每一项的实例;
    • 给每一项设置selectDevice点击事件,参数为设备的networkId。

    代码如下:

    <div class="container">
        <button class="text-button" onclick="startFA">开始游戏</button>
        <dialog id="continueAbilityDialog" class="dialog-main" oncancel="cancelDialog">
            <div class="dialog-div">
                <text class="dialog_title_text">选择设备</text>
                <list class="dialog_device_list" divider="true">
                    <list-item for="{{ deviceList }}" class="device_list_item">
                        <div>
                            <label class="device_item_title" target="{{ $item.id }}">{{ $item.name }}</label>
                            <input class="device_item_radio" type="radio" checked="{{ $item.id === 'localhost' }}"
                                   id="{{ $item.id }}"
                                   name="radioSample" value="{{ $item.id }}"
                                   onchange="onRadioChange({{ $item.id }})"></input>
                        </div>
                    </list-item>
                </list>
                <div class="inner-btn">
                    <button class="dialog_cancel_button" type="text" value="取消" onclick="onDismissDialogClicked"></button>
                </div>
            </div>
        </dialog>
    </div>

  3. 在index.css文件中,定义布局和样式。代码如下:

    .container {
        flex-direction: column;
        justify-content: center;
        align-items: center;
    }
    
    .text-button{
        background-color: #5959f1;
        color: #FFFFFF;
        text-align: center;
        font-size: 16px;
        width: 80px;
        height: 40px;
        border-radius: 8px;
    }
    
    .select-device-dialog {
        width: 90%;
        height: 33%;
    }
    
    .select-device-wrapper {
        margin: 5%;
        width: 90%;
        height: 90%;
        flex-direction: column;
    }
    
    .select-device-title {
        width: 100%;
        height: 20%;
        text-align: left;
        font-size: 20px;
    }
    
    .select-device-list {
        width: 100%;
        height: 60%;
        text-align: left;
        font-size: 15px;
    }
    
    .select-device-item {
        width: 100%;
        height: 33%;
    }
    
    .select-device-item-left {
        width: 100%;
        height: 100%;
        text-align: left;
        font-size: 16px;
    }
    
    .dialog-main {
        width: 500px;
    }
    
    .dialog-div {
        flex-direction: column;
        align-items: center;
    }
    
    .dialog_title_text {
        width: 434px;
        height: 80px;
        font-size: 32px;
        font-weight: 600;
    }
    
    .dialog_cancel_button {
        width: 100%;
        font-size: 32px;
    }

  4. 在index.js文件中:

    • 定义createDeviceManager方法,获得设备管理器实例并进行获得同一网段下的所有在线设备;

      // 创建实例
        createDeviceManager() {
          if (dmClass !== null) {
            return;
          }
          deviceManager.createDeviceManager('com.huawei.cookbook', (err, data) => {
            if (err) {
              return;
            }
            subscribeId = Math.floor(Math.random() * 10000 + 1000);
            dmClass = data;
            dmClass.on('dmFaCallback', data => this.log('dmFaCallback on:' + JSON.stringify(data)));
            dmClass.on('deviceStateChange', mFilterOption, data => this.log('deviceStateChange on:' + JSON.stringify(data)));
            dmClass.on('deviceFound', data => this.log('deviceFound on:' + JSON.stringify(data)));
            dmClass.on('discoverFail', data => this.log('discoverFail on:' + JSON.stringify(data)));
            dmClass.on('serviceDie', data => this.log('serviceDie on:' + JSON.stringify(data)));
            this.getLocalDeviceInfoSync();
            const deviceInfoList = dmClass.getTrustedDeviceListSync();
            const list = [];
            list[0] = DEVICE_LIST_LOCALHOST;
            if (deviceInfoList.length > 0) {
              for (let i = 0; i < deviceInfoList.length; i++) {
                list[i + 1] = {
                  name: deviceInfoList[i].deviceName,
                  id: deviceInfoList[i].deviceId
                };
              }
            }
            this.deviceList = list;
          });
        },

    • 定义getLocalDeviceInfoSync方法,获取本设备信息;

      getLocalDeviceInfoSync() {
          if (dmClass != null) {
            deviceInfo = dmClass.getLocalDeviceInfoSync();
          } else {
            prompt.showToast({
              message: '请先初始化'
            });
          }
        },

    • 将获取到的同一网段下的所有在线设备信息放入deviceList数组中;

    • 通过this.$element('showDialog')找到hml文件中dialog组件,调用show()方法显示对话框。

8.鉴权申请与回应

在本章节中,您将学会如何从设备A拉起设备B的FA,并将设备A的标识信息发送给设备B。效果图如下:

image.png

申请鉴权(同意游戏)

申请鉴权(拒绝游戏)

  1. 设备A点击开始游戏,显示可以进行鉴权申请的设备列表,并选中设备申请游戏鉴权

    1. 定义startFa方法,用以显示设备列表对话框;

      startFA() {
          this.$element('continueAbilityDialog').show();
        },

    2. 定义onRadioChange方法,用以监听选择的设备变化;

      onRadioChange(inputValue, e) {
          if (inputValue === e.value) {
            if (e.value === 'localhost') {
              this.$element('continueAbilityDialog').close();
              return;
            }
            if (this.deviceList.length > 0) {
              for (let i = 0; i < this.deviceList.length; i++) {
                if (this.deviceList[i].id === e.value) {
                  this.startAbilityContinuation(this.deviceList[i].id, this.deviceList[i].name);
                }
              }
            }
          }
        },

    3. 定义startAbilityContinuation方法,用以申请鉴权;

      startAbilityContinuation(deviceId, deviceName) {
          this.$element('continueAbilityDialog').close();
          const wantValue = {
            bundleName: 'com.huawei.cookbook',
            abilityName: 'com.huawei.gameauthopenh.MainAbility',
            deviceId: deviceId,
            // localDeviceId:申请设备的id,requestType,请求类型:0,申请鉴权
            parameters: {'localDeviceId': deviceInfo.deviceId, 'requestType': 0}
          };
      
          featureAbility.startAbility({
            want: wantValue
          }).then((data) => {
            // 销毁自身Ability
            featureAbility.terminateSelf();
          });
        },

  2. 设备B被设备A分布式拉起,对游戏进行授权

    1. index.hml页面添加div用以显示授权选项;

      <div class="div-permit" if="{{!isGame}}" >
          <text class="text-title">来自远程合成设备小游戏权限请求,是否允许?</text>
          <div class="div-button"  >
              <text class="text-allow" onclick="responds(true)">允许</text>
              <text class="text-reject" onclick="responds(false)">不允许</text>
          </div>
      </div>

    2. 定义responds方法用以反馈鉴权结果,并分布式拉起设备A的Ability;

      responds(value) {
          const wantValue = {
            bundleName: 'com.huawei.cookbook',
            abilityName: 'com.huawei.gameauthopenh.MainAbility',
            deviceId: this.targetDeviceId,
            parameters: {'localDeviceId': deviceInfo.deviceId, 'requestType': 1, 'isAgree': value}
          };
          featureAbility.startAbility({
            want: wantValue
          }).then((data) => {
            console.info('featureAbility.startAbility finished, ' + JSON.stringify(data));
            featureAbility.terminateSelf();
          });
        },

  3. 设备A被分布式拉起并解析鉴权结果,并根据结果执行不同的操作;

    在onInit方法中调用featureAbility.getWant()来获取启动信息并根据启动信息判断游戏申请是否被拒绝;

     
    onInit() {
      ...
      // 获取Ability启动参数
      featureAbility.getWant().then((want) => {
        if (want.parameters !== undefined && want.parameters !== null && want.parameters !== '') {
          // 如果是请求授权被拉起Ability(requestType === 0),则记录申请权限的设备id
          if (want.parameters.requestType === 0) {
            this.isGame = false;
            this.targetDeviceId = want.parameters.localDeviceId;
          } else if (want.parameters.requestType === 1) {
            // 如果是授权后被拉起Ability(requestType === 1),则根据授权情况判断是否进行游戏
            if (want.parameters.isAgree !== null) {
              this.isAgree = want.parameters.isAgree;
              if (this.isAgree === true) {
                this.isGame = true;
                this.isStart = true;
                this.startGame();
              } else {
                this.showStart = true;
                prompt.showToast({
                  message: '申请授权未被允许',
                  duration: 5000
                });
              }
            }
            this.targetDeviceId = want.parameters.localDeviceId;
          } else {
            // 如果没有请求类型字段(requestType),则表明是手动启动的Ability,此时显示启动游戏图标
            this.showStart = true;
          }
        }
      });
      ...
    },

  4. index.css文件新增内容如下:

    .div-permit{
        flex-direction: column;
        justify-content: center;
        align-items: center;
        width: 100%;
        height: 100%;
    }
    .div-button{
        flex-direction: row;
        justify-content: center;
        align-items: center;
    }
    .text-title{
        color: #222222;
        font-size: 22px;
        align-items: center;
        align-content: center;
        margin: 20px;
    }
    .text-allow{
        color: #3E7BDE;
        font-size: 18px;
        margin-right: 10px;
    }
    .text-reject{
        color: #212121;
        font-size: 18px;
        margin-left: 10px;
    }

9.游戏:图形的运动、碰撞与合成

  • [图形的运动]
  • [图形的碰撞与合成

如下图所示,按照从左到右的顺序,相同的图形碰撞合成下一个图形,最终合成OpenHarmony图形。

效果图预览:

图形的运动

  1. 在index.js的data下定义图片资源数组imgArray和显示在屏幕中图片的数组modes。代码如下:

    export default {
      data: {
        // 图片数组
        imgArray: ['common/images/product0.png', 'common/images/product1.png',
          'common/images/product2.png', 'common/images/product3.png',
          'common/images/product4.png', 'common/images/product5.png',
          'common/images/product6.png'],
        //在屏幕中出现的数据
        modes: [],
      }
    }

    modes添加数据模型格式为:要显示的图形路径src、图形的宽度width、图形的高度height、图形的等级level(用于区分不同的图形),以及图形的左坐标left、顶部坐标top和其在x、y方向上的速度。新增一个数据模型到数组中,代码如下:

    addNewData() {
      var index = Math.floor(Math.random() * 4);
      var src = this.imgArray[index];
      var width = 50 + index * 10;
      var height = 50 + index * 10;
    
      this.modes.push({
        level: index,
        width: width,
        height: height,
        src: src,
        top: 0,
        left: 120,
        speedX: 0,
        speedY: 10,
      })
    }

  2. 在index.hml文件中,遍历modes数组,用Image组件显示图形,只需要动态更改class、style、src等属性即可。代码如下:

    <div class="div-image" if="{{isStart}}">
        <image for="{{ (index, item) in modes }}"
               class="product{{ item.level }}"
               style="top : {{ item.top }}; left : {{ item.left }}" src="{{ item.src }} "/>
    </div>

    对应的index.css新增内容如下:

    .div-image{
        flex-direction: column;
        justify-content: flex-start;
        align-items: flex-start;
        width: 100%;
        height: 100%;
    }
    
    .product0{
        width: 50px;
        height: 50px;
        position: absolute;
    }
    .product1{
        width: 60px;
        height: 60px;
        position: absolute;
    }
    .product2{
        width: 70px;
        height: 70px;
        position: absolute;
    }
    .product3{
        width: 80px;
        height: 80px;
        position: absolute;
    }
    .product4{
        width: 90px;
        height: 90px;
        position: absolute;
    }
    .product5{
        width: 100px;
        height: 100px;
        position: absolute;
    }
    .product6{
        width: 110px;
        height: 110px;
        position: absolute;
    }

  3. 使用setInterval()开启定时器,反复执行excuteTask()方法,该方法用来计算图形的运动。图形的移动主要是将图形的顶部top和左侧left的坐标值,每次递增各自的x、y方向的速度值。部分代码如下:

    export default {
      startGame(){
        addNewData();
        intervalId = setInterval(this.excuteTask, 50);
      },
      excuteTask(){     
        this.modes.forEach(item => {
          item.top += item.speedY;
          item.left += item.speedX;
        });
      }
    }

图形的碰撞与合成

这部分仅介绍核心的思路,具体的实现过程读者可自行完成,其达到的效果图如下:

  1. 两个图形若满足它们的的圆心距离小于它们半径的总和,则认为它们发生了碰撞。部分代码如下:

    isCollision(run, other) {
      var runCenterX = run.left + run.width / 2;
      var runCenterY = run.top + run.width / 2;
      var otherCenterX = other.left + other.width / 2;
      var otherCenterY = other.top + other.width / 2;
      var distance = Math.sqrt(Math.abs(runCenterX - otherCenterX) * Math.abs(runCenterX - otherCenterX) +
      Math.abs(runCenterY - otherCenterY) * Math.abs(runCenterY - otherCenterY));
      if (distance < (run.width + other.width) / 2) {     return true;
      }
      return false;
    }

  2. 通过判断两个图形的等级level值是否相等,若相等就可以进行合成。部分代码如下:

    isCompose( productA,  productB) {
      return productA.level == productB.level;
    }

 最后呢,很多开发朋友不知道需要学习那些鸿蒙技术?鸿蒙开发岗位需要掌握那些核心技术点?为此鸿蒙的开发学习必须要系统性的进行。

而网上有关鸿蒙的开发资料非常的少,假如你想学好鸿蒙的应用开发与系统底层开发。你可以参考这份资料,少走很多弯路,节省没必要的麻烦。由两位前阿里高级研发工程师联合打造《鸿蒙NEXT星河版OpenHarmony开发文档》里面内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)技术知识点

如果你是一名Android、Java、前端等等开发人员,想要转入鸿蒙方向发展。可以直接领取这份资料辅助你的学习。下面是鸿蒙开发的学习路线图。

高清完整版请点击→《鸿蒙NEXT星河版开发学习文档》

针对鸿蒙成长路线打造的鸿蒙学习文档。话不多说,我们直接看详细资料鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,帮助大家在技术的道路上更进一步。

《鸿蒙 (OpenHarmony)开发学习视频》

图片

《鸿蒙生态应用开发V2.0白皮书》

图片

《鸿蒙 (OpenHarmony)开发基础到实战手册》

获取这份鸿蒙星河版学习资料,请点击→《鸿蒙NEXT星河版开发学习文档》

OpenHarmony北向、南向开发环境搭建

图片

《鸿蒙开发基础》

  1. ArkTS语言

  2. 安装DevEco Studio

  3. 运用你的第一个ArkTS应用

  4. ArkUI声明式UI开发

  5. .……

图片

《鸿蒙开发进阶》

  1. Stage模型入门

  2. 网络管理

  3. 数据管理

  4. 电话服务

  5. 分布式应用开发

  6. 通知与窗口管理

  7. 多媒体技术

  8. 安全技能

  9. 任务管理

  10. WebGL

  11. 国际化开发

  12. 应用测试

  13. DFX面向未来设计

  14. 鸿蒙系统移植和裁剪定制

  15. ……

图片

《鸿蒙开发实战》

  1. ArkTS实践

  2. UIAbility应用

  3. 网络案例

  4. ……

图片

 获取这份鸿蒙星河版学习资料,请点击→《鸿蒙NEXT星河版开发学习文档》

总结

鸿蒙—作为国家主力推送的国产操作系统。部分的高校已经取消了安卓课程,从而开设鸿蒙课程;企业纷纷跟进启动了鸿蒙研发

并且鸿蒙是完全具备无与伦比的机遇和潜力的;预计到年底将有 5,000 款的应用完成原生鸿蒙开发,未来将会支持 50 万款的应用那么这么多的应用需要开发,也就意味着需要有更多的鸿蒙人才。鸿蒙开发工程师也将会迎来爆发式的增长,学习鸿蒙势在必行!

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

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

相关文章

《R语言与农业数据统计分析及建模》学习——数据读入

一、工作目录 # 获取当前工作目录 getwd()# 改变工作目录为指定路径下的文件夹 # 注意工作目录的表达方式 setwd(D:/R_class) setwd(D:\\R_class) 二、文件路径 读取文件中的数据首先要确定文件路径&#xff0c;如果文件不在工作目录下&#xff0c;则必须使用绝对路径 1、文…

STL —— stack、queue

博主首页&#xff1a; 有趣的中国人 专栏首页&#xff1a; C专栏 目录 1. 容器适配器 2. 栈的模拟实现 3. 队列的模拟实现 4. 双端队列deque 4.1 deque的原理介绍 4.2 deque的缺陷 4.3 为什么选择deque作为stack和queue的底层默认容器 本篇文章主要讲解 stack 和 queue …

MDK-ARM Keil5.38 下载安装环境搭建

一、keil软件介绍 KEIL是公司的名称&#xff0c;有时候也指KEIL公司的所有软件开发工具&#xff0c;目前2005年Keil由ARM公司收购&#xff0c;成为ARM的公司之一。 MDK&#xff08;Microcontroller Development Kit&#xff09; 也称MDK-ARM、KEIL MDK、RealView MDK、KEIL For…

IDEA 设置类注释模板作者、日期、描述等信息(推荐标准!)

idea注释模版配置 idea作为越来越多程序员使用的开发工具&#xff0c;平时的代码注释也非常的关键&#xff0c;类上注释和方法上注释每次换电脑或者新同事入职都要统一修改&#xff0c;找了网上好多教程都写的乱七八糟的啥都有&#xff0c;为方便统一就自己写一个操作方法&…

【yolov5小技巧(2)】---将yolov5中的特征图以热力图的方式进行可视化

文章目录 &#x1f680;&#x1f680;&#x1f680;前言一、1️⃣ 将特征图可视化的文章CFPNet二、2️⃣yolov5自带的特征图可视化工具三、3️⃣如何将特征图转换成热力图 &#x1f440;&#x1f389;&#x1f4dc;系列文章目录 【yolov5小技巧(1)】—可视化并统计目标检测中的…

Leetcode二叉树刷题

给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true public boolean isSymmetric(TreeNode root) {if(rootnull)return true;return compare(root.left,root.right);}public boole…

Python学习笔记(37)——用xlwings库生成excel

老规矩先pip入xlwings库 STEP1:下载xlwings库 windowsr>>cmd>>pip install xlwings (如果需要不同版本可以到pypi上搜&#xff09; STEP2:完成EXCEL初级创建 请打开您的编写软件~~~~~&#xff08;小编的显示结果为PYCHARM编写的&#xff0c;因为颜色标注好看(…

113.PyQt5_QtPrintSupport_打印操作

我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448; 入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448; 虚 拟 环 境 搭 建 &#xff1a;&#x1f449;&…

光电传感器的工作原理简介

光电传感器是一种利用光电效应将光信号转换为电信号的传感器。 工作原理 光照射&#xff1a;光电传感器通过光源&#xff08;如LED或激光&#xff09;照射在其表面。 光电转换&#xff1a;光线与传感器材料发生光电反应&#xff0c;产生电信号。这种转换过程涉及到光子与电子的…

论文解读 --- 《针对PowerShell脚本的有效轻量级去混淆和语义感知攻击检测》

开篇 今天我们继续来解读安全行业优秀论文&#xff0c;通过学习他人的智慧成果&#xff0c;可以不断丰富我们的安全视野&#xff0c;使用它山之石来破解自身的难题。 这次要解读的论文为《Effective and Light-Weight Deobfuscation and Semantic-Aware Attack Detection for…

解决宝塔的FTP无法使用被动模式

问题&#xff1a;宝塔安装完ftp管理软件之后&#xff0c;无法使用被动模式连接 解决&#xff1a; 提示&#xff1a; 如果还是不行&#xff0c;那么要看看防火墙和安全组有没有放行被动模式的端口&#xff0c;宝塔安装的pure-ftpd软件的被动模式端口默认是39000至400…

使用稳压管和三极管射极输出器电路驱动PMOS

当电源电压大于PMOS 管的最大栅源电源时&#xff0c;不能直接把栅极拉到地&#xff0c;需要一点特殊的电路来限制栅极驱动电压。有的地方是用电阻分压器做的&#xff0c;比如这种&#xff1a; NPN 三极管导通时&#xff0c;MOS 管栅极电压是两个电阻中间的电压。这种设计最大的…

“华为杯“华南理工大学程序设计竞赛 L-再一道好题

题目 #include<bits/stdc.h> using namespace std; #define int long long #define pb push_back #define fi first #define se second const int maxn 1e6 5; const int inf 1e9 5;using namespace std;int n, m;void solve(){int res 0;int q;string s;int k;cin …

华为ensp中nat server 公网访问内网服务器

作者主页&#xff1a;点击&#xff01; ENSP专栏&#xff1a;点击&#xff01; 创作时间&#xff1a;2024年4月15日17点30分 NAT服务器是一种在网络边界设备上配置的服务&#xff0c;它允许外部网络的用户访问内部网络中的服务或主机&#xff0c;同时隐藏了内部网络的真实IP地…

Eigen笔记2:矩阵拼接

直接贴代码吧&#xff0c;使用的MatrixXd 和<<运算符&#xff1a; int main(int argc, char *argv[]) {Eigen::MatrixXd B(2, 2);B << 1, 2,3, 4;Eigen::MatrixXd C(2, 2);C << 5, 6,7, 8;Eigen::MatrixXd D(2, 2);D << 9, 10,11, 12;Eigen::MatrixXd…

《由浅入深学习SAP财务》:第2章 总账模块 - 2.6 定期处理 - 2.6.5 年末操作:维护新财政年度会计凭证编号范围

2.6.5 年末操作&#xff1a;维护新财政年度会计凭证编号范围 财务系统的维护者要在每年年末预先设置好下一年度的会计凭证编号范围&#xff08;number range&#xff09;&#xff0c;以便下一年度会计凭证能够顺利生成。这一操作一定要在下一年度1月1日以前预先完成。 …

基于SSM项目高校在线请假与审批系统

采用技术 基于SpringBoot框架实现的web的智慧社区系统的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringMVCMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 简介 本系统实现了管理员&#xff0c;教师&#xff0c;学生三个模…

《QT实用小工具·二十五》日志重定向输出

1、概述 源码放在文章末尾 日志重定向输出&#xff0c;包含如下功能&#xff1a; 支持动态启动和停止。支持日志存储的目录。支持网络发出打印日志。支持输出日志上下文信息比如所在代码文件、行号、函数名等。支持设置日志文件大小限制&#xff0c;超过则自动分文件&#xf…

JS - 关于DOM的介绍和使用01

DOM&#xff08;Document Object Model&#xff09;是一种用于表示和操作HTML、XML等文档结构的编程接口。在JavaScript中&#xff0c;通过DOM可以访问和操作网页中的各种元素、属性和事件。 获取元素&#xff1a; 通过ID获取元素&#xff1a;使用document.getElementById(el…

4.Godot图片素材的获取和编辑

游戏开发中经常遇到图片素材的需求 1. 图片素材的准备 术语&#xff1a;Sprite 精灵&#xff0c;游戏开发中指一张图片来源不明的图片&#xff0c;切勿在商业用途使用&#xff0c;以免引起版权风险。 1. 在学习阶段&#xff0c;可以百度或者从一些资源网站获取&#xff0c;这…