进程间通讯之管道
管道也是进程间通讯的常用方式,管道通讯分为有名管道和无名管道通讯,但无论哪种管道通讯都是半双工的通讯方式,即不同的进程完成不同的工作,读、写数据分别有不同的进程完成。负责写的进程关闭读端,负责读的进程关闭写端。有名管道与无名管道的区别在于有名管道会在磁盘上创建一个inode节点,不会创建block,会存在一个文件名。而无名管道不会存在文件名。所以,无名管道只能用于父子进程之间进行数据传输,而有名管道不受限制,可在任意两进程之间进行数据传输。
有名管道工作原理:
通过命令mkfifo或函数mkfifo()来创建一个管道文件FIFO,通过对管道文件的操作从而实现对内存空间上的数据流进行传输。
实例:
A进程:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include <fcntl.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include <fcntl.h>
int main()
{
int fd = open("FIFO", O_WRONLY);//会阻塞运行
if(fd < 0)
{
int n = mkfifo("FIFO", 0664);
if(n == -1)
{
perror("FIFO");
exit(0);
}
{
int fd = open("FIFO", O_WRONLY);//会阻塞运行
if(fd < 0)
{
int n = mkfifo("FIFO", 0664);
if(n == -1)
{
perror("FIFO");
exit(0);
}
fd = open("FIFO", O_WRONLY);
assert(fd != -1);
}
assert(fd != -1);
}
printf("open success\n");
while(1)
{
printf("please input: ");
char buff[128] = {0};
fgets(buff, 128, stdin);
{
printf("please input: ");
char buff[128] = {0};
fgets(buff, 128, stdin);
if(strncmp(buff, "end", 3) == 0)
{
break;
}
{
break;
}
write(fd, buff, strlen(buff) - 1);
}
}
close(fd);
}
}
B进程:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include <fcntl.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include <fcntl.h>
int main()
{
int fd = open("FIFO", O_RDONLY);
if(fd < 0)
{
int n = mkfifo("FIFO", 0664);
if(n == -1)
{
perror("FIFO");
exit(0);
}
{
int fd = open("FIFO", O_RDONLY);
if(fd < 0)
{
int n = mkfifo("FIFO", 0664);
if(n == -1)
{
perror("FIFO");
exit(0);
}
fd = open("FIFO", O_RDONLY);
assert(fd != -1);
}
assert(fd != -1);
}
printf("open success\n");
while(1)
{
char buff[128] = {0};
int n = read(fd, buff, 127);// 会阻塞运行
if(n == 0)
{
break;
}
{
char buff[128] = {0};
int n = read(fd, buff, 127);// 会阻塞运行
if(n == 0)
{
break;
}
printf("%s %d\n",buff,strlen(buff));
}
}
close(fd);
}
}
注:进程A和进程B都会存在阻塞的现象。A进程阻塞是因为写入数据,没有进程来读取数据而进入阻塞。B进程阻塞是因为读取时没有进程写入数据而阻塞。
无名管道工作原理:
无名管道并不会去创建管道文件,所以,无名管道只能应用于父子进程之间。应为父子进程之间对于fork之前打开的文件描述符是共享的。
无名管道的操作:
int pipe(int fd[2]);用于创建并打开一个无名管道,并且使fd[0]指向管道读端,fd[1]指向管道写端。
无名管道进行数据传输时,由于管道的半双工特性因此,父进程执行写操作是关闭读端,执行读操作时关闭写端。子进程也是同样的道理。
实例:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
int main()
{
int fds[2] = {0};
if(pipe(fds) == -1)
{
printf("error...\n");
exit(0);
}
{
int fds[2] = {0};
if(pipe(fds) == -1)
{
printf("error...\n");
exit(0);
}
if(fork() == 0)
{
close(fds[1]);
{
close(fds[1]);
while(1)
{
char buff[128] = {0};
int n = read(fds[0], buff, 127);
{
char buff[128] = {0};
int n = read(fds[0], buff, 127);
if(n == 0)
{
break;
}
{
break;
}
printf("%s %d",buff,strlen(buff));
}
}
close(fds[0]);
}
else
{
close(fds[0]);
}
else
{
close(fds[0]);
while(1)
{
printf("please input:");
char buff[128] = {0};
fgets(buff, 128, stdin);
{
printf("please input:");
char buff[128] = {0};
fgets(buff, 128, stdin);
if(strncmp(buff, "end", 3) == 0)
{
break;
}
{
break;
}
write(fds[1], buff, strlen(buff) - 1);
sleep(1);
}
sleep(1);
}
close(fds[1]);
}
}
}
}