IPC之二:使用命名管道(FIFO)进行进程间通信的例子

IPC 是 Linux 编程中一个重要的概念,IPC 有多种方式,本文主要介绍命名管道(FIFO),命名管道可以完成同一台计算机上的进程之间的通信,本文给出了多个具体的实例,每个实例均附有完整的源代码;本文所有实例在 Ubuntu 20.04 上编译测试通过,gcc版本号为:9.4.0;本文适合 Linux 编程的初学者阅读。

1 命名管道(FIFO)的基本概念

  • FIFO(First-In First-Out),在 Linux 文件系统中是一种特殊的文件,相对于匿名管道,FIFO 又被称为命名管道;

  • 在我的另一篇文章《IPC之一:使用匿名管道进行父子进程间通信的例子》中,介绍了管道(又称匿名管道)的基本概念;

  • 匿名管道和命名管道本质上是一种东西,在内核中都是一个 inode,只是因为匿名管道在物理文件系统中没有文件故而仅能通过进程间的继承来传递这个 inode 的索引号;而命名管道因为有了物理文件系统中的文件,通过这个文件可以找到内核中相应的 inode,故而对该文件有读写权限的进程均可以使用这个管道;

  • 命名管道的工作方式与匿名管道非常相似,但有一些明显的差异:

    1. 命名管道作为一种特殊文件存在于文件系统中,匿名管道仅存在于内核中,不存在于文件系统中;
    2. 不同祖先的进程可以通过命名管道交换数据,而匿名管道只能在有共同祖先的进程间进行通信;
    3. 命名管道的生命周期可以大于使用它的进程的生命周期,也就是说,当使用命名管道交换数据的所有进程都终止后,命名管道仍然可以保留在文件系统中供以后使用;匿名管道则不同,当使用匿名管道的进程全部终止后,匿名管道也会消亡。
  • 当进程通过命名管道交换数据时,内核会在内部传递所有数据,而不将其写入文件系统;因此,表示一个命名管道的特殊文件在文件系统上没有内容;文件系统中表示命名管道的文件名仅充当参考点,以便进程可以使用文件系统中的文件名找到内核中的 inode,从而访问管道。

  • 每个 FIFO 特殊文件代表着一个命名管道,由内核进行维护,必须先打开 FIFO 两端(读和写),然后才能传递数据;一般情况下,打开 FIFO 会产生阻塞,直到另一端也打开为止,后面我们会专门讨论 FIFO 的阻塞问题;

  • 进程也可以以非阻塞模式打开 FIFO;

    • 在使用非阻塞方式打开 FIFO 时,即便没有进程打开 FIFO 的写入端,一个进程以只读方式打开 FIFO 也会成功;
    • 即便是以非阻塞方式打开 FIFO,如果没有进程打开 FIFO 的读出端,以只写方式打开 FIFO 也会失败,产生错误:No such device or address
  • 以读写方式打开 FIFO 不管是在阻塞还是非阻塞方式下都会成功,其返回的文件描述符既是写入端又是读出端,以这种方式打开的 FIFO,既可以做写入端使用,也可以做读出端使用,但通常只能使用其一端(要么写入要么读出)。

