electron基础使用

安装以及运行

当前node版本18+,按照官网提供操作,npm init进行初始化操作,将index.js修改为main.js,执行npm install --save-dev electron。(这里我挂梯子下载成功了。),添加如下代码至package.json

  "scripts": {
    "start": "electron ."
  },

新建一个index.html文件,内容随意。新建一个main.js文件,内容如下。主要意思是将一个界面加载到一个应用窗口中。createWindow()方法来将index.html加载进一个新的BrowserWindow实例。在 app 模块的 ready 事件被激发后才能创建浏览器窗口。 可以通过使用 app.whenReady() API来监听此事件。 在whenReady()成功后调用createWindow()函数来打开窗口。

  • app 模块,它控制应用程序的事件生命周期。
  • BrowserWindow 模块,它创建和管理应用程序 窗口。
const { app, BrowserWindow } = require("electron");

const createWindow = () => {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
  });

  win.loadFile("index.html");
};

app.whenReady().then(() => {
  createWindow();
});

添加关闭应用窗口事件,若输出有乱码则参考该博客输出乱码解决

app.on("window-all-closed", () => {
  if (process.platform !== "darwin") {
    console.log("关闭");
    app.quit();
  }
});

在这里插入图片描述
添加代码至BrowserWindow中,可以打开控制台操作,应用开启后可以使用ctrl+shift+i打开控制台

    webContents: {
      openDevTools: true,
    },

在这里插入图片描述

vue3中运行

基于@quick-start/electron框架快速创建一个基于vue3+electron的项目结构。

npm create @quick-start/electron

最近又新看见一个框架electron-gg地址,感觉挺好的也是基于vue3

预加载脚本

Electron 的主进程是一个拥有着完全操作系统访问权限的 Node.js 环境。 除了 Electron 模组 之外,您也可以访问 Node.js 内置模块 和所有通过 npm 安装的包。 另一方面,出于安全原因,渲染进程默认跑在网页页面上,而并非 Node.js里。

主进程负责管理整个应用程序的生命周期,包含创建窗口,运行在nodejs环境中,每次打开一个窗口,实际是创建一个渲染进程。主进程和渲染进程之间通过IPC通信。

为了将 Electron 的不同类型的进程桥接在一起,我们需要使用被称为 预加载 的特殊脚本。

BrowserWindow 的预加载脚本运行在具有 HTML DOM 和 Node.js、Electron API 的有限子集访问权限的环境中。预加载脚本默认 沙盒化不再拥有完整 Node.js 环境的访问权。 实际上,这意味着你只拥有一个 polyfilled 的 require 函数,这个函数只能访问一组有限的 API。
在这里插入图片描述
预加载脚本在渲染器加载网页之前注入。 如果你想为渲染器添加需要特殊权限的功能,可以通过 contextBridge 接口定义 全局对象。

创建preload.js文件,该脚本通过 versions 这一全局变量,将 Electron 的 process.versions 对象暴露给渲染器。

const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('versions', {
  node: () => process.versions.node,
  chrome: () => process.versions.chrome,
  electron: () => process.versions.electron
  // 除函数之外,我们也可以暴露变量
})

将脚本附在渲染进程上,在 BrowserWindow 构造器中使用 webPreferences.preload 传入脚本的路径。webPreferences对象是用来定制渲染进程中的特性,其中preload属性是在网页运行其他脚本之前执行的脚本,用来提前注入Nodejs api或者其他需要再渲染进程中运行的脚本。

const { app, BrowserWindow } = require('electron')
const path = require('node:path')

const createWindow = () => {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js')
    }
  })

  win.loadFile('index.html')
}

app.whenReady().then(() => {
  createWindow()
})

现在渲染器能够全局访问 versions 了,但是还需要将版本等数据渲染到界面中,可以通过window.versions访问,也可以很简单地使用 versions 来访问。 新建一个 renderer.js 脚本, 使用 document.getElementById DOM API 来替换 id 属性为 info 的 HTML 元素的文本。

