linux进程通信1:进程通信概述,管道通信原理(无名管道,有名管道),管道编程实战

进程通信概述,管道通信原理(无名管道,有名管道),管道编程实战

1.进程间通信概述:

举例1:
你手机微信和别人手机微信通信
举例2:
如:父子进程wait 和 exit之间的通信

进程间通信(IPC):指在不同进程之间传播或交换信息

进程间通信(IPC)的通信方式:

IPC的方式通常有管道(包括无名管道和命名管道),
消息队列,
信号量,
共享存储,
socket,streams等,
其中socket和streams支持不同主机上的两个进程IPC

2. 管道通信原理:

管道:通常指无名管道,是UNIX系统IPC最古老的形式
特点:

半双工(数据只能在一个方向上流动),具有固定的读端和写端只能用于具有亲缘关系进程间通信(父子兄弟)
它可以看作文件,对于它的读写可用read,write等函数,
但是它不是普通的文件,并不属于其它任何文件系统,并且只存在于内存中

注意:管道中的数据读走后就没了。

pipe函数原型:

#include<unistd.h>
int pipe(int fd(2));//返回值:成功:0,失败:-1

当一个管道建立时,它会创建两个文件描述符:fd[0]为读而打开,fd[1]为写而打开。如下图:

在这里插入图片描述
要关闭管道只需将这两个文件描述符关闭即可。

例子:

单个进程中的管道几乎没有任何用处。所以,通常调用 pipe 的进程接着调用 fork,这样就创建了父进程与子进程之间的 IPC 通道。如下图所示:

在这里插入图片描述
若要数据流从父进程流向子进程,则关闭父进程的读端(fd[0])与子进程的写端(fd[1]);反之,则可以使数据流从子进程流向父进程。

参考代码:

#include<stdio.h> 
#include<unistd.h>
int main() 
{
int fd[2]; // 两个文件描述符 
pid_t pid;
char buff[20]; 
if(pipe(fd) < 0) // 创建管道 
printf("Create Pipe Error!\n"); 
if((pid = fork()) < 0) // 创建子进程 
printf("Fork Error!\n"); 
else if(pid > 0) // 父进程 
{ 
close(fd[0]); // 关闭读端 
write(fd[1], "hello world\n", 12); 
} 
else 
{ 
close(fd[1]); // 关闭写端 
read(fd[0], buff, 20); 
printf("%s", buff); 
}  
return 0; 
}

运行结果:

在这里插入图片描述

其中包含的读写函数原型:

#include <unistd.h>
int pipe(int pipef d[2]);
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
ssize_t read(int fd, void *buf, size_t count);

3.管道编程实战:

参考代码:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
//管道的原型:int pipe(int pipe fd[2]);
int main()
{
int fd[2];
int pid;//fork的返回值
char buf[128];
if(pipe(fd)==-1)
{
printf("创建管道失败\n");
}
pid=fork();//父进程会拷贝一个空间给子进程
if(pid<0)
{
printf("创建子进程失败\n");
}else if(pid>0)
{
sleep(3);//父进程睡3秒,保证子进程先运行,,子进程会阻塞
printf("进入了父进程id:%d\n",getpid());
close(fd[0]);//关掉父进程的管道读操作
write(fd[1],"hello from father",strlen("hello from father"));
wait(NULL);//不让父进程直接结束,子进程成孤儿
}else
{
printf("进入了子进程id:%d\n",getpid());
close(fd[1]);//关掉父进程的管道写操作
read(fd[0],buf,128);//读到buf里面,读wei字节
printf("read:%s\n",buf);
exit(0);
}
return 0;
}

代码:实现子进程与父进程之间的通信。

运行结果:

在这里插入图片描述
4.命名管道:

FIFO:也称为命名管道,它是一种文件类型

特点:

FIFO可以在无关的进程之间交换数据,与无名管道不同。
FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中

fifo函数原型:

#include <sys/types.h>  
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);//创建
// 返回值:成功返回0,出错返回-1  
//其中的 mode 参数与open函数中的 mode 相同。一旦创建了一个 FIFO,就可以用一般的文件I/O函数操作它。
//如果命名管道文件已经存在,则会创建失败

演示代码:

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
//int mkfifo(const char *pathname, mode_t mode);
int main()
{
int ret=mkfifo("./file",0600);//创建命名管道(文件),0600:可读可写的方式
if(ret==0)
{
printf("创建成功\n");
}
if(ret==-1)
{
printf("创建失败\n");
perror("why");//打印失败原因
}
}

运行结果:
在这里插入图片描述

注意:
此种创建如果文件存在,创建也失败,说明不完善

修改演示代码如下:

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
//int mkfifo(const char *pathname, mode_t mode);
int main()
{
if((mkfifo("./file",0600)==-1)&&errno!=EEXIST)//同时满足错误吗:文件已存在
{
printf("创建失败\n");
perror("why");
}else
{
if(errno==EEXIST)
{
printf("文件有啦\n");
}else
{
printf("创建成功\n");
}
}
return 0;
}

运行结果:
在这里插入图片描述
5.命名管道编程通信编程实现:

open函数原型:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>       
int open(const char *pathname, int flags);

//当 open 一个FIFO时,是否设置非阻塞标志(O_NONBLOCK)的区别:
//默认没有设置,
//只读 open :要阻塞---到某个其他进程为写而打开此 FIFO文件。
//类似的,只写 open 要阻塞---到某个其他进程为读而打开它。

演示代码:

打开并只读:

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
//int mkfifo(const char *pathname, mode_t mode);
int main()
{
char buf[30]={0};
if((mkfifo("./file",0600)==-1)&&errno!=EEXIST)//同时满足错误吗:文件已存在
{
printf("创建失败\n");
perror("why");
}
int fd=open("./file",O_RDONLY);//仅只读这个管道文件
printf("打开成功\n");
int nread=read(fd,buf,30);//一次读20个字节...返回字节数
printf("read %d byte from fifo\ncontext:%s\n",nread,buf);
close(fd);
return 0;
}

打开并只写:

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
//int mkfifo(const char *pathname, mode_t mode);
int main()
{
char *str="vnfvjdknvdrij";
int fd=open("./file",O_WRONLY);//仅只写这个管道文件
printf("写入打开成功\n");
write(fd,str,strlen(str));
close(fd);
return 0;
}

注意:读写同时打开才能进行操作
运行结果:
在这里插入图片描述
说明:

若指定了O_NONBLOCK(非阻塞)无意义,则只读 open 立即返回。而只写 open 将出错返回 -1 如果没有进程已经为读而打开该 FIFO,其errno置ENXIO。

一般使用FIFO的时候,都是以非阻塞方法打开

上述例子可以扩展成 客户进程—服务器进程 通信的实例,write_fifo的作用类似于客户端,可以打开多个客户端向一个服务器发送请求信息,read_fifo类似于服务器,它适时监控着FIFO的读端,当有数据时,读出并进行处理,但是有一个关键的问题是,每一个客户端必须预先知道服务器提供的FIFO接口,下图显示了这种安排:

在这里插入图片描述

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值