2 在 shell 下建立一个命名管道(FIFO)

  • 有多种方法可以创建命名管道,其中下面两种方法可以直接在 shell 中创建命名管道;

  • 使用 mknod 命令建立命名管道

    mknod myfifo p
    
    • mknod 命令用于创建一个特殊文件,命令最后的参数 “p”,表示建立一个 FIFO 特殊文件,这个参数还可以是 b、c、u,分别表示其它的特殊文件;

    • 可以使用在线手册 man mknod 了解 mknod 命令的详细信息;

    • 使用 ls -l myfifo 可以查看我们刚刚创建的 FIFO,文件权限最前面的 “p”,表示这个文件是个命名管道 FIFO;

      Screenshot for ls fifo

    • 使用 mknod 创建 FIFO 时,可以使用参数 -m 权限 来设置权限,比如:mknod -m 0644 myfifo p 命令,创建的 FIFO 只有拥有者可读写,其它用户只读;

  • 使用 mkfifo 命令建立命名管道

    mkfifo myfifo
    
    • mkfifo 命令用于创建一个 FIFO 特殊文件;
    • 可以使用在线手册 man mkfifo 了解 mkfifo 命令的详细信息;
    • 使用 mkfifo 创建 FIFO 时,可以像 mknod 命令一样使用参数 -m 权限 来设置权限,比如:mkfifo -m 0666 myfifo 命令,创建一个 FIFO,所有用户可读写;
  • mknodmkfifo 创建的 FIFO 可以用 chmod 修改权限

    mkfifo -m 0644 myfifo
    chmod a=rw myfifo
    
    • mkfifo 创建了一个 FIFO,chmod 将其权限改为所有用户可读写。
  • mknodmkfifo 创建的 FIFO 可以用 rm 删除

    rm myfifo
    

3 使用C语言创建命名管道

  • 使用系统调用 mknod() 创建命名管道

    原型:#include <sys/types.h>
         #include <sys/stat.h>
         #include <fcntl.h>
         #include <unistd.h>
    
         int mknod(const char *pathname, mode_t mode, dev_t dev);
    说明:mknod() 可以在文件系统上建立一个文件节点(普通文件、特殊文件、命名管道)
    返回:调用成功返回 0
         调用失败返回 -1
         errno = EFAULT (pathname invalid)
                 EACCES (permission denied)
                 ENAMETOOLONG (pathname too long)
                 ENOENT (invalid pathname)
                 ENOTDIR (invalid pathname)
                 (其它错误码请查看 man 手册)
    
    • pathname 是文件路径不用多说

    • mode 是文件类型和文件权限,比如:S_IFIFO | 0666 表示建立一个 FIFO 特殊文件,权限为 0666 (所有用户可读写)

    • dev 是设备号,只有当文件类型为 S_IFCHR 或 S_IFBLK 时,才有设备号,其他文件类型填 0 即可;

    • 在线手册 man 2 mknod 可以查询该系统调用的详细信息

    • 下面的调用创建了一个 FIFO 文件:/tmp/myfifo,权限为:0666 (所有用户可读写)

      mknod("/tmp/myfifo", S_IFIFO | 0666, 0);
      
    • 但实际上设置的文件权限还要受到 umask 的影响,最终的文件权限是 0666 & ~umask

    • 可以使用 shell 命令 umask 查看当前的 umask

      Screenshot of umask

    • 为了保证创建的 FIFO 文件的权限,可以在调用 mknod() 前临时删除 umask

      umask(0);
      mknod("/tmp/myfifo", S_IFIFO|0666, 0);
      
  • 使用 mknodat() 创建命名管道

    原型:#include <fcntl.h>           /* Definition of AT_* constants */
         #include <sys/stat.h>
    
         int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);
    
    • mknod() 相比,这个系统调用多了一个参数 dirfddirfd 是文件系统中一个打开的目录的文件描述符;
    • 当 pathname 为绝对路径时,参数 dirfd 被忽略,该调用与 mknod() 完全一样;
    • 当 pathname 为相对路径时,它是相对于 dirfd 所引用的目录,而不是相对于调用进程的当前工作目录;
    • mknod() 中的 pathname 也是可以使用相对路径的,但是相对于调用进程时的当前目录;
    • 下面代码使用 mknodat() 创建了一个 FIFO 文件:
      int dirfd = open("/tmp", O_RDONLY);
      mknodat(dirfd, "./myfifo", S_IFIFO|0666, 0); 
      
  • 使用系统调用 mkfifo() 创建命名管道

    原型:#include <sys/types.h>
         #include <sys/stat.h>
    
         int mkfifo(const char *pathname, mode_t mode);    
    
    • 毫无疑问,mkfifo() 就是专门用来创建 FIFO 文件的,pathname 为 FIFO 文件路径,mode 为文件权限,当然这个权限还要受到 umask 的影响,请参考前面的说明。
  • 使用系统调用 mkfifoat() 创建命名管道

    #include <fcntl.h>           /* Definition of AT_* constants */
    #include <sys/stat.h>
    
    int mkfifoat(int dirfd, const char *pathname, mode_t mode);    
    
    • mkfifoat()mkfifo() 的关系与 mknodat()mknod() 的关系一样,请参考 mknodat() 的说明

