1. 进程间通信(IPC)介绍

1.1 进程通信的几种方式

snipaste_20181130_164140.png
1547823900813.png

1.2 进程通信目的

  • 数据传输:一个进程需要将它的数据发送给另一进程
  • 资源共享.多个进程之间共享同样的资源。
  • 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进
    程终上时要通知父进程)。
  • 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),北时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。

2 信号处理

语雀内容

3 管道

管道只能在具有公共祖先的两个进程间使用,通常,一个管道由一个进程创建,在进程fork之后,父子进程可以共用这个管道。

3.1 管道函数

pipe

函数定义:int pipe(int pipefd[2]);
功能: 创建一个普通管道
返回值: 成功返回0,失败返回-1
参数:

  • pipefd[0]为读打开,用于输出
  • pipefd[1]为写打开,用于输入

imgclip.png

popen

函数定义:FILE *popen(const char *command, const char *type);
功能: 先fork一个子进程,然后调用exec执行command
返回值: 成功返回文件指针,失败返回-1。
参数:

  • command: 要执行的命令
  • type: 根据type不同,文件指针指向标准输出或标准输入

    pclose

    函数定义:int pclose(FILE *stream);
    功能: 关闭popen创建的管道,等待命令结束
    返回值: 成功返回shell中止状态,失败返回-1。
    参数:

  • stream: 指向管道的文件指针

3.2 代码示例

pipe

代码示例:

  1. #include "apue.h"
  2. int main(void)
  3. {
  4. int n;
  5. int fd[2];
  6. pid_t pid;
  7. char line[MAXLINE];
  8. if (pipe(fd) < 0)
  9. err_sys("pipe error");
  10. if ((pid = fork()) < 0) {
  11. err_sys("fork error");
  12. } else if (pid > 0) { /* parent */
  13. close(fd[0]);
  14. write(fd[1], "hello world\n", 12);
  15. } else { /* child */
  16. close(fd[1]);
  17. n = read(fd[0], line, MAXLINE);
  18. write(STDOUT_FILENO, line, n);
  19. }
  20. exit(0);
  21. }

popen

  1. #include "apue.h"
  2. #include <sys/wait.h>
  3. int
  4. main(void)
  5. {
  6. char line[MAXLINE];
  7. FILE *fpin;
  8. if ((fpin = popen("myuclc", "r")) == NULL)
  9. err_sys("popen error");
  10. for ( ; ; ) {
  11. fputs("prompt> ", stdout);
  12. fflush(stdout);
  13. if (fgets(line, MAXLINE, fpin) == NULL) /* read from pipe */
  14. break;
  15. if (fputs(line, stdout) == EOF)
  16. err_sys("fputs error to pipe");
  17. }
  18. if (pclose(fpin) == -1)
  19. err_sys("pclose error");
  20. putchar('\n');
  21. exit(0);
  22. }

4 FIFO命名管道

未命名的管道只能在有共同祖先进程的两个进程之间使用。通过FIFO,不相关的进程也能交换数据。创建FIFO类似于创建文件,路径存在于文件系统中。

4.1 FIFO函数

mkfifo

函数定义:int mkfifo(const char *pathname, mode_t mode);
功能: 创建一个命名管道
返回值: 成功返回0,失败返回-1
参数:

  • pathname:管道文件路径
  • mode:文件权限,和不同文件一样参数

    mkfifoat

    函数定义:int mkfifoat(int dirfd, const char *pathname, mode_t mode);
    功能: 在某个文件描述符指向的目录下创建一个命名管道
    返回值: 成功返回0,失败返回-1
    参数:

  • dirfd:

  • pathname:管道文件名
  • mode:文件权限

    打开管道读写

    FIFO管道是使用open打开(和打开普通文件一样),使用write和read读写。当打开FIFO是,O_NONBLOCK标志会产生如下影响:

  • 未指定O_NONBLOCK,只读open会阻塞到某个进程为写打开该管道为止。只写open会阻塞到某个进程为读而打开管道为止

  • 指定O_NONBLOCK, 只读open立刻返回,不会阻塞。如果没有读FIFO存在,只写open会返回-1, errno为ENXIO

    4.2 FIFO用途

    FIFO有以下两种用途:

  • shell命令使用FIFO将数据从一条管道传送到另一条管道,无需创建中间临时文件

  • CS架构中,FIFO用作汇聚点,在客户端和服务器进程间传递数据

imgclip_1.png