const information = document.getElementById('info')
information.innerText = `本应用正在使用 Chrome (v${versions.chrome()}), Node.js (v${versions.node()}), 和 Electron (v${versions.electron()})`

然后再index.html文件中引入

  <script src="./renderer.js"></script>

在这里插入图片描述

进程之间通信(简略)

Electron 的主进程和渲染进程有着清楚的分工并且不可互换,无论是从渲染进程直接访问 Node.js 接口,亦或者是从主进程访问 HTML 文档对象模型 (DOM),都是不可能的。
解决这一问题的方法是使用进程间通信 (IPC)。可以使用 Electron 的 ipcMain 模块 ipcRenderer 模块来进行进程间通信。 为了从你的网页向主进程发送消息,你可以使用ipcMain.handle设置一个主进程处理程序(handler),然后在预处理脚本中暴露一个被称为 ipcRenderer.invoke 的函数来触发该处理程序(handler)。

const { contextBridge, ipcRenderer } = require("electron");
contextBridge.exposeInMainWorld("versions", {
  node: () => process.versions.node,
  chrome: () => process.versions.chrome,
  electron: () => process.versions.electron,
  ping: () => ipcRenderer.invoke("ping"),
});

主进程中设置你的 handle 监听器,在 HTML 文件加载之前完成了这些,所以才能保证在你从渲染器发送 invoke 调用之前处理程序能够准备就绪。
渲染主进程中引入const { app, BrowserWindow, ipcMain } = require("electron");

app.whenReady().then(() => {
  ipcMain.handle("ping", () => "pong");
  createWindow();
});

将发送器与接收器设置完成之后,现在你可以将信息通过刚刚定义的 ‘ping’ 通道从渲染器发送至主进程当中。修改renderer中的文件

const func = async () => {
  const response = await window.versions.ping()
  console.log(response) // 打印 'pong'
}

func()

在这里插入图片描述

打包程序

Electron 的核心模块中没有捆绑任何用于打包或分发文件的工具。 如果您在开发模式下完成了一个 Electron 应用,需要使用额外的工具来打包应用程序 (也称为可分发文件) 并分发给用户 。 可分发文件可以是安装程序 (例如 Windows 上的 MSI) 或者绿色软件 (例如 macOS 上的 .app 文件)。Electron Forge 是一个处理 Electron 应用程序打包与分发的一体化工具。 在工具底层,它将许多现有的 Electron 工具 (例如 @electron/packager、 @electron/osx-sign、electron-winstaller 等) 组合到一起。

安装打包工具npm install --save-dev @electron-forge/cli,然后输入npx electron-forge import等待初始化完毕,之后package会变为如下图所示
在这里插入图片描述

创建一个可分发版本

要创建可分发文件,请使用项目中的 make 脚本,该脚本最终运行了 electron-forge make 命令。npm run make注意如果npm init 的时候,author 与 description 可为任意值,但对于应用打包是必填项。如果没有则会出现如下错误
在这里插入图片描述
注意,项目打包路径中不能包含中文字符,否则报错。 打包成功如下
在这里插入图片描述

  1. npm run make它将首先运行 electron-forge package ,把您的应用程序 代码与 Electron 二进制包结合起来。
  2. 完成打包的代码将会被生成到一个特定的文件夹中。 然后它将使用这个文件夹为每个 maker 配置生成一个可分发文件。
    在这里插入图片描述
    打包完成后查看.exe文件运行。
    在这里插入图片描述

代码签名

为了将桌面应用程序分发给最终用户,我们 强烈建议 您对 Electron 应用进行 代码签名。 代码签名是交付桌面应用程序的重要组成部分,并且它对于应用程序的自动更新功能 (将会在教程最后部分讲解) 来说是必需的。

代码签名是一种可用于证明桌面应用程序是由已知来源创建的安全技术。 Windows 和 macOS 拥有其特定的代码签名系统,这将使用户难以下载或启动未签名的应用程序。代码签名在forge.config.js文件中添加

