Linux系统编程入门(下)

news2024/11/17 15:27:21

Linux系统编程

    • 第一章 Linux系统编程入门(下)
      • 1.6 GDB 调试
      • 1.7 标准C库IO函数和Linux系统IO函数对比

第一章 Linux系统编程入门(上)

第一章 Linux系统编程入门(下)

1.6 GDB 调试

(1)什么是 GDB

  • GDB (GNU debugger) 是由 GNU 软件系统社区提供的调试工具,同 GCC 配套组成了一套完整的开发环境, GDB 是 Linux 和许多类 Unix 系统中的标准开发环境。

  • 一般来说, GDB 主要帮助你完成下面四个方面的功能

    1. 启动程序,可以按照自定义的要求随心所欲的运行程序
    2. 可让被调试的程序在所指定的调置的断点处停住(断点可以是条件表达式
    3. 当程序被停住时,可以检查此时程序中所发生的事
    4. 可以改变程序,将一个 BUG 产生的影响修正从而测试其他 BUG
  • 通常,在为调试而编译时,我们会()关掉编译器的优化选项(-O) 并打开调试选项-g)。另外 -Wall 在尽量不影响程序行为的情况下选项打开所有 warning ,也可以发现许多问题,避免一些不必要的 BUG

    gcc -g -Wall program.c -o program
    
    • -g 选项的作用是在可执行文件中加入源代码的信息,比如可执行文件中第几条机器指令对应源代码的第几行,但并不是把整个源文件嵌入到可执行文件中,所以在调试时必须保证 gdb 能找到源文件


例如,有一个test.c文件:

// test.c
#include <stdio.h>
#include <stdlib.h>

int test(int a);

int main(int argc, char* argv[]) {
    int a, b;
    printf("argc = %d\n", argc);

    if(argc < 3) {
        a = 10;
        b = 30;
    } else {
        a = atoi(argv[1]);
        b = atoi(argv[2]);
    }
    printf("a = %d, b = %d\n", a, b);
    printf("a + b = %d\n", a + b);

    for(int i = 0; i < a; ++i) {
        printf("i = %d\n", i);
        // 函数调用
        int res = test(i);
        printf("res value: %d\n", res);
    }

    printf("THE END !!!\n");
    return 0;
}

int test(int a) {
    int num = 0;
    for(int i = 0; i < a; ++i) {
        num += i;
    }
    return num;
}
gcc test.c -o test -g

在这里插入图片描述

(2)GDB命令——启动、退出、查看代码

  • 启动和退出

    gdb 可执行程序	 # 进入gdb
    quit 或 q 		# 在调试命令行输入quit就可退出调试
    

    在这里插入图片描述

  • 给程序设置参数 / 获取设置参数

    set args 10 20
    show args
    

    在这里插入图片描述

  • GDB 使用帮助

    help
    
  • 查看当前文件代码

    # 也可以在终端使用 vim 查看
    
    list/l 			  #(从默认位置显示)
    list/l 行号		 #(从指定行号显示,以该行号为中心,显示指定的行的上下文)
    list/l 函数名		#(从指定的函数显示, 也是上下文)
    

    在这里插入图片描述

  • 查看非当前文件代码

    list/l 文件名:行号
    list/l 文件名:函数名
    
    • 一个程序有好几个文件组成,当我们调试主函数所在程序时,其他文件的代码也需要查看,就可以使用上述命令。一个项目中含:bubble.cppselect.cppmain.cpp

      在这里插入图片描述

    • 在调试时,默认显示 main.cpp 中的代码。如下图所示:

      在这里插入图片描述

    • 查看非当前文件代码 (默认显示10行)

      在这里插入图片描述

  • 设置显示的行数

    show list/listsize
    set  list/listsize 行数
    

    在这里插入图片描述

