进程间通信-信号-pipe-fifo

1.运行结果


这三段代码实现了 FIFO(命名管道)的基本操作,允许进程之间进行通信。以下是对每个程序的简要说明:

fifo_creator.c:

这个程序创建了一个 FIFO 文件,它使用 mkfifo 函数在指定路径下创建了一个名为 /tmp/myfifo 的 FIFO。
• mkfifo("/tmp/myfifo", 0777):调用 mkfifo 函数创建了一个权限为 0777(八进制)的 FIFO 文件。
• 如果 mkfifo 调用成功(返回值为 0),程序输出 "FIFO created"。

fifo_reader.c:

这个程序打开了一个以只读方式打开的 FIFO,并尝试从 FIFO 中读取数据。
• open(FIFO_NAME, open_mode):使用 open 函数打开了一个以只读方式打开的 FIFO。
• 通过 read 函数尝试从 FIFO 中读取数据,直到读取完所有数据为止。
• 最后输出读取的总字节数和进程完成信息。

fifo_writer.c:

这个程序打开了一个以只写方式打开的 FIFO,并向 FIFO 中写入数据。
• mkfifo 函数用于确保 FIFO 存在,如果不存在则创建。
• open(FIFO_NAME, open_mode):使用 open 函数打开了一个以只写方式打开的 FIFO。
• 通过 write 函数向 FIFO 中写入数据,循环写入直到写入的总字节数达到设定的阈值。
• 最后输出进程完成信息。
这些程序一起展示了 FIFO 的创建、读取和写入操作,允许进程在文件系统上的路径下进行通信。你可以根据需求进行进一步的修改和扩展,比如改变读取或写入的数据内容、调整循环条件或处理数据的方式。
当涉及到使用 FIFO(命名管道)时,系统调用是其中最重要的部分。让我为你详细解释这三个程序中的系统调用部分。

fifo_creator.c:

c
int res = mkfifo("/tmp/myfifo", 0777);
• mkfifo 是一个系统调用,用于创建 FIFO 文件。
• /tmp/myfifo 是 FIFO 的路径。
• 0777 表示权限,指定了文件的权限(在这里是读写权限)。
fifo_reader.c:
c
pipe_fd = open(FIFO_NAME, open_mode);
res = read(pipe_fd, buffer, BUFFER_SIZE);
• open 系统调用以只读模式(O_RDONLY)打开 FIFO。
• read 系统调用从打开的 FIFO 文件描述符 pipe_fd 中读取数据到 buffer 中。
fifo_writer.c:
c
pipe_fd = open(FIFO_NAME, open_mode);
res = write(pipe_fd, buffer, BUFFER_SIZE);
• open 系统调用以只写模式(O_WRONLY)打开 FIFO。
• write 系统调用将 buffer 中的数据写入到打开的 FIFO 文件描述符 pipe_fd 中。
理解重要细节:
• mkfifo 创建 FIFO 文件。
• open 打开文件描述符以进行读取或写入操作。
• read 从文件描述符读取数据。
• write 将数据写入文件描述符。

Pipe.c:

这段代码实现了管道通信,关键点在于以下几个部分:

  1. 管道的创建:使用 pipe(thepipe) 创建了一个管道,它是一个包含两个文件描述符的数组 thepipe[2],分别代表管道的读端和写端。
  2. 子进程的创建:通过 pid = fork() 创建了一个子进程。在父子进程中,通过检查 pid 的值来区分当前代码在父进程还是子进程中运行。
  3. 管道的读写:
    o 父进程(pid > 0):关闭了管道的写端 close(thepipe[1]),将子进程的标准输入重定向到管道的读端 dup2(thepipe[0], 0),然后执行 av[2] 指定的命令。
    o 子进程(pid == 0):关闭了管道的读端 close(thepipe[0]),将父进程的标准输出重定向到管道的写端 dup2(thepipe[1], 1),然后执行 av[1] 指定的命令。
  4. 命令的执行:使用 execlp() 函数执行传入的命令。av[1] 和 av[2] 是作为参数传入的命令。
  5. 错误处理:使用 oops() 宏对可能出现的错误进行处理。当系统调用失败时,会输出相应的错误信息并退出程序。
    这段代码的核心思想是通过创建管道和子进程,实现了两个进程之间的通信。其中,父进程向子进程传递数据,子进程将处理结果发送回父进程。这种通信方式常用于实现管道、进程间通信等功能。