流程模型

多进程模型:在早期,浏览器通常使用单个进程来处理所有这些功能。 虽然这种模式意味着您打开每个标签页的开销较少,但也同时意味着一个网站的崩溃或无响应会影响到整个浏览器。Chrome 团队决定让每个标签页在自己的进程中渲染, 从而限制了一个网页上的有误或恶意代码可能导致的对整个应用程序造成的伤害。 然后用单个浏览器进程控制这些标签页进程,以及整个应用程序的生命周期。
在这里插入图片描述
electron包含两种进程:主进程和渲染进程。每个 Electron 应用都有一个单一的主进程,作为应用程序的入口点。 主进程在 Node.js 环境中运行,这意味着它具有 require 模块和使用所有 Node.js API 的能力。主进程的主要目的是使用 BrowserWindow 模块创建和管理应用程序窗口。BrowserWindow 类的每个实例创建一个应用程序窗口,且在单独的渲染器进程中加载一个网页。 您可从主进程用 window 的 webContent 对象与网页内容进行交互。

const { BrowserWindow, app } = require("electron");

const createWindow = () => {
  const win = new BrowserWindow({
    width: 800,
    height: 800,
  });

  win.loadURL("https://github.com"); //网页以地址的形式引入

  console.log(win.webContents); //主进程中输出
};

app.whenReady().then(() => {
  createWindow();
});

在这里插入图片描述
当一个 BrowserWindow 实例被销毁时,与其相应的渲染器进程也会被终止。

渲染进程:每个 Electron 应用都会为每个打开的 BrowserWindow ( 与每个网页嵌入 ) 生成一个单独的渲染器进程。 洽如其名,渲染器负责 渲染 网页内容。 所以实际上,运行于渲染器进程中的代码是须遵照网页标准的 (至少就目前使用的 Chromium 而言是如此) 。渲染器无权直接访问 require 或其他 Node.js API

Preload 脚本:预加载(preload)脚本包含了那些执行于渲染器进程中,且先于网页内容开始加载的代码 。 这些脚本虽运行于渲染器的环境中,却因能访问 Node.js API 而拥有了更多的权限。预加载脚本可以在 BrowserWindow 构造方法中的 webPreferences .preload选项里被附加到主进程。预加载脚本与浏览器共享同一个全局 Window 接口,并且可以访问 Node.js API,所以它通过在全局 window 中暴露任意 API 来增强渲染器,以便你的网页内容使用。

虽然预加载脚本与其所附着的渲染器在共享着一个全局 window 对象,但您并不能从中直接附加任何变动到 window 之上,因为 contextIsolation 是默认的,因此下面这段代码在窗口的控制台中输出undefined

//preload.js
window.myAPI = {
  desktop: true
}
//renderer.js
console.log(window.myAPI)
// => undefined

因此需要使用 contextBridge 模块来安全地实现交互.

const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('myAPI', {
  desktop: true
})

在这里插入图片描述

上下文隔离

上下文隔离功能将确保您的 预加载脚本 和 Electron的内部逻辑 运行在所加载的 webcontent网页 之外的另一个独立的上下文环境里。 这对安全性很重要,因为它有助于阻止网站访问 Electron 的内部组件 和 您的预加载脚本可访问的高等级权限的API

这意味着,实际上,您的预加载脚本访问的 window 对象并不是网站所能访问的对象。 例如,如果您在预加载脚本中设置 window.hello = ‘wave’ 并且启用了上下文隔离,当网站尝试访问window.hello对象时将返回 undefined。

自 Electron 12 以来,默认情况下已启用上下文隔离,并且它是 所有应用程序推荐的安全设置。

其实不使用contextBridge 创建预加载脚本就是没有开启上下文的方式。

进程通信

进程通信的表现形式例如 UI 调用原生 API 或从原生菜单触发 Web 内容的更改。

IPC通道

