进程间通信(IPC:Inner Proceeding Communication)
进程是操作系统实现程序独占系统运行的假象的方法,是对处理器、主存、I/O设备的抽象表示。每个进程都是一个独立的资源管理单元,每个进程所看到的是自己独占使用系统的假象,因此各个进程之间是不能够直接的访问对方进程的资源的,不同的进程之间进行信息交互需要借助操作系统提供的特殊的进程通信机制。
进程之间的通信,从物理上分,可以分为同主机的进程之间的通信和不同主机间的进程之间的通信。从通信内容方式上分,可以分为数据交互、同步通信、异步通信。
管道又可以分为匿名管道和命名管道,两者的用途是不一样的。
无名管道PIPE:主要用于具有亲缘关系的进程之间的通信,无名管道的通信是单向的,只能由一段到另外一段;匿名管道是临时性的,完成通信后将自动消失。一般采用先创建无名管道,再创建子进程,使子进程继承父进程的管道文件描述符,从而实现父子进程间的通信;在非亲缘关系管道之间,如果想利用匿名管道进行通信,则需要借助另外的文件描述符传递机制。
有名管道FIFO:有名管道是一个实际存在的特殊文件,利用有名管道可以实现同主机任意进程之间的数据交互。
实例演示:
匿名管道
匿名管道只能单向通信,且只能在有血缘关系的进程之间通信
编写管道通信实例:
<span style="font-size:14px;">#include<stdio.h>
#include<unistd.h>
#include<string.h>
int main()
{
int fd[2];
int ret = pipe(fd);
if(ret == -1){
printf("creat pipe failure ");
return 1;
}
//success
pid_t id = fork();
if(id <0)
{
printf("fork child failure");
return 2 ;
}
else if(id == 0){//child
close(fd[0]);// close read
int i = 0;
char* str = NULL;
while(i <100 )
{
str = "i am child ";
write(fd[1] , str , strlen(str)+1 );
sleep(1);
i++;
}
}
else
{ //father
close(fd[1]);
char msg[100];
int j = 0;
while(j < 100)
{
memset(msg , '\0',sizeof(msg));
read(fd[0], msg,sizeof(msg));
printf("%s \n",msg);
++j;
}
}
return 0;
}</span><span style="font-size:18px;">
</span>
Pipe:
gcc -o Pipe.o Pipe.c
.PHONY:clean
clean:
rm -f Pipe.o
看看实际结果吧。
命名管道(FIFO)
命名管道是⼀个设备⽂件,因此,即使进程与创建FIFO的进程不存在亲缘关系,只要可以访问该路径,就能够通过FIFO相互通信。值得注意的是, FIFO(first input first output)总是按照先进先出的原则⼯作,第⼀个被写⼊的数据将⾸先从管道中读出。
实例:
创建 客户端(write), 服务端(server)
//客户端 write:</span></strong>
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
#include<stdlib.h>
#define _PATH_ "/tmp/file.tmp"
#define _SIZE_ 100
int main()
{
int ret = mkfifo(_PATH_ , 0666 | S_IFIFO);
if(ret == -1)
{
printf("mkfifo failure \n");
return 1;
}
int fd = open(_PATH_ , O_WRONLY);
if(fd < 0)
{
printf("open failure \n");
return 2 ;
}
char buf[_SIZE_];
memset(buf ,'\0',sizeof(buf));
while(1)
{
scanf("%s",buf );
int ret = write(fd , buf,strlen(buf)+1);
if(ret <0)
{
printf("write failure \n");
break;
}
if(strncmp(buf ,"quit" , 4)==0 )
{
break;
}
}
close(fd);
return 0;
}
//服务端server :
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
#include<stdlib.h>
#define _PATH_ "/tmp/file.tmp"
#define _SIZE_ 100
int main()
{
int ret = mkfifo(_PATH_ , 0666 | S_IFIFO);
if(ret == -1)
{
printf("mkfifo failure \n");
return 1;
}
int fd = open(_PATH_ , O_WRONLY);
if(fd < 0)
{
printf("open failure \n");
return 2 ;
}
char buf[_SIZE_];
memset(buf ,'\0',sizeof(buf));
while(1)
{
scanf("%s",buf );
int ret = write(fd , buf,strlen(buf)+1);
if(ret <0)
{
printf("write failure \n");
break;
}
if(strncmp(buf ,"quit" , 4)==0 )
{
break;
}
}
close(fd);
return 0;
}
那么下来,我们演示下,两端能否通过file.tmp实现client和server通信呢?
总结:
无名管道主要用于具有亲缘关系的父子进程之间的通信,是临时性的,需要先创建管道,再创建子进程;管道都是单向的,若要实现双向通信,则需要两个管道。命名管道是实际存在的文件,使用前需要先打开,管道默认的read和write操作都是阻塞式的。
参考:
http://www.2cto.com/os/201410/343247.html