C++使用WebView2控件,通过IPC通信与Javascript交互

news2025/4/18 14:45:30

引言

在现代桌面应用程序开发中,Web技术与原生应用的融合变得越来越普遍。Microsoft的WebView2控件为C++开发者提供了一个强大的工具,使他们能够在桌面应用中嵌入基于Chromium的Web浏览器引擎。本文将详细介绍如何在C++应用程序中使用WebView2控件,并通过IPC(进程间通信)机制实现C++与JavaScript之间的双向交互。

WebView2简介

WebView2是Microsoft推出的新一代Web视图控件,基于Chromium引擎,替代了旧的MSHTML(IE)引擎。它允许开发者在Windows应用程序中嵌入Web内容,并提供了丰富的API用于控制Web视图和与Web内容交互。

WebView2的主要优势

  • 现代Web标准支持:基于Chromium引擎,支持最新的HTML5、CSS3和JavaScript特性
  • 与系统浏览器独立:不依赖于系统安装的浏览器版本
  • 强大的通信机制:提供多种方式实现本地代码与Web内容的通信
  • 安全性:Web内容在独立的进程中运行,提高了应用的稳定性和安全性

环境准备

在开始开发之前,需要准备以下环境:

  1. Visual Studio:推荐使用Visual Studio 2019或更高版本
  2. WebView2 SDK:可以通过NuGet包管理器安装
  3. C++开发环境:确保已安装C++桌面开发工作负载

安装WebView2 SDK

使用NuGet包管理器安装WebView2 SDK:

Install-Package Microsoft.Web.WebView2

或者在Visual Studio的NuGet包管理器中搜索并安装"Microsoft.Web.WebView2"。

创建基本WebView2应用

首先,我们来创建一个基本的WebView2应用程序。以下是一个简单的示例,展示如何在Win32应用程序中嵌入WebView2控件:

#include <windows.h>
#include <wrl.h>
#include <wil/com.h>
#include <WebView2.h>
#include <WebView2EnvironmentOptions.h>

using namespace Microsoft::WRL;

// WebView2控件
static wil::com_ptr<ICoreWebView2Controller> webViewController;
static wil::com_ptr<ICoreWebView2> webView;

// 初始化WebView2
HRESULT InitializeWebView(HWND hWnd)
{
    // 创建WebView2环境
    return CreateCoreWebView2EnvironmentWithOptions(nullptr, nullptr, nullptr,
        Callback<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>(
            [hWnd](HRESULT result, ICoreWebView2Environment* env) -> HRESULT {
                // 创建WebView2控制器
                env->CreateCoreWebView2Controller(hWnd, 
                    Callback<ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>(
                        [hWnd](HRESULT result, ICoreWebView2Controller* controller) -> HRESULT {
                            if (controller != nullptr) {
                                webViewController = controller;
                                webViewController->get_CoreWebView2(&webView);

                                // 设置WebView2的大小
                                RECT bounds;
                                GetClientRect(hWnd, &bounds);
                                webViewController->put_Bounds(bounds);

                                // 导航到初始URL
                                webView->Navigate(L"https://www.example.com");
                            }
                            return S_OK;
                        }).Get());
                return S_OK;
            }).Get());
}

// 窗口过程
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CREATE:
        InitializeWebView(hWnd);
        return 0;
    case WM_SIZE:
        if (webViewController != nullptr) {
            RECT bounds;
            GetClientRect(hWnd, &bounds);
            webViewController->put_Bounds(bounds);
        }
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
}

// 程序入口点
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    // 注册窗口类
    WNDCLASSEX wcex = {};
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WindowProc;
    wcex.hInstance = hInstance;
    wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wcex.lpszClassName = L"WebView2Sample";
    RegisterClassEx(&wcex);

    // 创建窗口
    HWND hWnd = CreateWindow(
        L"WebView2Sample", L"WebView2 Sample",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 1200, 900,
        nullptr, nullptr, hInstance, nullptr);

    if (!hWnd) {
        return 1;
    }

    // 显示窗口
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    // 消息循环
    MSG msg = {};
    while (GetMessage(&msg, nullptr, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int)msg.wParam;
}

这段代码创建了一个简单的窗口,并在其中嵌入了WebView2控件,导航到example.com网站。