在 Electron 中,进程使用 ipcMainipcRenderer模块,通过开发人员定义的“通道”传递消息来进行通信。 这些通道是 任意 (您可以随意命名它们)和 双向 (您可以在两个模块中使用相同的通道名称)的。

  1. 渲染器进程到主进程(单向)
    要将单向 IPC 消息从渲染器进程发送到主进程,您可以使用 ipcRenderer.send API 发送消息,然后使用 ipcMain.on API 接收。如下是一个事例,用户输入input内容,点击按钮会修改窗口的标题
index.html
    Title: <input id="title"/>
    <button id="btn" type="button">Set</button>
    <script src="./renderer.js"></script>
renderer.js
const setButton = document.getElementById('btn')
const titleInput = document.getElementById('title')
setButton.addEventListener('click', () => {
  const title = titleInput.value
  window.aaa.setTitle(title) // 渲染主线程使用预加载脚本暴露的通道,使用其提供的方法
})
const { contextBridge, ipcRenderer } = require("electron");
contextBridge.exposeInMainWorld("aaa", {
  //aaa是自定义的通道名
  //定义一个setTitle函数,通过send方法向主进程发生一个set-title消息,并携带参数
  setTitle: (title) => ipcRenderer.send("set-title", title), //send方法是一个异步行为
});
main.js
const { BrowserWindow, app, ipcMain } = require("electron");
const path = require("path");

function handleSetTitle(e, title) {
  /* 
  事件对象 e 中获取发送该事件的 webContents 对象。
  在 Electron 中,webContents 代表了渲染器进程内的网页内容,每个 Electron 窗口里都有一个与其关联的 webContents 实例
  */
  const webContents = e.sender;
  /* 
    BrowserWindow.fromWebContents 方法,并传入前面获得的 webContents 对象,
    可以获取到关联该 webContents 的 BrowserWindow 实例。
    基本上这行代码是根据渲染器进程(webContents)找到对应的窗口对象(BrowserWindow 实例)。
  */
  const w = BrowserWindow.fromWebContents(webContents);
  w.setTitle(title);
}

const createWindow = () => {
  const win = new BrowserWindow({
    width: 800,
    height: 800,
    webPreferences: {
      preload: path.join(__dirname, "preload.js"),
    },
    webContents: {
      openDevTools: true,
    },
  });

  win.loadFile("index.html");
};

app.whenReady().then(() => {
  //ipcMain.on监听set-title行为,箭头从渲染器进程中使用setTitle方法发送而来的set-title消息(可以理解vue的事件监听emit)
  ipcMain.on("set-title", handleSetTitle);
  createWindow();
});

在这里插入图片描述
其中事件对象的结构如下
在这里插入图片描述

  1. 渲染器进程到主进程(双向):如下是一个事例,用户选中一个文件,显示该文件的路径。
index.html
    <button type="button" id="btn">Open a File</button>
    File path: <strong id="filePath"></strong>
    <script src="./renderer.js"></script>
renderer.js
const btn = document.getElementById("btn");
const filePathElement = document.getElementById("filePath");

btn.addEventListener("click", async () => {
  const filePath = await window.electronAPI.openFile();
  filePathElement.innerText = filePath;
});
preload.js
const { contextBridge, ipcRenderer } = require("electron/renderer");
contextBridge.exposeInMainWorld("electronAPI", {
  /* 
    异步发送一个需要响应的消息,并且等待主进程的回复。
    这是异步操作,但允许以类似于同步调用的方式(使用 async/await 或者基于 Promise 的方法)等待响应。
  */
  openFile: () => ipcRenderer.invoke("dialog:openFile"),
});
const { app, BrowserWindow, ipcMain, dialog } = require("electron/main");
const path = require("node:path");