4 命名管道(FIFO)的实例

  • 在命名管道上的 I/O 操作与匿名管道是一样的,使用 read() 从管道中读出数据,使用 write() 向管道中写入数据,不能使用 lseek() 等;

  • 有一个明显的区别是在对命名管道进行 I/O 操作之前,必须用 open() 打开 FIFO 文件,这在匿名管道上是不需要的,因为匿名管道仅存在于内核中,并不存在于物理的文件系统中,而命名管道是存在于物理文件系统中的;

  • 由于 FIFO 文件存在于文件系统中,所以,对命名管道也可以使用流式文件的 I/O 操作,即:

    • fopen() 打开 FIFO 文件
    • 使用 fgetc()/fputc()、fgets()/fputs() 进行读写操作;或者
    • 使用 fscanf()/fprintf() 进行读写操作;或者
    • 使用 fread()/fwrite() 进行读写操作;
    • fclose() 关闭 FIFO 文件
  • 下面是一个使用 FIFO 传递消息的实例,分为两个独立的程序

    • 服务端源程序:fifo-server.c(点击文件名下载源程序),从 FIFO 上接收数据
    • 客户端源程序:fifo-client.c(点击文件名下载源程序),向 FIFO 中写入消息
    • 这个实例中使用 fopen() 打开 FIFO,客户端使用 fputs() 向 FIFO 中写入数据,服务端使用 fgets() 从 FIFO 中读出数据,使用 fclose() 关闭 FIFO;
    • 也可以使用 open()/write()/read()/close() 这组系统调用来进行 FIFO 的操作;
    • 这个实例使用 mknod() 创建 FIFO,当然也可以使用 mkfifo() 创建 FIFO;
    • 其实这个实例中也可以不使用 fifo-client 这个程序,我们可以在 shell 下使用 echo "Hello World!">myfifo 来代替 fifo-client 完成向 FIFO 发送信息的功能;
    • fifo-client 程序演示了使用流式文件向 FIFO 中写入数据的方法,特别要注意的是程序最后的 fflush(),在本例中,fflush() 并不是必须的,因为紧接着就使用了 fclose(),但在很多情况下,如果不使用 fflush(),数据会被缓存起来,不会立即发送出去。
  • FIFO 这种特殊文件有些地方确实特殊:

    • 从 FIFO 中读数据的进程在打开 FIFO 时会阻塞,直到有一个向这个 FIFO 中写数据的进程打开 FIFO;
    • 向 FIFO 中写数据的进程在打开 FIFO 时会阻塞,直到有一个从这个 FIFO 中读数据的进程打开 FIFO;
    • 进程从 FIFO 中读数据时会阻塞,直到有进程向 FIFO 中写入数据;
    • 向一个没有读出端的 FIFO 中写入数据时,会产生错误;

      这种情况通常发生在 FIFO 两端正常打开后,读出端关闭,导致管道没有读出端

  • 编译运行

    • 编译
      gcc -Wall fifo-server.c -o fifo-server
      gcc -Wall fifo-client.c -o fifo-client
      
    • 这个实例需要在两个终端中运行,一个终端中运行 ./fifo-server;另一个终端中运行 ./fifo-client "Hello world!"
    • 初次运行时,要先运行 ./fifo-server 再运行 ./fifo-client,因为 FIFO 文件是在 fifo-server 程序中创建的;
    • fifo-server 不会自行退出,需要在键盘上输入 ctrl+c 才能退出;
    • fifo-client 可以在 shell 下使用命令:echo "Hello world!">myfifo 来代替。
  • fifo-server 的运行截图:

    Screen of fifo-server