实现C++与JavaScript的IPC通信

WebView2提供了多种方式实现C++与JavaScript之间的通信。最常用的两种方式是:

  1. PostMessage/AddScriptToExecuteOnDocumentCreated:用于在C++和JavaScript之间传递消息
  2. WebMessage API:提供了更结构化的消息传递机制

从C++调用JavaScript

可以使用ExecuteScript方法从C++调用JavaScript代码:

// 从C++调用JavaScript函数
void CallJavaScriptFunction(const std::wstring& functionName, const std::wstring& parameter)
{
    if (webView) {
        std::wstring script = functionName + L"('" + parameter + L"');";
        webView->ExecuteScript(script.c_str(), nullptr);
    }
}

// 示例:调用JavaScript函数
CallJavaScriptFunction(L"updateStatus", L"Connected from C++");

从JavaScript调用C++

要从JavaScript调用C++代码,我们可以使用AddHostObjectToScriptWebMessageReceived事件。以下是使用WebMessageReceived的示例:

// 设置WebMessage处理程序
void SetupWebMessageHandler()
{
    if (webView) {
        // 注册消息处理程序
        webView->add_WebMessageReceived(
            Callback<ICoreWebView2WebMessageReceivedEventHandler>(
                [](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) -> HRESULT {
                    LPWSTR message;
                    args->TryGetWebMessageAsString(&message);
                    
                    // 处理来自JavaScript的消息
                    ProcessMessageFromJs(message);
                    
                    CoTaskMemFree(message);
                    return S_OK;
                }).Get(), nullptr);
                
        // 注入JavaScript代码,使Web页面能够向C++发送消息
        webView->AddScriptToExecuteOnDocumentCreated(
            L"window.chrome.webview.postMessage = function(message) {"
            L"    window.chrome.webview.postMessage(message);"
            L"};"
            L"window.callNative = function(functionName, parameter) {"
            L"    window.chrome.webview.postMessage(JSON.stringify({function: functionName, param: parameter}));"
            L"};",
            nullptr);
    }
}

// 处理来自JavaScript的消息
void ProcessMessageFromJs(const std::wstring& message)
{
    // 这里可以解析JSON消息,执行相应的本地功能
    // 例如,可以使用JSON库解析message,然后根据function字段调用不同的C++函数
    
    // 简单示例:打印消息
    OutputDebugString((L"Message from JS: " + message + L"\n").c_str());
    
    // 响应消息(可选)
    if (webView) {
        webView->PostWebMessageAsString(L"Message received by C++");
    }
}

在JavaScript端,可以这样调用C++:

// 调用C++函数
function callCppFunction(functionName, parameter) {
    window.chrome.webview.postMessage(JSON.stringify({
        function: functionName,
        param: parameter
    }));
}

// 示例:调用C++函数
callCppFunction('saveData', 'This is data from JavaScript');

// 接收C++的响应
window.chrome.webview.addEventListener('message', function(event) {
    console.log('Response from C++:', event.data);
});

完整的IPC通信示例

下面是一个更完整的示例,展示了C++和JavaScript之间的双向通信:

C++部分

#include <windows.h>
#include <wrl.h>
#include <wil/com.h>
#include <WebView2.h>
#include <WebView2EnvironmentOptions.h>
#include <string>
#include <sstream>
#include <nlohmann/json.hpp>

using namespace Microsoft::WRL;
using json = nlohmann::json;

// WebView2控件
static wil::com_ptr<ICoreWebView2Controller> webViewController;
static wil::com_ptr<ICoreWebView2> webView;