async function handleFileOpen() {
  /* 
    dialog 模块用于显示原生的对话框,例如文件打开、保存、消息提示等。
    dialog 模块是 Electron 提供的一个系统对话框接口,可以在主进程中使用,用于与用户进行交互。
    dialog 模块通过其 showOpenDialog 方法用于显示一个文件选择对话框。
    这个方法是异步的,它会返回一个 Promise。当用户选择文件并关闭对话框时,Promise 被解决(resolved),并带有一个对象,这个对象包含了两个属性:canceled 和 filePaths。
    canceled 是一个布尔值,表示用户是否取消了对话框而没有选择任何文件
    filePaths 是一个数组,包含用户选择的一个或多个文件的完整路径。
  */
  const { canceled, filePaths } = await dialog.showOpenDialog();
  if (!canceled) {
    return filePaths[0];
  }
}

function createWindow() {
  const mainWindow = new BrowserWindow({
    webPreferences: {
      preload: path.join(__dirname, "preload.js"),
    },
  });
  mainWindow.loadFile("index.html");
}

app.whenReady().then(() => {
   //会把处理完成的消息返回给渲染进程
  ipcMain.handle("dialog:openFile", handleFileOpen);
  createWindow();
});
  1. 主进程到渲染器进程:将消息从主进程发送到渲染器进程时,需要指定是哪一个渲染器接收消息。 消息需要通过其 ·WebContents 实例·发送到渲染器进程。 此 WebContents 实例包含一个 ·send ·方法,其使用方式与· ipcRenderer.send ·相同。如下实例是一个原生操作系统菜单控制的数字计数器。
index.html
    Current value: <strong id="counter">0</strong>
    <script src="./renderer.js"></script>
renderer.js
const counter = document.getElementById("counter");

window.electronAPI.onUpdateCounter((value) => {
  const oldValue = Number(counter.innerText);
  const newValue = oldValue + value;
  counter.innerText = newValue.toString();
  window.electronAPI.counterValue(newValue);
});
preload.js
const { contextBridge, ipcRenderer } = require("electron/renderer");
contextBridge.exposeInMainWorld("electronAPI", {
  onUpdateCounter: (callback) =>
    ipcRenderer.on("update-counter", (_event, value) => callback(value)),
  counterValue: (value) => ipcRenderer.send("counter-value", value),
});
main.js
const { app, BrowserWindow, Menu, ipcMain } = require("electron/main");
const path = require("node:path");

function createWindow() {
  const mainWindow = new BrowserWindow({
    webPreferences: {
      preload: path.join(__dirname, "preload.js"),
    },
  });

  const menu = Menu.buildFromTemplate([
    {
      label: app.name,
      submenu: [
        {
          click: () => mainWindow.webContents.send("update-counter", 1),
          label: "Increment",
        },
        {
          click: () => mainWindow.webContents.send("update-counter", -1),
          label: "Decrement",
        },
      ],
    },
  ]);

  Menu.setApplicationMenu(menu);
  mainWindow.loadFile("index.html");

  // Open the DevTools.
  mainWindow.webContents.openDevTools();
}

app.whenReady().then(() => {
  ipcMain.on("counter-value", (_event, value) => {
    console.log(value); // 主进程中输出打印
  });
  createWindow();
});

在这里插入图片描述

  1. 渲染器进程到渲染器进程:没有直接的方法可以使用 ipcMain 和 ipcRenderer 模块在 Electron 中的渲染器进程之间发送消息。将主进程作为渲染器之间的消息代理。 这需要将消息从一个渲染器发送到主进程,然后主进程将消息转发到另一个渲染器。从主进程将一个 MessagePort 传递到两个渲染器。 这将允许在初始设置后渲染器之间直接进行通信。

进程沙盒化

从 Electron 20 开始,渲染进程默认启用了沙盒,无需进一步配置。

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

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

相关文章

AI办公自动化:用Kimi批量在Excel文件名中加入日期

工作任务&#xff1a;在一个文件夹中所有的Excel文件后面加上一个日期 在Kimi中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;写一个Python脚本&#xff0c;具体步骤如下&#xff1a; 打开文件夹&#xff1a;F:\AI自媒体内容\AI行业数据分析\投融资 读取里面所…

电商核心技术系列58:电商平台的智能数据分析与业务洞察