(3)GDB命令——断点操作

  • 设置断点

    b/break 行号
    b/break 函数名
    b/break 文件名:行号
    b/break 文件名:函数
    
  • 查看断点

    i/info b/break
    

    在这里插入图片描述

    • num : 断点编号
    • Type下的 breakpoint说明该点为断点
    • Disp断点状态
    • Enbyes 代表为有效断点
    • adress断点地址
    • What 说明断点的在那个文件的第几行
  • 删除断点

    d/del/delete 断点编号
    

    在这里插入图片描述

  • 设置断点无效

    dis/disable 断点编号
    
  • 设置断点生效

    ena/enable 断点编号
    

    在这里插入图片描述

  • 设置条件断点(一般用在循环的位置)

    b/break 10 if i==5
    

    在这里插入图片描述

(4)GDB命令——调试命令

  • 运行 GDB 程序

    start 		# (程序停在第一行)
    run 		# (遇到断点才停)
    
  • 继续运行,到下一个断点停

    c/continue
    

    在这里插入图片描述

  • 向下执行一行代码(不会进入函数体)

    n/next
    
  • 变量操作

    p/print 变量名 		# (打印变量值)
    ptype 变量名			# (打印变量类型)
    
  • 向下单步调试(遇到函数进入函数体)

    s/step
    finish 					# (跳出函数体)
    
  • 自动变量操作

    display 变量名				# (自动打印指定变量的值,每次运行到该变量,都会自动打印)
    i/info display
    undisplay 编号
    
  • 其它操作

    set var	变量名=变量值 		 # (循环中用的较多)
    until						 #(跳出循环 (里面不能有断点,不然又会运行到断点处))
    

1.7 标准C库IO函数和Linux系统IO函数对比

  • 文件IO:从 内存 的角度看,输入Input文件 -> 内存),输出Output内存 -> 文件

(1)标准 C 库 IO 和 Linux 系统 IO 的关系

  • 标准 C 库 IO 函数在这里插入图片描述

    • 标准 C 库 IO 函数,可跨平台
    • 标准 C 库 IO 函数,高于 Linux系统IO函数 (标准C 调用 Linux系统的IO函数),尽量使用标准 C 库 IO 函数,缓冲区可以提高效率。
    • 而网络通信中应该使用Linux系统的IO函数。

  • 标准 C 库 IO 和 Linux 系统 IO 的关系
    在这里插入图片描述

(2)虚拟地址空间

在这里插入图片描述

(3)文件描述符

在这里插入图片描述

  • 文件描述符内核区
  • 文件描述符表是一个数组(默认大小为1024),可以存储 n文件描述符
  • 每个进程都有个文件描述符表,所以最大能打开文件的个数为 1024 个。
  • Linux 系统当中不管什么 硬件设备(显示器、网卡、显卡)都一个 虚拟 为一个文件。(Linux中一切皆文件!

(4)Linux 系统 IO 函数

  • Linux 系统中的 函数API2 中查找,而标准C库中的 API 说明文档应该在 3 中查找。
# 在 Linux终端 输入以下命令来查看手册
man 2 open

在这里插入图片描述

// 打开一个已经存在的文件
int open(const char *pathname, int flags);

// 创建一个新文件
int open(const char *pathname, int flags, mode_t mode); // 可变参数

// 关闭文件
int close(int fd); // 传入参数:文件描述符

ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);

off_t lseek(int fd, off_t offset, int whence);