Stdinredir1.c:这段代码是一个简单的文件读取程序,它有几个关键点:

  1. 文件描述符的使用:文件描述符是程序与文件之间的桥梁。在这个例子中,程序使用了文件描述符 0 来表示标准输入(stdin),并试图关闭标准输入,然后重新打开 /etc/passwd 文件,并将其作为新的标准输入。
  2. 文件操作:
    o fgets(line, 100, stdin) 用于从标准输入读取一行内容,存储在 line 缓冲区中,并打印这一行内容。
    o close(0) 试图关闭标准输入。
    o open("/etc/passwd", O_RDONLY) 尝试以只读方式打开 /etc/passwd 文件,并将其文件描述符返回给 fd。
    o 如果成功打开 /etc/passwd 文件,则继续从新的标准输入(即 /etc/passwd 文件)读取内容,并打印到标准输出。
  3. 错误处理:程序在尝试打开文件失败时进行了简单的错误处理,输出错误信息并退出程序。
    关键点在于程序首先尝试从标准输入读取内容并打印,然后关闭了标准输入并重新打开了 /etc/passwd 文件,并试图从该文件读取内容并打印到标准输出。
    但需要指出的是,这段代码在尝试关闭标准输入后重新打开一个文件,并假定新文件的文件描述符会是 0(标准输入),这种做法可能会导致意外行为和系统错误。在实际的应用中,不建议这样使用文件描述符。

Sigactdemo.c:这段代码是一个简单的信号处理程序,关键点在于信号处理器 inthandler 的设置和信号处理的流程。

关键点解释如下:

  1. 信号处理设置:
    o struct sigaction 结构体被用来定义一个新的信号处理器 newhandler。
    o sa_handler 被设置为 inthandler 函数,表示当接收到 SIGINT 信号时,将执行 inthandler 函数。
    o sa_flags 标志被设置为 SA_RESTART|SA_NODEFER|SA_RESETHAND,分别表示在系统调用被信号中断后,自动重启系统调用、在信号处理期间阻止对同一信号的再次处理,以及在信号处理完成后重置信号处理器为默认行为。
  2. 信号集的设置:
    o sigset_t blocked 用于定义信号集 blocked。
    o sigemptyset(&blocked) 将信号集清空,然后 sigaddset(&blocked, SIGQUIT) 将 SIGQUIT 信号添加到信号集中,表示当处理 SIGINT 信号时,阻止 SIGQUIT 信号的处理。
  3. 信号处理设置生效:
    o sigaction(SIGINT, &newhandler, NULL) 用于将定义好的新信号处理器应用于 SIGINT 信号。如果设置失败,则会输出错误信息。
  4. 主循环:
    o 主循环中使用 while (1) 不断等待输入,使用 fgets() 从标准输入中读取内容,并打印所输入的内容。
  5. 信号处理器函数 inthandler:
    o inthandler 是 SIGINT 信号的处理函数。
    o 当接收到 SIGINT 信号时,会打印相关信息,然后进入休眠状态(通过 sleep(s * 4))模拟信号处理的耗时操作。
    o 处理完毕后,会再次打印相关信息表示处理完成。
    总体而言,这段代码演示了如何设置信号处理器以捕获 SIGINT 信号,并在捕获到信号时执行指定的处理函数。它也展示了如何设置特定的标志来控制信号的处理行为和阻塞其他信号的处理过程。
posted @ 2023-12-20 08:53  20211414董准  阅读(7)  评论(0编辑  收藏  举报