// 处理来自JavaScript的消息
void ProcessMessageFromJs(const std::wstring& messageW)
{
    // 将wstring转换为string以便使用JSON库
    std::string message(messageW.begin(), messageW.end());
    
    try {
        auto jsonData = json::parse(message);
        std::string function = jsonData["function"];
        std::string param = jsonData["param"];
        
        // 根据function字段调用不同的C++函数
        if (function == "saveData") {
            // 保存数据的示例实现
            OutputDebugStringA(("Saving data: " + param + "\n").c_str());
            
            // 响应JavaScript
            if (webView) {
                webView->PostWebMessageAsString(L"Data saved successfully");
            }
        }
        else if (function == "getData") {
            // 获取数据的示例实现
            std::string data = "Sample data from C++ - " + param;
            OutputDebugStringA(("Getting data for: " + param + "\n").c_str());
            
            // 调用JavaScript函数返回数据
            if (webView) {
                std::wstring script = L"receiveDataFromCpp('" + std::wstring(data.begin(), data.end()) + L"');";
                webView->ExecuteScript(script.c_str(), nullptr);
            }
        }
    }
    catch (const std::exception& e) {
        OutputDebugStringA(("Error parsing JSON: " + std::string(e.what()) + "\n").c_str());
    }
}

// 初始化WebView2
HRESULT InitializeWebView(HWND hWnd)
{
    // 创建WebView2环境
    return CreateCoreWebView2EnvironmentWithOptions(nullptr, nullptr, nullptr,
        Callback<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>(
            [hWnd](HRESULT result, ICoreWebView2Environment* env) -> HRESULT {
                // 创建WebView2控制器
                env->CreateCoreWebView2Controller(hWnd, 
                    Callback<ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>(
                        [hWnd](HRESULT result, ICoreWebView2Controller* controller) -> HRESULT {
                            if (controller != nullptr) {
                                webViewController = controller;
                                webViewController->get_CoreWebView2(&webView);

                                // 设置WebView2的大小
                                RECT bounds;
                                GetClientRect(hWnd, &bounds);
                                webViewController->put_Bounds(bounds);
                                
                                // 设置WebMessage处理程序
                                webView->add_WebMessageReceived(
                                    Callback<ICoreWebView2WebMessageReceivedEventHandler>(
                                        [](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) -> HRESULT {
                                            LPWSTR message;
                                            args->TryGetWebMessageAsString(&message);
                                            
                                            // 处理来自JavaScript的消息
                                            ProcessMessageFromJs(message);
                                            
                                            CoTaskMemFree(message);
                                            return S_OK;
                                        }).Get(), nullptr);
                                
                                // 注入JavaScript代码
                                webView->AddScriptToExecuteOnDocumentCreated(
                                    L"window.callNative = function(functionName, parameter) {"
                                    L"    window.chrome.webview.postMessage(JSON.stringify({function: functionName, param: parameter}));"
                                    L"};"
                                    L"window.receiveDataFromCpp = function(data) {"
                                    L"    document.getElementById('result').innerText = data;"
                                    L"};",
                                    nullptr);
                                
                                // 导航到本地HTML文件
                                webView->Navigate(L"file:///C:/path/to/your/index.html");
                            }
                            return S_OK;
                        }).Get());
                return S_OK;
            }).Get());
}

// 窗口过程
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CREATE:
        InitializeWebView(hWnd);
        return 0;
    case WM_SIZE:
        if (webViewController != nullptr) {
            RECT bounds;
            GetClientRect(hWnd, &bounds);
            webViewController->put_Bounds(bounds);
        }
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
}

// 程序入口点
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    // 注册窗口类
    WNDCLASSEX wcex = {};
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WindowProc;
    wcex.hInstance = hInstance;
    wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wcex.lpszClassName = L"WebView2IPCSample";
    RegisterClassEx(&wcex);

    // 创建窗口
    HWND hWnd = CreateWindow(
        L"WebView2IPCSample", L"WebView2 IPC Sample",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 1200, 900,
        nullptr, nullptr, hInstance, nullptr);

    if (!hWnd) {
        return 1;
    }

    // 显示窗口
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    // 消息循环
    MSG msg = {};
    while (GetMessage(&msg, nullptr, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return (int)msg.wParam;
}

HTML/JavaScript部分 (index.html)

<!DOCTYPE html>
<html>
<head>
    <title>WebView2 IPC Demo</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
        }
        button {
            margin: 10px 0;
            padding: 8px 16px;
        }
        #result {
            margin-top: 20px;
            padding: 10px;
            border: 1px solid #ccc;
            min-height: 100px;
        }
    </style>