int stat(const char *pathname, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);
  • int open(const char *pathname, int flags); 打开一个已经存在的文件

    • 参数

      • pathname:要打开的文件路径

      • flags:对文件的操作权限设置还有其他的设置

        O_RDONLY, O_WRONLY, O_RDWR 这三个设置是互斥的

    • 返回值:返回一个新的文件描述符,如果调用失败,返回 -1

    errno:属于Linux系统函数库,库里面的一个全局变量,记录的是最近的错误号

    #include <stdio.h> 标准C库

    void perror(const char *s);作用:打印 errno对应的错误描述

    • s参数:用户描述,比如 hello,最终输出的内容是 hello:xxx(实际的错误描述)
  • int open(const char *pathname, int flags, mode_t mode);

    • 参数

      • pathname:要创建的文件的路径

      • flags:对文件的操作权限和其他的设置
        - 必选项O_RDONLY, O_WRONLY, O_RDWR 这三个之间是互斥的
        - 可选项O_CREAT 文件不存在,创建新文件

      • mode:八进制的数,表示创建出的新的文件的操作权限,比如:0775

      最终的权限是:mode & ~umask
      0777 -> 111111111
      & 0775 -> 111111101
      ------------------------------------------
      ​ 111111101

      • 按位与:0和任何数都为0
      • umask 的作用就是 抹去某些权限

      flags 参数是一个 int 类型的数据,占4个字节,32位。
      flags 32个位,每一位就是一个标志位。(按位或

    • 例如:create.c

      #include <sys/types.h>
      #include <sys/stat.h>
      #include <fcntl.h>
      #include <unistd.h> // Unix 的标准IO
      #include <stdio.h>  // 标准C库
      
      int main() {
      
          // 创建一个新的文件
          int fd = open("create.txt", O_RDWR | O_CREAT, 0777);
      
          if(fd == -1) {
              perror("open");
          }
      
          // 关闭
          close(fd);
      
          return 0;
      }
      
  • ssize_t read(int fd, void *buf, size_t count);

    • 参数

      • fd文件描述符open得到的,通过这个文件描述符操作某个文件
      • buf:读取数据存放的地方,数组的地址(传出参数
      • count:指定的 数组的大小大于数组大小则截断
    • 返回值

             - 成功:
      
       `>0`: 返回实际的读取到的 **字节数**
       `=0`:文件已经读取完了
       
       
                 - 失败:`-1` ,并且设置 `errno`
      
  • ssize_t write(int fd, const void *buf, size_t count);

    • 参数

      • fd文件描述符open 得到的,通过这个文件描述符操作某个文件

      • buf:要往磁盘写入的数据,数组

      • count:要写的数据的实际的大小

    • 返回值

      • 成功:实际写入的字节数

      • 失败:返回 -1,并设置 errno

    #include <unistd.h>
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>    // 存放 宏
    #include <fcntl.h>
    
    int main() {
    
        // 1.通过open打开english.txt文件
        int srcfd = open("english.txt", O_RDONLY);
        if(srcfd == -1) {
            perror("open");
            return -1;
        }
    
        // 2.创建一个新的文件(拷贝文件)
        int destfd = open("cpy.txt", O_WRONLY | O_CREAT, 0664);
        if(destfd == -1) {
            perror("open");
            return -1;
        }
    
        // 3.频繁的读写操作
        char buf[1024] = {0};
        int len = 0;
        while((len = read(srcfd, buf, sizeof(buf))) > 0) {
            write(destfd, buf, len);
        }
    
        // 4.关闭文件
        close(destfd);
        close(srcfd);
    
        return 0;
    }
    

(5)stat 结构体

struct stat {
    dev_t st_dev;			 // 文件的设备编号
    ino_t st_ino; 			 // 节点
    mode_t st_mode; 		 // 文件的类型和存取权限
    nlink_t st_nlink; 		 // 连到该文件的硬接数目
    uid_t st_uid;			 // 用户 ID
    gid_t st_gid;			 // 组ID
    dev_t st_rdev;			 // 设备文件的编号
    off_t st_size;			 // 文件字节数 (文件大小 )
    blksize_t st_blksize;	 // 块大小
    blkcnt_t st_blocks;		 // 块数
    time_t st_atime;		 // 最后一次访问时间
    time_t st_mtime;		 // 最后一次修改时间
    time_t st_ctime;		 // 最后一次改变时间 (指属性 )
};

(6)st_mode 变量

在这里插入图片描述

(7)文件属性操作函数

// 判断某个文件是否有某个权限,或者判断文件是否存在
int access(const char *pathname, int mode);

// 修改文件的权限
int chmod(const char *filename, int mode);

// 修改文件的所有者和所在组
int chown(const char *path, uid_t owner, gid_t group);

// 缩减或者扩展文件的尺寸至指定的大小
int truncate(const char *path, off_t length);
  • int access(const char *pathname, int mode);

    • 作用:判断某个文件是否有某个权限,或者判断文件是否存在

    • 参数

      • pathname: 判断的文件路径

      • mode:

        R_OK: 判断是否有权限

        W_OK: 判断是否有权限

        X_OK: 判断是否有执行权限

        F_OK: 判断文件是否存在

    • 返回值:成功返回 0, 失败返回 -1

  • int chmod(const char *pathname, mode_t mode);

    • 作用:修改文件的权限
    • 参数
      • pathname: 需要修改的文件的路径
      • mode: 需要修改的权限值,八进制的数
    • 返回值:成功返回 0,失败返回 -1
  • int truncate(const char *path, off_t length);

    • 作用:缩减或者扩展文件的尺寸至指定的大小
    • 参数
      • path: 需要修改的文件的路径
      • length: 需要最终文件变成的大小
    • 返回值
      • 成功返回0, 失败返回-1

(8)目录操作函数

// 修改目录名字
int rename(const char *oldpath, const char *newpath);

// 修改进程的工作目录
int chdir(const char *path);
// 获取当前工作目录
char *getcwd(char *buf, size_t size);

// 创建一个目录
int mkdir(const char *pathname, mode_t mode);
// 删除空目录
int rmdir(const char *pathname);

查看 系统函数 的帮助文档:man 2 mkdir

查看 Linux命令 的帮助文档:man mkdir

  • int chdir(const char *path);

    • 作用:修改进程的工作目录
      • 比如,在 /home/nowcoder 启动了一个可执行程序 a.out, 进程的工作目录 /home/nowcoder
    • 参数
      • path : 需要修改的工作目录
  • char *getcwd(char *buf, size_t size);

  • 作用:获取当前工作目录

  • 参数

    • buf : 存储的路径,指向的是一个数组(传出参数)
    • size: 数组的大小
  • 返回值

    • 返回的指向的一块内存,这个数据就是第一个参数

例如:

#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>

int main() {

    // 获取当前的工作目录
    char buf[128];
    getcwd(buf, sizeof(buf));
    printf("当前的工作目录是:%s\n", buf);

    // 修改工作目录
    int ret = chdir("/home/nowcoder/Linux/lesson13");
    if(ret == -1) {
        perror("chdir");
        return -1;
    } 

    // 创建一个新的文件
    int fd = open("chdir.txt", O_CREAT | O_RDWR, 0664);
    if(fd == -1) {
        perror("open");
        return -1;
    }

    close(fd);

    // 获取当前的工作目录
    char buf1[128];
    getcwd(buf1, sizeof(buf1));
    printf("当前的工作目录是:%s\n", buf1);
    
    return 0;
}

输出

当前的工作目录是: /home/nowcoder/Linux/lesson14
当前的工作目录是: /home/nowcoder/Linux/lesson13

  • int mkdir(const char *pathname, mode_t mode);
    • 作用:创建一个目录
    • 参数
      • pathname: 创建的目录的路径
      • mode: 权限,八进制的数
    • 返回值
      • 成功返回 0, 失败返回 -1

(9)目录遍历函数

// 打开一个目录
DIR *opendir(const char *name);

// 读取目录中的数据(while循环遍历)
struct dirent *readdir(DIR *dirp);

// 关闭目录
int closedir(DIR *dirp);

这3个函数在第3章 标准c库 中:man 3 opendir

在Linux中,man 命令用于查看手册页manual pages)以获取关于系统命令库函数等的信息。手册页被分为多个章节,其中常见的有 man 1man 2man 3 等。这些数字代表手册页的不同章节,每个章节有特定的主题。

  • man 1:用于 可执行程序 的手册页。包括系统命令和可执行程序的文档。
  • man 2:用于 系统调用 的手册页。包括内核系统调用的详细文档。
  • man 3:用于 库函数 的手册页。包括C标准库中提供的函数的详细文档。
  • DIR *opendir(const char *name);

    • 参数
      • name: 需要打开的 目录的名称
    • 返回值
      • DIR* 类型,理解为目录流
      • 错误返回 NULL
  • struct dirent *readdir(DIR *dirp);

    • 参数dirpopendir 返回的结果
    • 返回值
      • struct dirent,代表读取到的文件的信息
      • 读取到了末尾或者失败了,返回 NULL

dirent 结构体和 d_type

struct dirent
{
    // 此目录进入点的 inode
    ino_t d_ino;
    // 目录文件开头至此目录进入点的位移
    off_t d_off;
    // d_name 的长度 , 不包含 NULL 字符
    unsigned short int d_reclen;
    // d_name 所指的文件类型
    unsigned char d_type;
    // 文件名
    char d_name[256];
};

d_type // 
    DT_BLK -块设备
    DT_CHR -字符设备
    DT_DIR -目录
    DT_LNK -软连接
    DT_FIFO -管道
    DT_REG -普通文件
    DT_SOCK -套接字
    DT_UNKNOWN -未知

(10)dupdup2 函数

int dup(int oldfd);  // 复制文件描述符

int dup2(int oldfd, int newfd); //重定向文件描述符
  • int dup(int oldfd);

    • 作用复制 一个新的文件描述符

    fd=3, int fd1 = dup(fd),

    • fd 指向的是 a.txt, fd1 也是指向 a.txt

    空闲的文件描述符表中找一个 最小的,作为新的拷贝的文件描述符

  • int dup2(int oldfd, int newfd);

    • 作用重定向 文件描述符

    oldfd 指向 a.txt, newfd 指向 b.txt

    • 调用函数成功后:newfdb.txtclose, newfd 指向了 a.txt ,返回 newfd
    • oldfd 必须是一个有效的文件描述符
    • 如果oldfdnewfd 值相同,相当于什么都没有做

(11)fcntl 函数

int fcntl(int fd, int cmd, ... /* arg */ );
// 复制文件描述符
// 设置/获取文件的状态标志
  • int fcntl(int fd, int cmd, ...);

    • 参数

      • fd : 表示需要操作的 文件描述符

      • cmd: 表示对文件描述符进行如何操作

        • F_DUPFD : 复制文件描述符, 复制的是第一个参数fd,得到一个新的文件描述符(返回值)int ret = fcntl(fd, F_DUPFD);

        • F_GETFL : 获取指定的文件描述符 文件状态`flag

           获取的 flag和我们通过open函数传递的flag是一个东西。

        • F_SETFL : 设置 文件描述符 文件状态 flag

           必选项:O_RDONLY, O_WRONLY, O_RDWR 不可以被修改

           可选性:O_APPEND, O_NONBLOCK

          O_APPEND 表示 追加数据

          O_NONBLOK 设置成 非阻塞

      • 阻塞和非阻塞:描述的是函数调用的行为。

    具体查看man 2 fcntl

    #include <unistd.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <string.h>
    
    int main() {
    
    // 1.复制文件描述符
    // int fd = open("1.txt", O_RDONLY);
    // int ret = fcntl(fd, F_DUPFD);
    
    // 2.修改或者获取文件状态flag
    int fd = open("1.txt", O_RDWR);
    if(fd == -1) {
        perror("open");
        return -1;
    }
    
    // 获取文件描述符状态flag
    int flag = fcntl(fd, F_GETFL);
    if(flag == -1) {
        perror("fcntl");
        return -1;
    }
    flag |= O_APPEND;   // flag = flag | O_APPEND
    
    // 修改文件描述符状态的flag,给flag加入O_APPEND这个标记
    int ret = fcntl(fd, F_SETFL, flag);
    if(ret == -1) {
        perror("fcntl");
        return -1;
    }
    
    char * str = "nihao";
    write(fd, str, strlen(str));
    
    close(fd);
    
    return 0;
    }
    

注:仅供学习参考,如有不足,欢迎指正!

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

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

相关文章

AOP(黑马学习笔记)

AOP基础 学习完spring的事务管理之后&#xff0c;接下来我们进入到AOP的学习。 AOP也是spring框架的第二大核心&#xff0c;我们先来学习AOP的基础。 在AOP基础这个阶段&#xff0c;我们首先介绍一下什么是AOP&#xff0c;再通过一个快速入门程序&#xff0c;让大家快速体验A…

JVM性能优化

运行时优化 方法内联 方法内联&#xff0c;是指 JVM在运行时将调用次数达到一定阈值的方法调用替换为方法体本身 &#xff0c;从而消除调用成本&#xff0c;并为接下来进一步的代码性能优化提供基础&#xff0c;是JVM的一个重要优化手段之一。 注&#xff1a; C的inline属于编…

构建一个基于Node.js的文件存储服务

随着现代web应用程序变得越来越复杂和功能强大&#xff0c;文件存储服务成为了许多应用的重要组成部分。在本篇博客中&#xff0c;我们将探讨如何构建一个基于Node.js的文件存储服务&#xff0c;让您可以轻松地上传、下载和管理文件。我们将利用Node.js的强大功能和模块来构建这…

【Javascript编程实操01】判断最大数、奇偶数、是否成年

目录 前言 1、求两个数的最大数 代码&#xff1a; 实现效果&#xff1a; 2、判断一个整数是偶数还是奇数 代码&#xff1a; 实现效果&#xff1a; 3、判断一个人的年龄是否满18岁 代码&#xff1a; 实现效果&#xff1a; 总结 前言 从今天开始正式进入了Web前端第二…

信安数学(验证定理6.3.2~6.3.3)

定理6.3.2 如果n是对于基b的强伪素数&#xff0c;则n是对于基b得到欧拉伪素数 nint(input("给定一奇合数n&#xff1a;")) bint(input("给定一个整数b&#xff1a;")) def solution(a,b):#若b>a&#xff0c;则交换两个数的值if(b>a):taabbtr b #初…

字符函数与字符串函数(上)

个人主页&#xff08;找往期文章包括但不限于本期文章中不懂的知识点&#xff09;&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 目录 strlen的使用与模拟实现 函数原型&#xff1a; strlen的使用 strlen的模拟使用 strcpy的使用与模拟实现 函数原型&#xff1a; strcpy的使…

【冲击蓝桥篇】动态规划(上):真题实战+思路解析

&#x1f389;&#x1f389;欢迎光临&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;特别推荐给大家我的最新专栏《数据结构与算法&#xff1a;初学者入门指南》&#x1f4d8;&am…

普中51单片机学习(EEPROM)

EEPROM IIC串行总线的组成及工作原理 I2C总线的数据传送 数据位的有效性规定 I2C总线进行数据传送时&#xff0c;时钟信号为高电平期间&#xff0c;数据线上的数据必须保持稳定&#xff0c;只有在时钟线上的信号为低电平期间&#xff0c;数据线上的高电平或低电平状态才允许…

【Java 基础】Java 数组、方法极致精讲

《Java 零基础入门到精通》专栏持续更新中。通过本专栏你将学习到 Java 从入门到进阶再到实战的全套完整内容,所有内容均将集中于此专栏。无论是初学者还是有经验的开发人员,都可从本专栏获益。 订阅专栏后添加我微信或者进交流群,进群可找我领取 前端/Java/大数据/Python/低…

从0到1使用C++实现一个模拟器-1-【实现最简CPU】

文章目录 uint64_tstdstd::arrayCPU和CU类构造函数size_tstatic_caststd::ifstreamriscv64-unknown-elf-objcopy -O binary add-addi add-addi.binriscv64-unknown-elf-gcc -Wl,-Ttext0x0 -nostdlib -o add-addi add-addi.s-wlstd::hex std::setw() std::setfill()各自的用法he…

upload-Labs靶场“1-5”关通关教程

君衍. 一、环境搭建二、第一关 前端JS检测后缀1、源码分析2、禁用浏览器JS上传3、burp抓包修改 三、第二关 MIME头验证1、源码分析2、burp抓包绕过 四、第三关 PHP3绕过1、源码分析2、PHP3绕过 五、第四关 .htaccess重写绕过1、源码分析2、.htaccess复写 六、第五关 黑名单大小…

Qt槽函数不响应的原因总结

Qt专栏&#xff1a;http://t.csdnimg.cn/LE2Lx 目录 1.问题 2.原因 2.1.没有继承QObject&#xff0c;声明Q_OBJECT宏 2.2.信号槽参数不匹配 2.3.信号函数未声明为 signals 2.4.访问权限 2.5.注意connect的位置&#xff0c;信号在创建信号槽连接前使用&#xff0c;则无法…

C#使用iText7将多个PDF文档合并为单个文档

使用HtmlAgilityPack抓取并分析网页内容&#xff0c;然后再调用PuppeteerSharp将网页生成PDF文件&#xff0c;最终的成果如下图所示&#xff0c;得到将近120个pdf文档。能看&#xff0c;但是不方便&#xff0c;需要逐个打开文档才能看到所需的内容&#xff0c;最好能将这些文档…

java 企业培训管理系统Myeclipse开发mysql数据库web结构jsp编程计算机网页项目

一、源码特点 java 企业培训管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&…

Vulnhub靶机:basic_pentesting_2

一、介绍 运行环境&#xff1a;Virtualbox 攻击机&#xff1a;kali&#xff08;10.0.2.4&#xff09; 靶机&#xff1a;basic_pentesting_2&#xff08;10.0.2.7&#xff09; 目标&#xff1a;获取靶机root权限和flag 靶机下载地址&#xff1a;https://download.vulnhub.c…

未来已来:智慧餐饮点餐系统引领餐饮业的数字化转型

时下&#xff0c;智慧餐饮点餐系统正在引领着餐饮业迈向更高的位置。今天&#xff0c;小编将与大家共同探讨智慧餐饮点餐系统的发展趋势、优势以及对餐饮业的影响。 一、智慧餐饮点餐系统的发展趋势 智慧餐饮点餐系统的出现填补了这一空白&#xff0c;它通过引入数字化技术&a…

基于springboot+vue的医院资源管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

IDEA-DeBug理论与实践

文章目录 01_Debug简介和意义02_IDEA中的Debug步骤03_跳转到当前代码执行的行04_步过调试的使用05_步入调试的使用06_强制步入调试的使用07_步出调试的使用08_回退断点调试的使用09_运行到光标处10_计算表达式11_条件断点12_多线程调试 在软件开发中&#xff0c;IDEA&#xff0…

让燃油车再次破防 比亚迪汉唐荣耀双出击

相信很多读者朋友都还记得&#xff0c;就在不久前趣味科技曾经报道&#xff0c;2024龙年伊始比亚迪就打着“电比油低”的旗号&#xff0c;推出了价格仅为7.98万元起的秦PLUS、驱逐舰05荣耀版&#xff0c;向合资燃油车发起了大举进攻。 这两款“7”字头售价的车型上市&#xff0…

<网络安全>《60 概念讲解<第七课 网络模型OSI对应协议>》

1 OSI模型 OSI模型&#xff08;Open Systems Interconnection Model&#xff09;是一个由国际标准化组织&#xff08;ISO&#xff09;提出的概念模型&#xff0c;用于描述和标准化电信或计算系统的通信功能&#xff0c;以实现不同通信系统之间的互操作性。该模型将通信系统划分…