5 命名管道(FIFO)的阻塞机制

  • 打开 FIFO 有三种方式:只读方式、只写方式和读写方式

  • 使用阻塞方式(没有 O_NONBLOCK 标志)打开 FIFO

    • 以只读方式(O_RDONLY)打开 FIFO 的读出端会发生阻塞,直至 FIFO 写入端被其它进程打开;
    • 以只写方式(O_WRONLY)打开 FIFO 的写入端会发生阻塞,直至 FIFO 读出端被其它进程打开;
    • 以读写方式(O_RDWR)方式打开 FIFO 会直接返回成功,因为打开的 FIFO 描述符既可作读出端,也可以作写入端,相当于打开了 FIFO 的两端;
    • 以只读方式(O_RDONLY)成功打开的 FIFO,在读出数据时:
      • 如果写入端打开,则发生阻塞,直到写入端将数据写入 FIFO 后,返回读出的数据长度(字符数);
      • 如果写入端关闭,则立即返回 EOF(读出数据长度为 0);
    • 以只写方式(O_WRONLY)成功打开的 FIFO,向 FIFO 写入数据时:
      • 如果读出端打开,则会直接返回成功,读出端可以正常读出数据;
      • 如果读出端关闭,则出现错误,并产生 SIGPIPE 信号。
  • 使用非阻塞方式(设置 O_NONBLOCK 标志)打开 FIFO

    • 以只读方式(O_RDONLY)打开 FIFO 时不会阻塞,返回成功;
    • 以只写方式(O_WRONLY)打开 FIFO 时不会阻塞:
      • 如果 FIFO 的读出端没有打开,直接返回失败;
      • 如果 FIFO 的读出端已经打开,直接返回成功
    • 从以只读方式(O_RDONLY)打开的 FIFO 中读取数据不会阻塞:
      • FIFO 的写入端已打开,但 FIFO 中没有数据时,会产生错误:Resource temporarily unavailable
      • FIFO 的写入端已打开,且 FIFO 中有数据时,返回读出数据的长度(字节数);
      • 当 FIFO 写入端关闭时,返回 EOF(读出数据长度为 0)。
    • 向以只写方式(O_WRONLY)打开的 FIFO 写入数据时不会阻塞,立即返回:
      • 当 FIFO 读出端关闭时,写入数据时出错,并产生 SIGPIPE 信号;
      • 当 FIFO 读出端打开时,写入成功,写入的数据可以被读出端正常读出。
  • 这种教条式的说明其实很枯燥,建议读者编写一些测试程序来体会上面的“教条”。