</head>
<body>
    <h1>WebView2 IPC通信演示</h1>
    
    <div>
        <input type="text" id="inputData" placeholder="输入数据">
        <button onclick="saveData()">保存数据到C++</button>
        <button onclick="getData()">从C++获取数据</button>
    </div>
    
    <div>
        <h3>结果:</h3>
        <div id="result"></div>
    </div>
    
    <script>
        // 保存数据到C++
        function saveData() {
            const data = document.getElementById('inputData').value;
            window.callNative('saveData', data);
        }
        
        // 从C++获取数据
        function getData() {
            const query = document.getElementById('inputData').value || 'default';
            window.callNative('getData', query);
        }
        
        // 接收C++的响应
        window.chrome.webview.addEventListener('message', function(event) {
            document.getElementById('result').innerText = event.data;
        });
    </script>
</body>
</html>

高级IPC通信技术

除了基本的消息传递外,WebView2还提供了一些高级的IPC通信技术:

1. 使用AddHostObjectToScript

AddHostObjectToScript允许将C++对象直接暴露给JavaScript,使JavaScript可以直接调用C++对象的方法:

// 定义要暴露给JavaScript的COM对象
class HostObject : public Microsoft::WRL::RuntimeClass<
    Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
    IDispatch> {
public:
    // IDispatch实现...
    
    // 示例方法
    HRESULT Add(int a, int b, int* result) {
        *result = a + b;
        return S_OK;
    }
};

// 将对象暴露给JavaScript
void ExposeHostObjectToJs()
{
    if (webView) {
        auto hostObject = Make<HostObject>();
        webView->AddHostObjectToScript(L"cppObject", hostObject.Get());
    }
}

在JavaScript中:

// 直接调用C++对象的方法
const result = window.chrome.webview.hostObjects.cppObject.Add(5, 3);
console.log('Result:', result);

2. 使用DevToolsProtocol

WebView2还支持Chrome DevTools Protocol (CDP),可以用于高级调试和控制:

// 使用CDP发送命令
void SendDevToolsCommand()
{
    if (webView) {
        webView->CallDevToolsProtocolMethod(L"Network.enable", L"{}", nullptr);
    }
}

3. 使用自定义事件

可以使用自定义事件在C++和JavaScript之间建立更结构化的通信:

// C++中发送事件
void SendEventToJs(const std::wstring& eventName, const std::wstring& eventData)
{
    if (webView) {
        std::wstring script = L"document.dispatchEvent(new CustomEvent('" + 
            eventName + L"', { detail: " + eventData + L" }));";
        webView->ExecuteScript(script.c_str(), nullptr);
    }
}

在JavaScript中:

// 监听来自C++的事件
document.addEventListener('myCustomEvent', function(event) {
    console.log('Event received:', event.detail);
});

性能优化与最佳实践

在使用WebView2进行IPC通信时,有一些性能优化和最佳实践需要注意:

1. 批量处理消息

对于频繁的通信,应该考虑批量处理消息,而不是每次都单独发送:

// C++批量发送数据
void SendBatchData(const std::vector<std::wstring>& dataItems)
{
    if (webView && !dataItems.empty()) {
        std::wstringstream ss;
        ss << L"[";
        for (size_t i = 0; i < dataItems.size(); ++i) {
            ss << L"'" << dataItems[i] << L"'";
            if (i < dataItems.size() - 1) {
                ss << L",";
            }
        }
        ss << L"]";
        
        std::wstring script = L"processBatchData(" + ss.str() + L");";
        webView->ExecuteScript(script.c_str(), nullptr);
    }
}

2. 使用二进制数据传输

对于大量数据,考虑使用二进制格式而不是文本格式:

// 在JavaScript中使用ArrayBuffer
function sendBinaryData() {
    const buffer = new ArrayBuffer(1024);
    const view = new Uint8Array(buffer);
    // 填充数据...
    
    // 将ArrayBuffer转换为Base64
    const base64 = arrayBufferToBase64(buffer);
    window.callNative('processBinaryData', base64);
}

function arrayBufferToBase64(buffer) {
    let binary = '';
    const bytes = new Uint8Array(buffer);
    for (let i = 0; i < bytes.byteLength; i++) {
        binary += String.fromCharCode(bytes[i]);
    }
    return window.btoa(binary);
}

在C++中:

