1.无名管道
无名管道是一种特殊的IPC(进程间通信)机制,它可以在Linux系统中用于将一个进程的输出连接到另一个进程的输入。以下是使用无名管道的一般步骤:
-
创建管道:
bashint pipefd[2]; pipe(pipefd);
这将创建一个管道,并返回两个文件描述符。
pipefd[0]
用于读取管道的数据,pipefd[1]
用于写入管道的数据。 -
创建子进程:
bashpid_t pid = fork();
fork()
系统调用将创建一个子进程,该子进程将继承父进程的文件描述符。 -
在子进程中关闭读端或写端:
bashif (pid == 0) { close(pipefd[0]); //关闭读端(子进程只写入管道) // 执行需要发送数据的命令,并将输出写入管道 write(pipefd[1], data, strlen(data)); close(pipefd[1]); //关闭写端 exit(0); }
在父进程中关闭读端或写端:
bash
if (pid > 0) {
close(pipefd[1]); //关闭写端(父进程只读取管道数据)
//从管道读取数据并进行处理
read(pipefd[0], buffer, sizeof(buffer));
close(pipefd[0]); //关闭读端
}
等待子进程结束:
5.
bash
wait(NULL);
通过以上步骤,你可以在两个进程之间使用无名管道进行通信。注意,在使用管道时需要适当处理文件描述符的关闭,以避免资源泄漏和错误。
2.有名管道
在现代操作系统中,进程间通信(IPC)是一个至关重要的功能,它允许运行在同一台计算机上的不同进程之间进行数据交换。有名管道(FIFO)是实现IPC的一种方式,它提供了一种在不同进程间传输数据的机制。
有名管道与无名管道(PIPE)相比,最大的区别在于它们可以在没有亲缘关系的进程间使用。有名管道通过在文件系统中创建一个特殊的文件来实现,这个文件不占用磁盘空间,但提供了一个路径名,使得任何可以访问该路径的进程都能够通过它来交换数据。
创建有名管道的过程相对简单。在Linux系统中,可以使用`mkfifo`命令或者`mkfifo()`函数来创建管道文件。一旦创建,进程就可以通过标准的文件I/O调用来读写管道,如`open()`, `read()`, `write()`, 和 `close()`。
使用有名管道进行IPC的一个典型场景是,一个进程写入数据到管道,而另一个进程读取管道中的数据。这种方式的通信是单向的,但可以通过创建两个有名管道来实现双向通信。
值得注意的是,有名管道在使用过程中需要考虑同步问题。例如,如果一个进程尝试从空管道中读取数据,它将会被阻塞,直到有数据写入。同样,如果管道已满,写入操作也会被阻塞。此外,当所有写入端关闭后,读取操作将返回0,表示到达了管道的末尾。
有名管道是Linux进程间通信机制中的一个强大工具,它的使用提高了进程间通信的灵活性和效率。通过合理的设计和同步机制,开发者可以利用有名管道在不同进程间高效地传递信息。
使用有名管道需要经过以下几个步骤:
-
创建有名管道:使用命令
mkfifo
创建有名管道文件。例如,执行命令mkfifo mypipe
将创建一个名为mypipe
的有名管道文件。 -
打开管道:在程序中使用
open
函数来打开有名管道,指定相应的管道文件路径和操作模式。例如,使用以下代码片段打开管道:int fd = open("mypipe", O_WRONLY);
-
写入数据:使用
write
函数将数据写入管道。例如,使用以下代码将数据写入管道:char buffer[1024] = "Hello, pipe!";
write(fd, buffer, strlen(buffer)); -
关闭管道:使用
close
函数关闭管道。例如,使用以下代码关闭管道:close(fd);
注意:在使用有名管道时,需要保证有读端和写端同时打开。如果没有进程打开管道的读端,写入端将被阻塞,反之亦然。
作业1:有名管道,创建两个发送接收端,父进程写入管道1和管道2,子进程读取管道2和管道1.
右进程
#include <myhead.h>
int main(int argc, const char *argv[])
{
pid_t pid=fork();
if(pid>0)//父进程,将数据发送至管道1
{
int fd1;
char buff[1024];
fd1=open("./fifo_a",O_WRONLY);
if(fd1==-1)
{
perror("打开管道1");
return -1;
}
while(1)
{
fgets(buff,sizeof(buff),stdin);//从键盘读取数据
buff[strlen(buff)-1] = '\0';
write(fd1,buff,sizeof(buff));//将数据发送至管道1
if(strcmp(buff,"quit")==0)
{
break;
}
}
close(fd1);
}
else if(pid==0)
{
int fd2;
char buff1[1024];
fd2=open("./fifo_b",O_RDONLY);
if(fd2==-1)
{
perror("打开管道2");
return -1;
}
while(1)
{
read(fd2,buff1,sizeof(buff1));//从管道2读取数据
if(strcmp(buff1,"quit")==0)
{
break;
}
printf("%s\n",buff);
}
close(fd2);
}
else
{
perror("pid");
return -1;
}
return 0;
}
左进程
#include <myhead.h>
int main(int argc, const char *argv[])
{
pid_t pid=fork();
if(pid>0)//父进程,将数据发送至管道1
{
int fd1;
char buff[1024];
fd1=open("./fifo_b",O_WRONLY);
if(fd1==-1)
{
perror("打开管道1");
return -1;
}
while(1)
{
fgets(buff,sizeof(buff),stdin);//从键盘读取数据
buff[strlen(buff)-1] = '\0';
write(fd1,buff,sizeof(buff));//将数据发送至管道1
if(strcmp(buff,"quit")==0)
{
break;
}
}
close(fd1);
}
else if(pid==0)
{
int fd2;
char buff1[1024];
fd2=open("./fifo_a",O_RDONLY);
if(fd2==-1)
{
perror("打开管道2");
return -1;
}
while(1)
{
read(fd2,buff1,sizeof(buff1));//从管道2读取数据
if(strcmp(buff1,"quit")==0)
{
break;
}
printf("%s\n",buff);
}
close(fd2);
}
else
{
perror("pid");
return -1;
}
return 0;
}