6 SIGPIPE 信号和 EOF

  • 在上一节的“教条”中,我们提出过两个要点:

    1. 当一个向 FIFO 写入数据的进程将写入端关闭时,正在等待从 FIFO 中读取数据进程会收到一个 EOF;
    2. 当一个从 FIFO 读出数据的进程将读出端关闭时,向 FIFO 中写入数据的进程在写入数据时系统会发出一个 SIGPIPE 信号。
  • 这一节专门讨论与 FIFO 有关的 SIGPIPE 信号和 EOF(End Of File);

  • 在 Linux 的信号集有一个 SIGPIPE 信号是和 FIFO 相关的;

  • 只有在向 FIFO 写入数据时才会产生 SIGPIPE 信号;也就是说,虽然读出端关闭,但如果不向 FIFO 中写入数据,也不会产生 SIGPIPE 信号;

  • 写入数据时,write() 也会返回错误,所以,通常情况下并不一定要捕捉 SIGPIPE 信号;

  • 源程序:fifo-sigpipe.c(点击文件名下载源程序)演示了在向 FIFO 写入数据时,如何截获 SIGPIPE 信号;

    • 编译:gcc -Wall fifo-sigpipe.c -o fifo-sigpipe
    • 运行这个程序需要两个终端窗口,在第一个终端上运行:./fifo-sigpipe,程序运行后将被阻塞在 open() 上,在第二个终端上运行:cat myfifo,来模拟从 FIFO 中读取数据;
    • 我们可以看到第一个终端中由 fifo-sigpipe 每 5 秒一次发出的信息可以在第二个终端上收到并显示出来,此时我们在第二个窗口中输入 ctrl+c 终止 cat 的运行,则在第一个窗口中可以看到截获到的 SIGPIPE 信号;
    • ./fifo-sigpipe 是 FIFO 的写入端,cat fifo-sigpipe 是 FIFO 的读出端,终止读出端,然后再次运行 cat fifo-sigpipe,可以继续收到 fifo-sigpipe 发出的信息。
  • EOF 是读文件时常用的判断文件结束的方法,在 FIFO 上表示写入端被关闭:

    • 以阻塞方式打开 FIFO 进行读操作时,EOF 表示写入端已被关闭;
    • 以阻塞方式打开 FIFO 进行读操作时,如果写入端打开但 FIFO 中没有数据,则会产生阻塞;
    • 以非阻塞方式打开 FIFO 时,写入端关闭时,读出端会返回 EOF(读出数据长度为 0);
    • 以非阻塞方式打开 FIFO 时,写入端打开但 FIFO 中没有数据时,读出端不会返回 EOF,会产生错误:Resource temporarily unavailable
  • 源程序:fifo-eof.c(点击文件名下载源程序)演示了在从 FIFO 中读数据时,如何截获 EOF;

    • 编译:gcc -Wall fifo-eof.c -o fifo-eof
    • 运行这个程序需要两个终端窗口,在第一个终端上运行:./fifo-eof,程序运行后将被阻塞在 open() 上,在第二个终端上运行:echo "Hello world">myfifo,来模拟向 FIFO 写入数据;
    • 当第二个终端的命令启动后,第一个终端上的 fifo-eof 程序会收到第二个终端的命令发来的数据,然后,第二个终端命令执行完毕退出,相当于关闭了 FIFO 的写入端,此时,可以在第一个终端的 fifo-eof 程序上看到捕捉到的 EOF;
    • ./fifo-eof 是 FIFO 的读出端,echo "Hello world">myfifo 是 FIFO 的写入端,终止写入端,然后再次运行 echo "Hello world">myfifofifo-eof 可以再次从 FIFO 中收到信息;
    • 不管在打开 FIFO 时是阻塞状态还是非阻塞状态,当 FIFO 的写入端关闭时,读出端都会收到 EOF。

7 使用流式文件操作 FIFO 的一些差异

  • 使用流式文件的操作函数(fopen()/fread()/fwrite()/fclose()等)是可以操作 FIFO 的,这个在前面的实例中已经有演示,但是与低级文件I/O的系统调用比是有一些差异的,本节将讨论已经发现的一些差异;
  • 使用流式文件的方式从 FIFO 中读出数据时,如果遇到 EOF,必须要关闭 FIFO,然后再次打开,才能继续从 FIFO 中读取数据;
    • fifo-server.c 这个实例中,演示了流式文件方式从 FIFO 中读取数据时,遇到 EOF 需要再次打开 FIFO 的过程;
    • 读者可以尝试修改这个程序,在遇到 EOF 后不关闭 FIFO,继续读取数据,是读不出数据的;
    • 但是使用低级文件 I/O (open()/read()/write()/close())操作 FIFO,在遇到 EOF 时,则不需要关闭 FIFO;
    • fifo-eof.c 这个实例中,演示了使用低级文件 I/O 从 FIFO 中读取数据时,遇到 EOF 无需关闭 FIFO 的过程;
  • 当使用流式文件的方式向 FIFO 中写入数据时,因为流式文件缓存的原因,写入的数据可能不会马上进入到 FIFO 中;
    • 如果希望写入的数据立即进入 FIFO 的话,应该在调用写入函数(fputs()/fwrite()等)之后,立即调用 fflush(),该函数的意义在于强制将缓冲区中的数据写入到指定的流式文件中;
    • 使用低级文件 I/O 向 FIFO 中写入数据则没有这个问题;
  • 当使用流式文件的方式向 FIFO 中写入数据时,如果 FIFO 的读出端关闭,写入函数仍然会返回成功;
    • 尽管函数调用返回成功,但向 FIFO 写入的数据会被忽略,再次打开的读出端无法读出这些数据;
    • 和使用低级文件 I/O 写入 FIFO 时一样,会捕捉到一个 SIGPIPE 信号,所以使用流式文件的方式向 FIFO 写入数据时,要靠捕捉 SIGPIPE 信号来判断写入失败;
    • 使用低级文件 I/O 写入 FIFO 时,如果 FIFO 读出端已关闭,写入函数(write())会报告错误,这使得我们可以考虑不去捕捉 SIGPIPE 信号。