// 处理二进制数据
void ProcessBinaryData(const std::string& base64Data)
{
    // 解码Base64数据
    // 处理二进制数据...
}

3. 避免频繁的DOM操作

在JavaScript中,避免频繁的DOM操作,可以使用虚拟DOM或批量更新:

// 批量更新DOM
function updateElements(dataArray) {
    const fragment = document.createDocumentFragment();
    
    dataArray.forEach(item => {
        const div = document.createElement('div');
        div.textContent = item;
        fragment.appendChild(div);
    });
    
    document.getElementById('container').appendChild(fragment);
}

4. 使用异步通信

对于不需要立即响应的操作,使用异步通信可以提高性能:

// C++中异步处理消息
void ProcessMessageAsync(const std::wstring& message)
{
    // 在另一个线程中处理消息
    std::thread([message]() {
        // 处理消息...
        
        // 处理完成后通知JavaScript
        // 注意:需要在UI线程中调用ExecuteScript
    }).detach();
}

安全性考虑

在使用WebView2进行IPC通信时,需要注意以下安全问题:

1. 输入验证

始终验证从JavaScript接收的数据,防止注入攻击:

// 验证输入数据
bool ValidateInput(const std::wstring& input)
{
    // 实现适当的验证逻辑
    return true; // 示例
}

2. 限制JavaScript访问权限

只暴露必要的功能给JavaScript:

// 限制JavaScript访问权限
void LimitJsAccess()
{
    if (webView) {
        // 设置WebView2的权限
        ICoreWebView2Settings* settings;
        webView->get_Settings(&settings);
        
        // 禁用JavaScript对文件系统的访问
        settings->put_IsWebMessageEnabled(TRUE);
        settings->put_AreDefaultScriptDialogsEnabled(FALSE);
        settings->put_IsScriptEnabled(TRUE);
        settings->put_AreDevToolsEnabled(FALSE);
    }
}

3. 使用内容安全策略

在HTML中使用内容安全策略限制JavaScript的行为:

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">

调试技巧

调试WebView2应用程序中的IPC通信可能具有挑战性。以下是一些有用的调试技巧:

1. 启用开发者工具

在开发过程中启用WebView2的开发者工具:

// 启用开发者工具
void EnableDevTools()
{
    if (webView) {
        ICoreWebView2Settings* settings;
        webView->get_Settings(&settings);
        settings->put_AreDevToolsEnabled(TRUE);
        
        // 打开开发者工具
        webView->OpenDevToolsWindow();
    }
}

2. 日志记录

在C++和JavaScript中添加详细的日志记录:

// C++日志记录
void LogMessage(const std::wstring& message)
{
    OutputDebugString((L"[C++] " + message + L"\n").c_str());
}
// JavaScript日志记录
function logMessage(message) {
    console.log(`[JS] ${message}`);
}

3. 使用事件监听器调试通信

在JavaScript中添加事件监听器来监视通信:

// 监视所有WebMessage通信
window.chrome.webview.addEventListener('message', function(event) {
    console.log('Message from C++:', event.data);
});

实际应用场景

WebView2的IPC通信机制可以应用于多种场景:

1. 混合桌面应用

创建具有原生性能和Web界面优势的混合应用:

  • 使用C++处理复杂计算、文件操作和系统集成
  • 使用Web技术创建现代化、响应式的用户界面

2. 离线Web应用

创建可以在没有互联网连接的情况下工作的Web应用:

  • 使用C++处理本地数据存储和同步
  • 使用Web技术提供用户界面

3. 扩展现有应用

为现有的C++应用程序添加Web功能:

  • 逐步将传统应用程序的部分UI迁移到Web技术
  • 保留现有的C++业务逻辑

结论

WebView2为C++开发者提供了一个强大的工具,使他们能够在桌面应用中嵌入现代Web技术,并通过IPC机制实现C++与JavaScript之间的无缝通信。通过本文介绍的技术,开发者可以创建兼具原生性能和Web灵活性的应用程序。

参考资料

  1. Microsoft WebView2 官方文档
  2. WebView2 Samples
  3. WebView2 API Reference
  4. C++/WinRT Documentation
  5. Windows App SDK

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

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

相关文章

精准测试建设过程中遇到的一些问题