相关系列文章 电商技术揭秘相关系列文章合集&#xff08;1&#xff09; 电商技术揭秘相关系列文章合集&#xff08;2&#xff09; 电商技术揭秘相关系列文章合集&#xff08;3&#xff09; 电商核心技术揭秘56&#xff1a;客户关系管理与忠诚度提升 电商核心技术揭秘57:数…

Codeforces Round 951 (Div. 2) A~E

A.Guess the Maximum&#xff08;枚举&#xff09; 题意&#xff1a; 爱丽丝和鲍勃想出了一个相当奇怪的游戏。他们有一个整数数组 a 1 , a 2 , … , a n a_1,a_2,\ldots,a_n a1​,a2​,…,an​。爱丽丝选择了某个整数 k k k并告诉了鲍勃&#xff0c;然后就发生了下面的事情&…

UiPath发送邮件给多人时需要注意哪些限制?

UiPath发送邮件给多人的步骤&#xff1f;如何使用UiPath发信&#xff1f; 尽管UiPath提供了强大的邮件发送功能&#xff0c;但在批量发送邮件时&#xff0c;有一些限制和注意事项是我们必须了解的。AokSend将详细介绍这些限制&#xff0c;并提供一些优化建议。 UiPath发送邮件…

ArrayList和LinkedList的区别!!!

总结&#xff1a; 1、数据结构的实现 ArrayList&#xff1a;动态数组。 LinkedList&#xff1a;双向链表。 2、时间复杂度不同 ArrayList&#xff1a;O(1) LinkedList: O(n) ①&#xff1a;随机访问---- ArrayList > LinkedList &#xff08;ArrayList采用下标&#xff0…

frps 0.33

一个模拟示例 下载windows版本的frfps 需要准备的测试设备 一台frp服务器一台frp客户端PCsscom5.exe测试软件开2个,来模拟野外的设备和本地连接野外设备的软件。原理 frp服务器搭建了一条中转的桥梁,frp的客户端在本地做好端口映射后,本地的设备软件就可以连接到野外的设…

第34章-WLAN

1. 概述 2. WLAN模式 3. 相关概念 1. 概述 ① 定义WLAN(Wireless Local Area Network,无线局域网)&#xff0c;是一种技术&#xff1b; ② WLAN技术&#xff1a; Wi-Fi WAPI&#xff1a;中国强制标准&#xff1b; 例子&#xff1a;苹果手机 -- 设置 -- 国行(无线局域网设置) …

大众点评全国学习培训POI采集99万家-2024年5月底

大众点评全国学习培训POI采集99万家-2024年5月底 店铺POI点位示例&#xff1a; 店铺id k40VtNBN3bixFJIU 店铺名称 梦想钢琴成人钢琴(珠江新城总部) 十分制服务评分 9.4 十分制环境评分 9.4 十分制划算评分 9.4 人均价格 80 评价数量 6705 店铺地址 华穗路263号双城国…

Python酷库之旅-比翼双飞情侣库(01)

目录 一、xlrd库的由来 二、xlrd库优缺点 1、优点 1-1、支持多种Excel文件格式 1-2、高效性 1-3、开源性 1-4、简单易用 1-5、良好的兼容性 2、缺点 2-1、对.xlsx格式支持有限 2-2、功能相对单一 2-3、更新和维护频率低 2-4、依赖外部资源 三、xlrd库的版本说明 …

1 机器人软件开发学习所需通用技术栈(一)

机器人软件工程师技术路线&#xff08;如有缺失&#xff0c;欢迎补充&#xff09; 1. 机器人软件开发工程师技术路线 1.1 基础知识 C/C编程&#xff1a;掌握C/C语言基础&#xff0c;包括数据结构、算法、内存管理等。操作系统&#xff1a;了解Linux或Windows等操作系统的基本…

程序固化——FPGA学习笔记6