8 后记

  • 本文涉及的所有观点均编有测试程序进行测试,限于篇幅,不能都列在文章中;
  • 以本文提供的四个范例已经足够衍生出很多的测试程序:
    • fifo-server.c - 是使用流式文件的方式从 FIFO 中读数据的,可以尝试将 fopen()/fclose() 放在循环外面,可以验证使用流式文件的方式读取 FIFO 时遇到 EOF 需要重新打开 FIFO 的观点;
    • fifo-server.c - 可以将这个程序改成使用低级文件 I/O 读取 FIFO 的方式,以比较流式文件的操作函数和低级文件 I/O 的操作函数之间的差异;
    • fifo-client.c - 可以加一个循环,使程序每隔 5 秒向 FIFO 写入一次数据,同时去掉 fflush(),可以验证流式文件的缓存对 FIFO 写入的影响;
    • fifo-client.c - 可以将其改成使用低级文件 I/O 写入 FIFO 的方式,以比较流式文件的操作函数和低级文件 I/O 的操作函数之间的差异;
    • fifo-sigpipe.c - 可以将其改为使用流式文件方式向 FIFO 写入数据,验证一下在读出端关闭时,fputs() 仍然返回成功的情况,同时体会一下如何在流式文件方式下捕捉 SIGPIPE 信号;
  • 本质上说,命名管道和匿名管道在内核中的实现基本是一样的,所以,命名管道其实也是半双工的,要建立一个全双工的命名管道只需建立两条管道即可;可以参考我的另一篇介绍匿名管道的文章《IPC之一:使用匿名管道进行父子进程间通信的例子》
  • 命名管道如果不从文件系统中删除,会一直存在下去,这点和匿名管道有很大的区别,删除一个命名管道和删除一个普通文件无异;
  • 为了让所有进程都可以访问到建立的命名管道,通常会把一个命名管道建在 /tmp/ 下,好处有两点:
    1. 这个目录的权限是 0777,所有的用户可进行读写;
    2. 这个目录是一个内存文件系统,并不在物理磁盘上,所以重新启动后你建立的命名管道也会消失,减少了维护。
  • 与匿名管道一样,Linux 下命名管道的缓冲区长度也是有限制的,最大长度为 4096 字节,定义在头文件:linux/limits.h 中:
    #define PIPE_BUF        4096	/* # bytes in atomic write to a pipe */
    
  • 向 FIFO 中写入数据的长度不超过这个阈值,将是一个原子操作。

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

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

相关文章

Pytest测试框架搭建的关键6个知识点(建议收藏)

在现代软件开发中&#xff0c;测试是确保代码质量和功能稳定性的关键步骤。而Pytest作为一个功能强大且易于使用的Python测试框架&#xff0c;为我们提供了一个优雅的方式来编写和管理测试。本文将为你介绍如何构建高效可靠的测试环境&#xff0c;着重探讨Pytest测试框架搭建时…