1.sqlite3 仅可以处理单个任务问题&#xff0c;多线程往往会面临数据库锁定 因为仅临时存储&#xff0c;后来在创建数据库时&#xff0c;给每个任务开了一个临时数据库&#xff0c;存储数据执行完毕后&#xff0c;删除db sql_insert_new:INSERT INTO analyze_api_resault_dynam…

【Docker】Dockerfile 编写实践

&#x1f47b;创作者&#xff1a;丶重明 &#x1f47b;创作时间&#xff1a;2025年4月8日 &#x1f47b;擅长领域&#xff1a;运维 目录 1. Dockerfile编写原则1.1.选择合适的基础镜像1.2.镜像层优化1.3.多阶段构建1.4.安全增强 2. 关键指令与技巧2.1.COPY vs ADD2.2.ENTRYPOIN…

LabVIEW商业软件开发注意问题

在 LabVIEW 商业软件开发进程中&#xff0c;性能优化、界面设计及兼容性与扩展性&#xff0c;对软件品质、用户体验和市场适配性起着决定性作用。下面&#xff0c;借助多个LabVIEW 编程特性的实际案例&#xff0c;深入分析这些方面的开发要点。 一、性能优化&#xff1a;提升软…

Java 中 SQL 注入问题剖析​

一、引言​ 在当今数字化时代&#xff0c;数据是企业和组织的核心资产之一。许多应用程序都依赖于数据库来存储和管理数据&#xff0c;而 Java 作为一种广泛使用的编程语言&#xff0c;常被用于开发与数据库交互的应用程序。然而&#xff0c;SQL 注入这一安全漏洞却如同隐藏在…

深度学习项目--分组卷积与ResNext网络实验探究(pytorch复现)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 前言 ResNext是分组卷积的开始之作&#xff0c;这里本文将学习ResNext网络&#xff1b;本文复现了ResNext50神经网络&#xff0c;并用其进行了猴痘病分类实验…

CSS 笔记——Flexbox(弹性盒布局)

目录 1. Flex 容器与 Flex 项目 2. 主轴与交叉轴 3. Flex 容器的属性 display flex-direction justify-content align-items align-content flex-wrap 4. Flex 项目的属性 flex-grow flex-shrink flex-basis flex align-self 5. Flexbox 的优点 6. Flexbox 的…

cpp(c++)win 10编译GDAL、PROJ、SQLite3、curl、libtiff

cpp&#xff08;c&#xff09;编译GDAL、PROJ、SQLite3 Sqlite3libtiffcurlprojGDAL Sqlite3 1、下载 Sqlite3 源码、工具、二进制预编译 exe Sqlite3 官网&#xff1a;https://www.sqlite.org/download.html 下载 sqlite-amalgamation-3430200.zipsqlite-dll-win64-x64-3430…

每日一题(小白)暴力娱乐篇23

由题意得知给我们一串数字&#xff0c;我们每次交换两位&#xff0c;最少交换多少次成功得到有顺序的数组。我们以平常的思维去思考&#xff0c;加入给你一串数字获得最少的交换次数&#xff0c;意味着你的交换后续基本不会变&#xff0c;比如说2 1 3 5 4 中1与2交换后不变&…

01-Redis-基础

1 redis诞生历程 redis的作者笔名叫做antirez&#xff0c;2008年的时候他做了一个记录网站访问情况的系统&#xff0c;比如每天有多少个用户&#xff0c;多少个页面被浏览&#xff0c;访客的IP、操作系统、浏览器、使用的搜索关键词等等(跟百度统计、CNZZ功能一样)。最开始存储…

【从零开始学习JVM | 第一篇】快速认识JVM

什么是JVM&#xff1f; JVM--Java虚拟机&#xff0c;它是Java实现平台无关性的基石。 Java程序运行的时候&#xff0c;编译器将Java代码编译为平台无关的Java字节码文件&#xff08;.class&#xff09;&#xff0c;接下来对应平台的JVM对字节码进行运行解释&#xff0c;翻译成…

使用RabbitMQ实现异步秒杀

