拦截 open调用 (进程白名单,文件白名单)

拦截 open

文章目录

      • 拦截 open
      • 第一个需求
      • 文件结构
        • 进程白名单
        • 文件白名单
      • 测试代码
      • 第一个版本
      • 版本二
        • 代码演示
      • 增加一个日志记录
      • 代码解释

gcc -shared -fPIC -o libintercept.so intercept.c -ldl
LD_PRELOAD=./libintercept.so ./processA
在Linux中,我们可以使用LD_PRELOAD环境变量来拦截并替换系统调用,如open函数。这是一个简单的示例,展示了如何创建一个新的open函数来替换系统的open函数:
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>

// 定义原始的open函数
static int (*original_open)(const char*, int, ...);

// 我们的新open函数
int open(const char *pathname, int flags, ...) {
    printf("Intercepted open call for %s\n", pathname);

    // 获取原始的open函数
    original_open = dlsym(RTLD_NEXT, "open");

    // 调用原始的open函数
    return original_open(pathname, flags);
}

~~~

你可以将这段代码保存为一个.c文件,然后使用以下命令编译为共享库:

gcc -shared -fPIC -o libintercept.so intercept.c -ldl


然后,你可以使用LD_PRELOAD环境变量来运行你的程序,如下所示:

```bash
LD_PRELOAD=./libintercept.so your_program

这样,每当你的程序调用open函数时,都会调用我们的新open函数,而不是系统的open函数。

请注意,这只是一个基本的示例,你可能需要根据你的具体需求来修改这个新的open函数。此外,使用LD_PRELOAD拦截系统调用应该谨慎进行,因为它可能会影响到其他库的行为。


第一个需求

第一个需求
1.白名单进程 保存在 进程白名单文件 , 受保护文件的文件名保存在 文件白名单文件 中,
2.白名单 进程 能访问 所有文件(受保护文件和非保护文件)
3.对所有进程访问文件的 过程进行日志记录.(进程名,文件名,访问时间,成功与否)

在这里插入图片描述

文件结构

.
├── Files
│   ├── t1
│   ├── t2
│   ├── t3
│   ├── t4
│   ├── t5
│   ├── t6
│   ├── t7
│   ├── t8
│   └── t9
├── WHITELIST
│   ├── file_whitelist
│   ├── file_whitelist_backup
│   └── process_whitelist
├── intercept.c
├── libintercept.so
├── log.txt
├── p1
└── p1.c
进程白名单

白名单文件的路径名是/home/xxx/Test/WHITELIST/process_whitelist

/home/xxx/Test/p1
/home/xxx/Test/p2
/home/xxx/Test/p3
/home/xxx/Test/p4
/home/xxx/Test/p5
文件白名单

非白名单文件的路径名是/home/xxx/Test/WHITELIST/file_whitelist

/home/xxx/Test/Files/t1
/home/xxx/Test/Files/t2
/home/xxx/Test/Files/t3
/home/xxx/Test/Files/t4
/home/xxx/Test/Files/t5

测试代码

#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main() {
    DIR *dir;
    struct dirent *entry;
    int fd;

    // 打开目录
    dir = opendir("/home/xxx/Test/Files");
    if (dir == NULL) {
        perror("无法打开目录");
        return 1;
    }

    // 遍历目录中的每个文件
    while ((entry = readdir(dir)) != NULL) {
        // 检查文件名是否以"t"开头
        if (strncmp(entry->d_name, "t", 1) == 0) {
            char filepath[1024];

            // 构造文件路径
            snprintf(filepath, sizeof(filepath), "/home/xxx/Test/Files/%s", entry->d_name);

            // 使用open函数打开文件
            fd = open(filepath, O_RDWR);
            if (fd == -1) {
                perror("无法打开文件");
                continue;
            }

            printf("打开文件: %s\n", filepath);

            // 写入文件
            const char *message = "我访问了这个文件\n";
            if (write(fd, message, strlen(message)) == -1) {
                perror("无法写入文件");
            }

            // 关闭文件
            if (close(fd) == -1) {
                perror("无法关闭文件");
            }
        }
    }

    // 关闭目录
    if (closedir(dir) == -1) {
        perror("无法关闭目录");
    }

    return 0;
}

第一个版本

gcc -shared -fPIC -o libintercept.so intercept.c -ldl

当然,这是修改后的完整代码:

#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>

// 定义原始的open函数
static int (*original_open)(const char*, int, ...);

// 根据进程ID获取进程名
char *get_process_name(pid_t pid) {
    char path[256];
    static char name[256];

    snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
    FILE *file = fopen(path, "r");
    if (file == NULL) {
        return NULL;
    }
    if (fgets(name, sizeof(name), file) == NULL) {
        fclose(file);
        return NULL;
    }

    fclose(file);

    // 将程序名称转换为绝对路径
    char *absolute_path = realpath(name, NULL);
    if (absolute_path != NULL) {
        strncpy(name, absolute_path, sizeof(name));
        free(absolute_path);
    }

    return name;
}

// 检查进程是否在白名单中
int is_whitelisted_process(const char *whitelist) {
    FILE *file = fopen(whitelist, "r");
    if (file == NULL) {
        return 0;
    }

    char *process_name = get_process_name(getpid());
    if (process_name == NULL) {
        fclose(file);
        return 0;
    }

    char line[256];
    while (fgets(line, sizeof(line), file)) {
        line[strcspn(line, "\n")] = '\0';  // 去掉换行符
        if (strcmp(line, process_name) == 0) {
            printf("匹配进程白名单成功,进程名为%s\n",process_name);
            fclose(file);
            return 1;
        }
    }

    fclose(file);
    return 0;
}

// 检查文件是否在白名单中
int is_whitelisted_file(const char *whitelist, const char *filename) {
    FILE *file = fopen(whitelist, "r");
    if (file == NULL) {
        return 0;
    }

    char line[256];
    while (fgets(line, sizeof(line), file)) {
        line[strcspn(line, "\n")] = '\0';  // 去掉换行符
        if (strcmp(line, filename) == 0) {
            printf("匹配文件白名单成功,访问文件名为%s\n",filename);
            fclose(file);
            return 1;
        }
    }

    fclose(file);
    return 0;
}

// 我们的新open函数
int open(const char *pathname, int flags, ...) {   //pathname 是打开的文件地址
    // 获取原始的open函数
    original_open = dlsym(RTLD_NEXT, "open");

    char real_path[PATH_MAX];
    realpath(pathname, real_path); // 将打开的文件路径转换为绝对路径

    // 检查进程是否在白名单中
    if (is_whitelisted_process("/home/xxx/Test/WHITELIST/process_whitelist")) {   // 传入的是进程白名单列表的绝对地址
        // 白名单进程可以访问所有文件
        return original_open(real_path, flags);
    }

    // 检查文件是否在白名单中,  传入文件白名单的绝对地址,和要访问文件的绝对地址
    if (!is_whitelisted_file("/home/xxx/Test/WHITELIST/file_whitelist", real_path)) {
        printf("非白名单文件的路径名是%s\n",real_path);
        // 非白名单进程可以访问非白名单文件
        return original_open(real_path, flags);
    }

    // 非白名单进程不能访问白名单文件
    fprintf(stderr, "拒绝访问: %s\n", real_path);
    return -1;
}

这段代码首先获取进程名,并将其转换为绝对路径。然后,它将这个绝对路径与进程白名单进行比较。如果进程在白名单中,它就可以访问所有文件。如果进程不在白名单中,但要访问的文件也不在白名单中,那么进程仍然可以访问该文件。如果进程和文件都不在白名单中,那么访问将被拒绝。

之前的版本一没有获取进程名绝对值

版本二

  1. 使用哈希表存储白名单:每次检查文件或进程是否在白名单中时,都需要打开白名单文件并逐行读取。这在白名单很大时会非常低效。相反,可以在程序启动时将白名单读入内存中的哈希表。这样,检查一个文件或进程是否在白名单中只需要在哈希表中查找,这将大大提高效率。
  2. 避免重复计算is_whitelisted_processis_whitelisted_file函数都调用了get_process_name函数来获取进程名。这意味着在一次open调用中,可能会多次计算同一个进程的名字。可以通过将进程名缓存到全局变量中来避免这种重复计算。
  3. 减少内存分配:在get_process_name函数中,每次调用都会分配一个新的字符串来存储进程名。这可能会导致大量的内存分配和释放。可以考虑使用静态缓冲区来存储进程名,从而避免频繁的内存分配。
  4. 关闭文件描述符:在is_whitelisted_processis_whitelisted_file函数中,如果在打开文件后发生错误,函数会直接返回,可能会导致文件描述符泄漏。应确保在所有可能的代码路径上都正确关闭了文件描述符。
gcc -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include/ -shared -fPIC -o libintercept.so intercept.c -ldl -lglib-2.0
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>

#include <glib.h>  // 需要安装glib库

// 定义原始的open函数
static int (*original_open)(const char*, int, ...);

// 进程名和白名单的全局变量
static char process_name[256] = {0};
static GHashTable *process_whitelist = NULL;
static GHashTable *file_whitelist = NULL;

// 根据进程ID获取进程名
char *get_process_name(pid_t pid) {
    if (process_name[0] == '\0') {
        char path[256];
        snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
        FILE *file = fopen(path, "r");
        if (file == NULL) {
            return NULL;
        }
        if (fgets(process_name, sizeof(process_name), file) == NULL) {
            fclose(file);
            return NULL;
        }
        fclose(file);
    }

      // 将程序名称转换为绝对路径
    char *absolute_path = realpath(process_name, NULL);
    if (absolute_path != NULL) {
        strncpy(process_name, absolute_path, sizeof(process_name));
        free(absolute_path);
        // printf("绝对路径不为空");
//      printf("进程绝对路径为 %s",process_name);
    }

    else{

        printf("进程名 %s 绝对路径为空\n",process_name);
    }
    return process_name;
}

// 从文件中加载白名单到哈希表
void load_whitelist(const char *filename, GHashTable **whitelist) {
    FILE *file = fopen(filename, "r");
    if (file == NULL) {
        return;
    }
    char line[256];
    while (fgets(line, sizeof(line), file)) {
        line[strcspn(line, "\n")] = '\0';  // 去掉换行符
        g_hash_table_insert(*whitelist, g_strdup(line), NULL);
    }
    fclose(file);
}

// 检查进程是否在白名单中
int is_whitelisted_process() {
    if (process_whitelist == NULL) {
        process_whitelist = g_hash_table_new(g_str_hash, g_str_equal);
        load_whitelist("/home/xxx/Test/WHITELIST/process_whitelist", &process_whitelist);
    }
    return g_hash_table_contains(process_whitelist, get_process_name(getpid()));
}

// 检查文件是否在白名单中
int is_whitelisted_file(const char *filename) {
    if (file_whitelist == NULL) {
        file_whitelist = g_hash_table_new(g_str_hash, g_str_equal);
        load_whitelist("/home/xxx/Test/WHITELIST/file_whitelist", &file_whitelist);
    }
    return g_hash_table_contains(file_whitelist, filename);
}

// 我们的新open函数
int open(const char *pathname, int flags, ...) {
    // 获取原始的open函数
    original_open = dlsym(RTLD_NEXT, "open");

    char real_path[PATH_MAX];
    realpath(pathname, real_path); // 将打开的文件路径转换为绝对路径

    // 检查进程是否在白名单中
    if (is_whitelisted_process()) {
        // 白名单进程可以访问所有文件

             printf("白名单进程访问%s 访问文件%s\n",get_process_name(getpid()),real_path);
        return original_open(real_path, flags);

    }

    // 检查文件是否在白名单中
    if (!is_whitelisted_file(real_path)) {
        // 非白名单进程可以访问非白名单文件

             printf("非白名单进程访问%s 访问 非白名单文件%s\n",get_process_name(getpid()),real_path);
        return original_open(real_path, flags);
    }

             printf("非白名单进程访问%s 访问 白名单文件%s\n",get_process_name(getpid()),real_path);
    // 非白名单进程不能访问白名单文件
    fprintf(stderr, "拒绝访问: %s\n", real_path);
    return -1;
}

这个代码使用了glib库的哈希表实现。在程序启动时,它会将白名单文件读入内存中的哈希表。然后,检查一个文件或进程是否在白名单中只需要在哈希表中查找,这将大大提高效率。此外,它还缓存了进程名,避免了重复计算。请注意,这个代码需要安装glib库才能编译和运行。

代码演示

白名单进程

能访问所有文件

在这里插入图片描述
在这里插入图片描述

非白名单进程

只能访问非白名单文件

在这里插入图片描述
在这里插入图片描述

增加一个日志记录


#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <time.h>

#include <glib.h>  // 需要安装glib库

// 定义原始的open函数
static int (*original_open)(const char*, int, ...);

// 进程名和白名单的全局变量
static char process_name[256] = {0};
static GHashTable *process_whitelist = NULL;
static GHashTable *file_whitelist = NULL;

// 日志文件名
static const char *log_filename = "/home/xxx/Test/LOG";

// 根据进程ID获取进程名
char *get_process_name(pid_t pid) {
    if (process_name[0] == '\0') {
        char path[256];
        snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
        FILE *file = fopen(path, "r");
        if (file == NULL) {
            return NULL;
        }
        if (fgets(process_name, sizeof(process_name), file) == NULL) {
            fclose(file);
            return NULL;
        }
        fclose(file);
    }


     // 将程序名称转换为绝对路径
    char *absolute_path = realpath(process_name, NULL);
    if (absolute_path != NULL) {
        strncpy(process_name, absolute_path, sizeof(process_name));
        free(absolute_path);
        // printf("绝对路径不为空");
//      printf("进程绝对路径为 %s",process_name);
    }

    else{

        printf("进程名 %s 绝对路径为空\n",process_name);
    }



    return process_name;
}

// 从文件中加载白名单到哈希表
void load_whitelist(const char *filename, GHashTable **whitelist) {
    FILE *file = fopen(filename, "r");
    if (file == NULL) {
        return;
    }
    char line[256];
    while (fgets(line, sizeof(line), file)) {
        line[strcspn(line, "\n")] = '\0';  // 去掉换行符
        g_hash_table_insert(*whitelist, g_strdup(line), NULL);
    }
    fclose(file);
}

// 检查进程是否在白名单中
int is_whitelisted_process() {
    if (process_whitelist == NULL) {
        process_whitelist = g_hash_table_new(g_str_hash, g_str_equal);
        load_whitelist("/home/xxx/Test/WHITELIST/process_whitelist", &process_whitelist);
    }
    return g_hash_table_contains(process_whitelist, get_process_name(getpid()));
}

// 检查文件是否在白名单中
int is_whitelisted_file(const char *filename) {
    if (file_whitelist == NULL) {
        file_whitelist = g_hash_table_new(g_str_hash, g_str_equal);
        load_whitelist("/home/xxx/Test/WHITELIST/file_whitelist", &file_whitelist);
    }
    return g_hash_table_contains(file_whitelist, filename);
}

// 记录日志
void log_access(const char *process, const char *file, int success) {
    FILE *log_file = fopen(log_filename, "a");
    if (log_file == NULL) {
        return;
    }

    time_t now = time(NULL);
    char *time_str = ctime(&now);
    time_str[strlen(time_str) - 1] = '\0';  // 去掉换行符

    fprintf(log_file, "[%s] Process: %s, File: %s, Access: %s\n",
            time_str, process, file, success ? "SUCCESS" : "FAILURE");

    fclose(log_file);
}

// 我们的新open函数
int open(const char *pathname, int flags, ...) {
    // 获取原始的open函数
    original_open = dlsym(RTLD_NEXT, "open");

    char real_path[PATH_MAX];
    realpath(pathname, real_path); // 将打开的文件路径转换为绝对路径

    // 检查进程是否在白名单中
    if (is_whitelisted_process()) {
        // 白名单进程可以访问所有文件
        if (is_whitelisted_file(real_path)) {
            // 记录白名单进程访问白名单文件的日志
            log_access(get_process_name(getpid()), real_path, 1);
        }
        return original_open(real_path, flags);
    }

    // 检查文件是否在白名单中
    if (is_whitelisted_file(real_path)) {
        // 记录非白名单进程访问白名单文件的日志
        log_access(get_process_name(getpid()), real_path, 0);
        fprintf(stderr, "拒绝访问: %s\n", real_path);
        return -1;
    }

    // 非白名单进程可以访问非白名单文件
    return original_open(real_path, flags);
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码解释

这段代码主要包含以下几个函数:

  1. get_process_name(pid_t pid):此函数根据进程ID获取进程名。它首先检查全局变量process_name是否已经被设置。如果没有,它会打开/proc/<pid>/cmdline文件并读取第一行,这就是进程名。然后,它会将进程名转换为绝对路径。
  2. load_whitelist(const char *filename, GHashTable **whitelist):此函数从指定的文件中加载白名单,并将其存储在一个哈希表中。每一行都被视为一个独立的条目。
  3. is_whitelisted_process()is_whitelisted_file(const char *filename):这两个函数检查给定的进程或文件是否在相应的白名单中。如果白名单哈希表尚未创建,它们会首先调用load_whitelist函数来加载白名单。
  4. log_access(const char *process, const char *file, int success):此函数将访问记录写入日志文件。每条记录包含时间戳、进程名、文件名和访问结果(成功或失败)。
  5. open(const char *pathname, int flags, ...):这是一个拦截open系统调用的函数。它首先检查调用进程是否在进程白名单中。如果在,那么它可以打开任何文件。否则,它只能打开文件白名单中的文件。如果一个非白名单进程试图打开一个白名单文件,访问将被拒绝,并记录一条失败的访问记录。

这个拦截器可以用来限制某些进程访问敏感文件,或者跟踪某些进程的文件访问行为。但是,它也可能被用于恶意目的,比如阻止某些进程正常工作。因此,使用这种拦截器需要谨慎。

这段代码是一个Linux系统调用拦截器,它拦截了open系统调用。这个拦截器的目的是限制某些进程访问特定的文件。它的工作原理如下:

  1. 获取进程名get_process_name函数通过读取/proc/<pid>/cmdline文件来获取进程名。这个文件包含了启动该进程的命令行参数。
  2. 加载白名单load_whitelist函数从指定的文件中读取白名单,并将其存储在一个哈希表中。白名单中的每一行都被视为一个独立的条目。
  3. 检查白名单is_whitelisted_processis_whitelisted_file函数检查给定的进程或文件是否在相应的白名单中。
  4. 记录日志log_access函数将访问记录写入日志文件。每条记录包含时间戳、进程名、文件名和访问结果(成功或失败)。
  5. 拦截open系统调用:新的open函数首先检查调用进程是否在进程白名单中。如果在,那么它可以打开任何文件。否则,它只能打开文件白名单中的文件。如果一个非白名单进程试图打开一个白名单文件,访问将被拒绝,并记录一条失败的访问记录。

这个拦截器可以用来限制某些进程访问敏感文件,或者跟踪某些进程的文件访问行为。但是,它也可能被用于恶意目的,比如阻止某些进程正常工作。因此,使用这种拦截器需要谨慎。

记录。

这个拦截器可以用来限制某些进程访问敏感文件,或者跟踪某些进程的文件访问行为。但是,它也可能被用于恶意目的,比如阻止某些进程正常工作。因此,使用这种拦截器需要谨慎。

这段代码是一个Linux系统调用拦截器,它拦截了open系统调用。这个拦截器的目的是限制某些进程访问特定的文件。它的工作原理如下:

  1. 获取进程名get_process_name函数通过读取/proc/<pid>/cmdline文件来获取进程名。这个文件包含了启动该进程的命令行参数。
  2. 加载白名单load_whitelist函数从指定的文件中读取白名单,并将其存储在一个哈希表中。白名单中的每一行都被视为一个独立的条目。
  3. 检查白名单is_whitelisted_processis_whitelisted_file函数检查给定的进程或文件是否在相应的白名单中。
  4. 记录日志log_access函数将访问记录写入日志文件。每条记录包含时间戳、进程名、文件名和访问结果(成功或失败)。
  5. 拦截open系统调用:新的open函数首先检查调用进程是否在进程白名单中。如果在,那么它可以打开任何文件。否则,它只能打开文件白名单中的文件。如果一个非白名单进程试图打开一个白名单文件,访问将被拒绝,并记录一条失败的访问记录。

这个拦截器可以用来限制某些进程访问敏感文件,或者跟踪某些进程的文件访问行为。但是,它也可能被用于恶意目的,比如阻止某些进程正常工作。因此,使用这种拦截器需要谨慎。


待改进之处
程序一开始就应该加载白名单文件,而不是在open函数调用一次就加载一次。但是如果一开始就加载文件白名单,之后如果对白名单文件进行修改,就要将 该so 库文件重新编译一次。 如果能监控白名单文件是否修改,如果修改了就再加载白名单文件 就好了

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

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

相关文章

RT-DETR优化:Backbone改进 | UniRepLKNet,通用感知大内核卷积网络,RepLK改进版本 | 2023.11

🚀🚀🚀本文改进: UniRepLKNet,通用感知大内核卷积网络,ImageNet-22K预训练,精度和速度SOTA,ImageNet达到88%, COCO达到56.4 box AP,ADE20K达到55.6 mIoU 🚀🚀🚀RT-DETR改进创新专栏:http://t.csdnimg.cn/vuQTz 学姐带你学习YOLOv8,从入门到创新,轻轻松松…

无人机高空巡查+智能视频监控技术,打造森林防火智慧方案

随着冬季的到来&#xff0c;森林防火的警钟再次敲响&#xff0c;由于森林面积广袤&#xff0c;地形复杂&#xff0c;且人员稀少&#xff0c;一旦发生火灾&#xff0c;人员无法及时发现&#xff0c;稍有疏忽就会酿成不可挽救的大祸。无人机高空巡查智能视频监控是一种非常有效的…

库卡LBR_iisy_3_R760协作机器人导入到coppeliasim

1.从库卡官网xpert下载模型 一般载都是这个step文件格式&#xff0c;其他的好像不太好用。coppeliasim导入格式用的是stl,需要用freeCAD打开重新转换一下。下载下来后&#xff0c;很多都是一个整体&#xff0c;在freeCAD导入中&#xff0c;导入选择要不勾选合并。 下载完用CAD …

Day54力扣打卡

打卡记录 出租车的最大盈利&#xff08;动态规划&#xff09; 链接 class Solution:def maxTaxiEarnings(self, n: int, rides: List[List[int]]) -> int:d defaultdict(list)for start, end, w in rides:d[end].append((start, end - start w))f [0] * (n 1)for i in…

linux进入emergency mode

问题描述 linux系统进入emergency mode模式 解决方法 查看问题原因 journalctl -xb -p3 使用fsck 不一定是sda2&#xff0c;也可能是其他&#xff0c;我的是/dev/sda6&#xff0c;然后接受所有的option&#xff0c;完毕后重启电脑 fsck /dev/sda2接受所有的选项&#xff…

华为配置Smart Link主备备份示例

定义 Smart Link&#xff0c;又叫做备份链路。一个Smart Link由两个接口组成&#xff0c;其中一个接口作为另一个的备份。Smart Link常用于双上行组网&#xff0c;提供可靠高效的备份和快速的切换机制。 Monitor Link是一种接口联动方案&#xff0c;它通过监控设备的上行接口…

Leetcode—2646.最小化旅行的价格总和【困难】

2023每日刷题&#xff08;五十三&#xff09; Leetcode—2646.最小化旅行的价格总和 算法思想 看灵神的 实现代码 class Solution { public:int minimumTotalPrice(int n, vector<vector<int>>& edges, vector<int>& price, vector<vector&l…

Spring Boot 整合 xxl-job 保姆级教程!

文章目录 介绍使用初始化“调度数据库”配置调度中心配置“执行器项目”调度任务 介绍 首先我们介绍一下什么是xxl-job&#xff0c;根据官方定义&#xff0c;XXL-JOB是一个分布式任务调度平台&#xff0c;其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码…

快速学会绘制Pyqt5中的所有图(下)

Pyqt5相关文章: 快速掌握Pyqt5的三种主窗口 快速掌握Pyqt5的2种弹簧 快速掌握Pyqt5的5种布局 快速弄懂Pyqt5的5种项目视图&#xff08;Item View&#xff09; 快速弄懂Pyqt5的4种项目部件&#xff08;Item Widget&#xff09; 快速掌握Pyqt5的6种按钮 快速掌握Pyqt5的10种容器&…

【Go自学版】02-goroutine

利用时间片分割进程&#xff0c;致使宏观上A,B,C同时执行&#xff08;并发&#xff09; CPU利用率包含了执行和切换&#xff0c;进程/线程的数量越多&#xff0c;切换成本也会增大 最大并行数&#xff1a;GOMAXPROCS work stealing: 偷其他队列的G hand off: 当前G1阻塞&#…

【Pytorch】Fizz Buzz

文章目录 1 数据编码2 网络搭建3 网络配置&#xff0c;训练4 结果预测5 翻车现场 学习参考来自&#xff1a; Fizz Buzz in Tensorflowhttps://github.com/wmn7/ML_Practice/tree/master/2019_06_10Fizz Buzz in Pytorch I need you to print the numbers from 1 to 100, excep…

数字化转型怎么才能做成功?_光点科技

数字化转型对于现代企业来说是一场必要的革命。它不仅仅是技术的更迭&#xff0c;更是企业战略、文化和运营方式全面升级的体现。一个成功的数字化转型能够使企业更具竞争力、更灵活应对市场变化&#xff0c;并最终实现业务增长和效率提升。那么&#xff0c;数字化转型怎么才能…

JVM常见垃圾回收器

串行垃圾回收器 Serial和Serial Old串行垃圾回收器&#xff0c;是指使用单线程进行垃圾回收&#xff0c;堆内存较小&#xff0c;适合个人电脑 Serial作用于新生代&#xff0c;采用复制算法 Serial Old作用于老年代&#xff0c;采用标记-整理算法 垃圾回收时&#xff0c;只有…

Navicat 技术指引 | 适用于 GaussDB 分布式的数据生成功能

Navicat Premium&#xff08;16.3.3 Windows 版或以上&#xff09;正式支持 GaussDB 分布式数据库。GaussDB 分布式模式更适合对系统可用性和数据处理能力要求较高的场景。Navicat 工具不仅提供可视化数据查看和编辑功能&#xff0c;还提供强大的高阶功能&#xff08;如模型、结…

物联网后端个人第十四周总结

物联网方面进度 1.登陆超时是因为后端运行的端口和前端监听的接口不一样&#xff0c;所以后端也没有报错&#xff0c;将二者修改一致即可 2.登录之后会进行平台的初始化&#xff0c;但是初始化的时候会卡住,此时只需要将路径的IP端口后边的内容去掉即可 3.阅读并完成了jetlinks…

log4j(日志的配置)

日志一般配置在resources的config下面的&#xff0c;并且Util当中的initLogRecord中的initLog&#xff08;&#xff09;方法就是加载这个log4j.properties的. 首先先看log4j.properties的配置文件 log4j.rootLoggerdebug, stdout, Rlog4j.appender.stdoutorg.apache.log4j.Co…

【UE 材质】任务目标点效果

效果 步骤 1. 新建一个工程&#xff0c;创建一个Basic关卡 2. 新建一个材质&#xff0c;这里命名为“M_GoalPoint” 打开“M_GoalPoint”&#xff0c;设置混合模式为“半透明”&#xff0c;勾选“双面” 在材质图表中添加如下节点 此时预览效果如下 继续添加如下节点 此时效果…

iPaaS架构深入探讨

在数字化时代全面来临之际&#xff0c;企业正面临着前所未有的挑战与机遇。技术的迅猛发展与数字化转型正在彻底颠覆各行各业的格局&#xff0c;不断推动着企业迈向新的前程。然而&#xff0c;这一数字化时代亦衍生出一系列复杂而深奥的难题&#xff1a;各异系统之间数据孤岛、…

3D材质编辑:制作被火烧的木头

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 当谈到游戏角色的3D模型风格时&#xff0c;有几种不同的风格&#xf…

使用STM32定时器实现精确的时间测量和延时

✅作者简介&#xff1a;热爱科研的嵌入式开发者&#xff0c;修心和技术同步精进&#xff0c; 代码获取、问题探讨及文章转载可私信。 ☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。 &#x1f34e;获取更多嵌入式资料可点击链接进群领取&#xff0c;谢谢支持&#xff01;…