一、固化文件介绍 BIN:一般是由Vivado软件编译产生的&#xff0c;存储在特定目录下的二进制文件 MCS:一般通过VivadoGUl界面操作或者TCL命令生成&#xff0c;MCS文件里包含了BIN文件的内容&#xff0c;除此之外&#xff0c;每行的开始有地址信息&#xff0c;最后一个Byte是CRC校…

Java---BigInteger和BigDecimal和枚举

1.简介 1.BigInteger可以支持任意长度的整数 2.BigDecimal可以支持任意精度的浮点数 3.用来做精确计算 2.创建方式 new BigInteger(); new BigInteger(参数1,进制)&#xff1a;可以将不同进制转成10进制显示 new BigDecimal(); BigInteger.valueOf(); BigDecimal.valueOf();…

吴恩达2022机器学习专项课程C2W3:实验Lab_01模型评估与选择

这里写目录标题 导入模块与实验环境配置回归1.构建并可视化数据集2.分割数据集3.重新绘制数据集3.特征缩放4.评估模型&#xff1a;计算训练集的误差5.评估模型&#xff1a;计算交叉验证集的误差 添加多项式1.构建多项式特征集2.缩放特征3.使用标准化的计训练集和交叉验证集&…

搭建一个简单的深度神经网络

目录 一、引入所需要的库 二、制作数据集 三、搭建神经网络 四、训练网络 五、测试网络 本博客实验环境为jupyter 一、引入所需要的库 torch库是核心&#xff0c;其中torch.nn 提供了搭建网络所需的所有组件&#xff0c;nn即神经网络。matplotlib类似与matlab&#xff0…

136G全国1m土地覆盖数据

数据是GIS的血液&#xff01; 我们现在为你分享一个136G的全国土地覆盖数据&#xff0c;该数据的分辨率为1米&#xff0c;你可以在文末查看领取方法。 数据概况 为满足对更精确地感知国土面积的需求&#xff0c;来自武汉大学和中国地质⼤学的团队利用低成本的激光扫描仪&…

SAP CS01/CS02/CS03 BOM创建维护删除BAPI使用及增强改造

BOM创建维护删除相关BAPI的使用代码参考示例&#xff0c;客户电脑只能远程桌面&#xff0c;代码没法复制粘贴出来&#xff0c;只能贴图。 创建及修改BAPI: CSAP_MAT_BOM_MAINTAIN。 删除BAPI: CSAP_MAT_BOM_DELETE。 改造BAPI: CSAP_MAT_BOM_MAINTAIN 改造点1&#xff1a;拷…

[LitCTF 2023]Virginia(变异凯撒)

题目&#xff1a; 首先利用网站进行维吉尼亚解密&#xff08;第一段和第二段密钥不同&#xff0c;两段无关&#xff0c;可只解密第二段&#xff09; 第二段解密结果&#xff1a; Please send this message to those people who mean something to you,to those who have touch…

雪球产品可能要远离普通人了

最近有消息说&#xff0c;在年初发生大规模敲入事件后&#xff0c;雪球产品的购买门槛可能从300w提升至1000w。 那么在这个时间&#xff0c;了解一下雪球产品到底是什么&#xff0c;运行原理是什么。 第一种 经典雪球 经典雪球比较容易理解&#xff0c;设定好了固定的敲出条件…

Java从放弃到继续放弃

并发编程 为什么需要多线程&#xff1f; 由于硬件的发展&#xff0c;CPU的核数增多&#xff0c;如果仍然使用单线程对CPU资源会造成浪费。同时&#xff0c;单线程也会出现阻塞的问题。所以&#xff0c;选择向多线程转变。 多线程的使用使得程序能够并行计算&#xff0c;提高计…

HTTPS请求阶段图解分析

HTTPS请求阶段分析 请求阶段分析 请求阶段分析 一个完整、无任何缓存、未复用连接的 HTTPS 请求需要经过以下几个阶段&#xff1a; DNS 域名解析、TCP 握手、SSL 握手、服务器处理、内容传输。 一个 HTTPS 请求共需要 5 个 RTT 1 RTT&#xff08;域名解析&#xff09; 1 RTT…