java 版本企业招标投标管理系统源码+多个行业+tbms+及时准确+全程电子化tbms

​ 功能描述 1、门户管理&#xff1a;所有用户可在门户页面查看所有的公告信息及相关的通知信息。主要板块包含&#xff1a;招标公告、非招标公告、系统通知、政策法规。 2、立项管理&#xff1a;企业用户可对需要采购的项目进行立项申请&#xff0c;并提交审批&#xff0c;查…

数据结构—树和二叉树

5.树和二叉树 5.1树和二叉树的定义 树形结构&#xff08;非线性结构&#xff09;&#xff1a;结点之间有分支&#xff0c;具有层次关系。 5.1.1树的定义 树&#xff08;Tree&#xff09;是n&#xff08;n≥0&#xff09;个结点的有限集。 若n0&#xff0c;称为空树&#x…

文件传输软件的市场现状和未来趋势

文件传输软件是一种能够在不同计算机之间高效、便捷、安全地传送各种类型的文件的应用软件。它是计算机领域中的一项重要技术&#xff0c;涉及到网络通信、数据加密、文件管理等多个方面。随着互联网和移动互联网的发展&#xff0c;文件传输软件的市场需求也日益增大&#xff0…

Linux 中使用 verdaccio 搭建私有npm 服务器

安装 Node Linux中安装Node 安装verdaccio npm i -g verdaccio安装完成 输入verdaccio,出现下面信息代表安装成功&#xff0c;同时输入verdaccio后verdaccio已经处于运行状态&#xff0c;当然这种启动时暂时的&#xff0c;我们需要通过pm2让verdaccio服务常驻 ygiZ2zec61wsg…

iPhone苹果手机地震预警功能怎么开启?

iPhone苹果手机地震预警功能怎么开启&#xff1f; 1、打开iPhone苹果手机设置&#xff1b; 2、在iPhone苹果手机设置内找到辅助功能&#xff1b; 3、在辅助功能内找到触控&#xff1b; 4、在iPhone苹果手机辅助功能触控内找到振动&#xff0c;如果是关闭状态请启&#xff1b; …

看门狗文章

1. iwdg.c #include "stm32f4xx.h" #include "iwdg.h"//prer&#xff1a;预分频值 //rlr&#xff1a;自动重装载值 void IWDG_Init(unsigned char prer,unsigned int rlr)//IWDG初始化 {IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);…

你知道音频文件格式转换要用什么软件吗?今天就来分享给你

你是否曾经遇到过这样的情况&#xff1f;你正在享受着一首心爱的歌曲&#xff0c;却突然发现它的音频格式不兼容你的设备或播放器&#xff1f;或者你需要将录音文件从一种格式转换成另一种&#xff0c;以便在不同场景中使用&#xff1f;音频格式转换软件就像是一个通向音乐自由…

林大数据结构【2019】

关键字&#xff1a; 哈夫曼树权值最小、哈夫曼编码、邻接矩阵时间复杂度、二叉树后序遍历、二叉排序树最差时间复杂度、非连通无向图顶点数&#xff08;完全图&#xff09;、带双亲的孩子链表、平衡二叉树调整、AOE网关键路径 一、判断 二、单选 三、填空 四、应用题 五、算…

Windows搭建Snort环境及使用方式

目录 0x01 前置环境0x02修改配置文件0x03 自测0x04 使用0x05 感言 0x01 前置环境 环境描述windows10snort2.9.2https://www.snort.org/downloads 先把上面环境下载好&#xff01; 需要注意的是安装npcap这个软件 0x02修改配置文件 软件安装目录&#xff1a;C:/Snort/ 配置文…

视频添加字幕

