1、IPC
IPC:是指进程间通信(Inter Process Cnmunication)。进程间相互通信的方式主要有以下6种:
(1)管道(pipe)和有名管道(FIFO)。
(2)信号(signal)
(3)消息队列
(4)共享内存
(5)信号量
(6)套接字(socket)
2、进行进程间通信的目的
(1)数据传输:一个进程需要将它的数据发送给另一个进程。
(2)资源共享:多个进程之间共享同样的资源。
(3)通知事件:一个进程需要向另一个或一组进程发送消息,通知它们发生了某种事件。
(4)进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时进程希望能够拦截另一个进程的所有操作,并能够及时知道它的状态改变。
3、管道通信
管道是单向的、先进先出的,它把一个进程的输出和另一个进程的输入连接在一起。一个进程(写进程)在管道的尾部写入数据,另一个进程(读进程)从管道的头部读出数据。
4、管道创建
管道包括无名管道和有名管道两种,前者用于父进程和子进程之间的通信;后者用于统一系统的任意两个进程间的通信。
(1) 无名管道由pipe()函数创建:
#include <unistd.h>
int pipe(int fd[2]);
当一个管道建立时,它会创建两个文件描述符:
fd[0]用于读管道,fd[1]用于写管道。
(2)命名管道由mkfifo()函数创建:
#include <sys/stat.h>
int mkfifo(const char *path, mode_t mode);
int mkfifoat(int fd, const char *path, mode_t mode);
mkfifo() 中 path 需要指定为文件的绝对路径。
nkfifoat() 当 fd 为 AT_FDCWD时,则路径名以当前目录开始。
mode 创建一个命名管道时的属性。
一旦创建了FIFO,就可以用 open 打开它,一般的文件访问函数(read、write、close等)都可用于FIFO。
当 open 一个FIFO时,非阻塞标志(O_NONBLOCK)会产生以下影响。
1、没有使用O_NONBLOCK:访问要求无法满足要求时进程将阻塞,如试图读取空FIFO时,将导致进程阻塞。
2、使用O_NONBLOCK:访问要求无法满足时不阻塞,立刻出错返回,errno 是 ENXIO
5、管道关闭
关闭管道只需要将文件描述符关闭即可,可以使用普通的close()函数逐个关闭。
6、管道通信demo
(1)无名管道
demo:
#include <apue.h>
int main(int argc, const char *argv[])
{
int fd[2];
pid_t pid;
int n;
char line[MAXLINE];
/* 创建管道 */
if (pipe(fd) < 0)
err_sys("pipe error");
/* 创建子进程 */
if ((pid = fork()) < 0)
err_sys("fork error");
else if (pid > 0){ //父进程
close(fd[0]);
write(fd[1], "Hello World\n", 12);
close(fd[1]);
waitpid(pid, NULL, 0); //等待子进程退出
exit(0);
}
else{ //子进程
close(fd[1]);
sleep(1); //先让父进程有时间写数据
n = read(fd[0], line, MAXLINE);
write(STDOUT_FILENO, line, n);
close(fd[0]);
exit(0);
}
return 0;
}
注意:系统必须先调用pipe()再调用fork(),不然会产生两个进程,子进程也不会继承文件描述符!
(2)命名管道通信demo
创建两个进程,一个为写进程,另一个为读进程。
/**************/
/* 读进程 */
/*************/
#include <apue.h>
#include <fcntl.h>
#define FIFO "/tmp/myfifo"
int main(int argc, char *argv[])
{
char buf_rd[100];
int fd;
int bytes_rd;
/* 创建管道 */
if ((mkfifo(FIFO, O_CREAT | O_EXCL) < 0) && (errno != EEXIST))
printf("Can't create fifo\n");
printf("Preparing for reading bytes...\n");
memset(buf_rd, 0, sizeof(buf_rd));
/* 打开管道 */
fd = open(FIFO, O_RDONLY | O_NONBLOCK);
if (fd == -1){
perror("Open fifo error");
exit(10);
}
while(1){
memset(buf_rd, 0, sizeof(buf_rd));
if (bytes_rd = read(fd, buf_rd, 100) == -1)
if (errno == EAGAIN)
printf("No data yet\n");
printf("Read %s from FIFO\n", buf_rd);
sleep(1);
}
}
/**************/
/* 写进程 */
/*************/
#include <apue.h>
#include <fcntl.h>
#define FIFO_SERVICE "/tmp/myfifo"
int main(int argc, char *argv[])
{
char buf_wr[100];
int bytes_wr;
int fd;
int i;
if (argc == 1){
printf("Please send something\n");
printf("Usage : ./a.out string ...\n");
exit(1);
}
for (i = 1; i < argc; i++){
strcat(buf_wr, " ");
strcat(buf_wr, argv[i]);
}
fd = open(FIFO_SERVICE, O_WRONLY | O_NONBLOCK);
if (fd == -1){
perror("Open FIFO error");
exit(10);
}
if ((bytes_wr = write(fd, buf_wr, 100)) == -1){
if (errno == EAGAIN)
printf("The FIFO has been read yet, Please try agian\n");
}
else
printf("Write%s to FIFO\n", buf_wr);
}