搭建RabbitMQ 在虚拟机上用docker搭建RabbitMQ&#xff0c;首先拉取镜像 docker run --privilegedtrue -d -p 5672:5672 -p 15672:15672 --name rabbitmq rabbitmq:management mkdir -p /usr/local/docker/rabbitmq再创建rabbitmq容器&#xff0c;下面的命令已经能够创建之后…

解决华硕主板Z890m下载ubuntu20.04后没有以太网问题

问题描述&#xff1a; 华硕主板Z890m下载双系统ubuntu20.04后&#xff0c;发现ubuntu不能打开以太网。 问题原因&#xff1a; 华硕主板的网卡驱动是r8125,而ubuntu20.04的驱动版本是r8169&#xff0c;所以是网卡驱动不匹配造成 解决方案 开机界面按下F2进入BOIS模式&#…

xLua的Lua调用C#的2,3,4

使用Lua在Unity中创建游戏对象&#xff0c;组件&#xff1a; 相关代码如下&#xff1a; Lua --Lua实例化类 --C# Npc objnew Npc() --通过调用构造函数创建对象 local objCS.Npc() obj.HP100 print(obj.HP) local obj1CS.Npc("admin") print(obj1.Name)--表方法希…

Debian系统_主板作为路由器_测试局域网设备间网速

Debian系统_主板作为路由器_测试局域网设备间网速 一、360软件测网速 360测出来的网速实际上是宽带的速度&#xff0c;并不是路由器LAN口到电脑这一段的网速 二、使用iperf3 进行双向带宽测试 1、开发板端下载软件 //Debian系统或者/Ubuntu sudo apt update && sudo…

从 macos 切换到 windows 上安装的工具类软件

起因 用了很多年的macos, 已经习惯了macos上的操作, 期望能在windows上获得类似的体验, 于是花了一些时间来找windows上相对应的软件. 截图软件 snipaste​​​​​​ windows和macos都有的软件, 截图非常好用 文件同步软件 oneDrive: 尝试了不同的同步软件, 还是微软在各…

JavaScript中通过array.map()实现数据转换、创建派生数组、异步数据流处理、复杂API请求、DOM操作、搜索和过滤等,array.map()的使用详解(附实际应用代码)

目录 JavaScript中通过array.map(&#xff09;实现数据转换、创建派生数组、异步数据流处理、复杂API请求、DOM操作、搜索和过滤等&#xff0c;array.map&#xff08;&#xff09;的使用详解&#xff08;附实际应用代码&#xff09; 一、什么时候该使用Array.map()&#xff0…

SQL优化技术分享:从 321 秒到 0.2 秒的性能飞跃 —— 基于 PawSQL 的 TPCH 查询优化实战

在数据库性能优化领域&#xff0c;TPC-H 测试集是一个经典的基准测试工具&#xff0c;常用于评估数据库系统的查询性能。本文将基于 TPCH 测试集中的第 20个查询&#xff0c;结合 PawSQL 自动化优化工具&#xff0c;详细分析如何通过 SQL 重写和索引设计&#xff0c;将查询性能…

密码学基础——DES算法

前面的密码学基础——密码学文章中介绍了密码学相关的概念&#xff0c;其中简要地对称密码体制(也叫单钥密码体制、秘密密钥体制&#xff09;进行了解释&#xff0c;我们可以知道单钥体制的加密密钥和解密密钥相同&#xff0c;单钥密码分为流密码和分组密码。 流密码&#xff0…

在 Linux 终端中轻松设置 Chromium 的 User-Agent:模拟手机模式与自定义浏览体验

在 Linux 系统中&#xff0c;通过终端灵活控制 Chromium 的行为可以大幅提升工作效率。本文将详细介绍如何通过命令行参数和环境变量自定义 Chromium 的 User-Agent&#xff0c;并结合手机模式模拟&#xff0c;实现更灵活的浏览体验。 为什么需要自定义 User-Agent&#xff1f;…

http页面的加载过程

HTTP/2 核心概念 1.1 流&#xff08;Stream&#xff09; • 定义&#xff1a;HTTP/2 连接中的逻辑通道&#xff0c;用于传输数据&#xff0c;每个流有唯一标识符&#xff08;Stream ID&#xff09;。 • 特点&#xff1a; ◦ 支持多路复用&#xff08;多个流并行传输&#…