1、依靠ffmpeg 命令 package zimu;import java.io.IOException;public class TestSrt {public static void main(String[] args) {String videoFile "/test/test1.mp4";String subtitleFile "/test/test1.SRT";String outputFile "/test/testout13…

dy六神参数记录分析(立秋篇)

version&#xff1a; 23.9 X-SSSTUB: 搜索&#xff1a;x-tt-dt var hashMap Java.use("java.util.HashMap");hashMap.put.implementation function (a, b) {console.log("hashMap.put: ", a, b);return this.put(a, b);}https://codeooo.blog.csdn.n…

河北泛域名https证书可以保护几个域名

什么是泛域名https证书呢&#xff1f;在众多https证书产品中总有几种特别的https证书——泛域名https证书、多域名https证书。通常一张https证书只能保护一个站点&#xff0c;如果想保护多个站点&#xff0c;只能一次给各个站点购买https证书&#xff0c;这种做法虽然解决了问题…

华为云Classroom赋能—TooKit助力开发者上云

对于资深程序员而言&#xff0c;IDE是必不可少的&#xff0c;它好比是剑客手中的宝剑&#xff0c;IDE帮助程序员更快更丝滑的去编程&#xff0c;同时插件就是这把剑上的各种Buff&#xff0c;为宝剑赋能&#xff0c;提供更好的升级打怪体验。 什么是Huawei Cloud Toolkit Huaw…

STDF - 基于 Svelte 和 Tailwind CSS 打造的移动 web UI 组件库,Svelte 生态里不可多得的优秀项目

Svelte 是一个新兴的前端框架&#xff0c;组件库不多&#xff0c;今天介绍一款 Svelte 移动端的组件库。 关于 STDF STDF 是一个移动端的 UI 组件库&#xff0c;主要用来开发移动端 web 应用。和我之前介绍的很多 Vue 组件库不一样&#xff0c;STDF 是基于近来新晋 js 框架 S…

MySQL之深入InnoDB存储引擎——redo日志

文章目录 一、为什么需要redo日志二、redo日志的类型1&#xff09;简单的redo日志类型2&#xff09;复杂的redo日志类型 三、Mini-Transaction四、redo日志的写入过程五、redo日志文件1、刷盘时机2、redo日志文件组 六、log sequence number1、lsn的引入2、flushed_to_disk_lsn…

生活小妙招之UE custom Decal

因为这几年大部分时间都在搞美术&#xff0c;所以博客相关的可能会鸽的比较多&#xff0c;阿巴阿巴 https://twitter.com/Tuatara_Games/status/1674034744084905986 之前正好看到一个贴花相关的小技巧&#xff0c;正好做一个记录&#xff0c;也在这个的基础上做一些小的拓展…

GATK BaseRecalibratorSpark 过程中因Too many open files终止

Error&#xff1a; GATK BaseRecalibratorSpark 过程中因Too many open files终止 执行命令&#xff1a; nohup time ./gatk --java-options "-Xmx16G" BaseRecalibratorSpark -R ../../alignment/hg38/hg38.fa -I ../../alignment/bam/P368T.sorted.markdup.bam …

【Ubuntu】Ubuntu 22.04 升级 OpenSSH 9.3p2 修复CVE-2023-38408

升级原因 近日Openssh暴露出一个安全漏洞CVE-2023-38408&#xff0c;以下是相关资讯&#xff1a; 一、漏洞详情 OpenSSH是一个用于安全远程登录和文件传输的开源软件套件。它提供了一系列的客户端和服务器程序&#xff0c;包括 ssh、scp、sftp等&#xff0c;用于在网络上进行…

[C++项目] Boost文档 站内搜索引擎(5): cpphttplib实现网络服务、html页面实现、服务器部署...

在前四篇文章中, 我们实现了从文档文件的清理 到 搜索的所有内容: 项目背景: &#x1fae6;[C项目] Boost文档 站内搜索引擎(1): 项目背景介绍、相关技术栈、相关概念介绍…文档解析、处理模块parser的实现: &#x1fae6;[C项目] Boost文档 站内搜索引擎(2): 文档文本解析模块…