在Linux中实现进程间通信:
实现描述:
进程A:
1. 判断有名管道fifo1与fifo2是否创建:
1.1 没创建,需要首先创建管道;
1.2. 创建好了:
1.2.1 进程A 以只写的方式打开管道1,只读的方式打开管道2
1.2.2 定义一个内核缓冲区
1.2.3 向管道1中,写入数据之前清空缓冲区
1.2.4 向缓冲区中写入数据
1.2.5 写完数据后等待进程B向管道2中发送数据以读取
1.2.6 打印读取的数据
进程B:
1. 判断有名管道fifo1与fifo2是否创建:
1.1 没创建,需要首先创建管道;
1.2. 创建好了:
1.2.1 进程B 以只读的方式打开管道1,只写的方式打开管道2
1.2.2 定义一个内核缓冲区
1.2.3 在管道1中,读取数据之前清空缓冲区
1.2.4 从缓冲区中读取数据
1.2.5 打印读取的数据
1.2.6 读完数据后向管道2中写入数据
代码:进程A
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
int main()
{
// 1.首先判断有名管道是否存在,存在就直接使用,不存在就创建
int ret = access("fifo1", F_OK); //判断管道是否存在
if (ret == 0)
{
printf("Pipe 1 has existed\n");
}
else
{
printf("Pipe 1 has not existed,need to create\n");
int ret = mkfifo("fifo1", 0664); //第一个是文件路径,第二个是权限
if (ret == -1)
{
perror("mkfifo");
exit(0);
}
}
ret = access("fifo2", F_OK); //判断管道是否存在
if (ret == 0)
{
printf("Pipe 2 has existed\n");
}
else
{
printf("Pipe 2 has not existed,need to create\n");
int ret = mkfifo("fifo2", 0664); //第一个是文件路径,第二个是权限
if (ret == -1)
{
perror("mkfifo");
exit(0);
}
}
// 2. 只写的方式打开管道1
int fdw = open("fifo1", O_WRONLY);
if (fdw == -1)
{
perror("open");
exit(0);
}
printf("打开管道fifo1成功,等待写入...\n");
// 3. 只读的方式打开管道2
int fdr = open("fifo2", O_RDONLY);
if (fdr == -1)
{
perror("open");
exit(0);
}
printf("打开管道fifo2成功,等待读取...\n");
// 4.循环的写读数据
char buf[128] = {}; //初始化一个内核缓冲区,fifo中的数据存在内核中
while (1)
{
memset(buf, 0, 128); //清空buf
//获取标准的输入
fgets(buf, 128, stdin); //换行不会结束输入,标准输入中获取文件指针
//写端写数据
ret = write(fdw, buf, strlen(buf));
if (ret == -1)
{
perror("write");
exit(0);
}
// 5. 读管道数据
memset(buf, 0, 128);
ret = read(fdr, buf, 128); //等待B写入才能再读
if (ret <= 0)
{ //<0 调用失败;=0 read完数据
perror("read");
break;
}
printf("buf:%s\n", buf);
}
//关闭文件描述符
close(fdw);
close(fdr);
return 0;
}
代码:进程B
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
int main()
{
// 1.首先判断有名管道是否存在,存在就直接使用,不存在就创建
int ret = access("fifo1", F_OK); //判断管道是否存在
if (ret == 0)
{
printf("Pipe 1 has existed\n");
}
else
{
printf("Pipe 1 has not existed,need to create\n");
int ret = mkfifo("fifo1", 0664); //第一个是文件路径,第二个是权限
if (ret == -1)
{
perror("mkfifo");
exit(0);
}
}
ret = access("fifo2", F_OK); //判断管道是否存在
if (ret == 0)
{
printf("Pipe 2 has existed\n");
}
else
{
printf("Pipe 2 has not existed,need to create\n");
int ret = mkfifo("fifo2", 0664); //第一个是文件路径,第二个是权限
if (ret == -1)
{
perror("mkfifo");
exit(0);
}
}
// 2. 只读的方式打开管道1
int fdr = open("fifo1", O_RDONLY); //另一端没打开,阻塞,等待另一端打开才继续进行
if (fdr == -1)
{
perror("open");
exit(0);
}
printf("打开管道fifo1成功,等待读取...\n");
// 3. 只写的方式打开管道2
int fdw = open("fifo2", O_WRONLY);
if (fdw == -1)
{
perror("open");
exit(0);
}
printf("打开管道fifo2成功,等待写入...\n");
// 4.循环的读写数据
char buf[128] = {}; //初始化一个内核缓冲区,fifo中的数据存在内核中
while (1)
{
// 5. 读管道数据
memset(buf, 0, 128);
ret = read(fdr, buf, 128);
if (ret <= 0)
{ //<0 调用失败;=0 read完数据
perror("read");
break;
}
printf("buf:%s\n", buf);
memset(buf, 0, 128); //清空buf
//获取标准的输入
fgets(buf, 128, stdin); //换行不会结束输入,标准输入中获取文件指针
//写端写数据
ret = write(fdw, buf, strlen(buf));
if (ret == -1)
{
perror("write");
exit(0);
}
}
// 6. 关闭文件描述符
close(fdw);
close(fdr);
return 0;
}
———————————————————————————————————————————
上述进程通信存在的问题:
只有当进程A发送多行数据时,B中只读取第一行数据,在终端只显示第一行,只有A进程再次收到进程B的数据后,A中的第二行才会从缓冲区内显示在进程B的终端中。
造成此结果的原因是,进程A、B读写在同一个进程中进行,read() 没有读到另一个进程的数据 会发送阻塞等待。
避免:创建一个子进程,用父进程实现写的功能,用子进程实现读的功能,互不干扰。
———————————————————————————————————————————
代码:进程A
pid_t pid = fork();
char buf[128] = {};
if (pid > 0)
{
// 4.父进程用来写数据
while (1)
{
memset(buf, 0, 128); //清空buf
//获取标准的输入
fgets(buf, 128, stdin); //换行不会结束输入,标准输入中获取文件指针
//写端写数据
ret = write(fdw, buf, strlen(buf));
if (ret == -1)
{
perror("write");
exit(0);
}
}
}
else if (pid == 0)
{
// 5. 子进程读管道数据
while (1)
{
memset(buf, 0, 128);
ret = read(fdr, buf, 128); //等待B写入才能再读
if (ret <= 0)
{ //<0 调用失败;=0 read完数据
perror("read");
break;
}
printf("buf:%s\n", buf);
}
}
代码:进程B
pid_t pid = fork();
char buf[128] = {}; //初始化一个内核缓冲区,fifo中的数据存在内核中
if (pid > 0)
{
while (1)
{
// 5. 读管道数据
memset(buf, 0, 128);
ret = read(fdr, buf, 128);
if (ret <= 0)
{ //<0 调用失败;=0 read完数据
perror("read");
break;
}
printf("buf:%s\n", buf);
}
}
else if (pid == 0)
{
while (1)
{
memset(buf, 0, 128); //清空buf
//获取标准的输入
fgets(buf, 128, stdin); //换行不会结束输入,标准输入中获取文件指针
//写端写数据
ret = write(fdw, buf, strlen(buf));
if (ret == -1)
{
perror("write");
exit(0);
}
}
}