进程间的通信(IPC),是指在不同进程之间传播或交换信息 IPC的方式通常有管道(无名管道和命名管道),消息队列,信号量,共享储存,Socket、Streams等,其中Socket、Streams支持两台PC机上的两个进程
单机通信:如果是在一台机器上,则为单机通信 ,如半双工管道,全双工管道,消息队列,信号量,共享内存
多机通信:在多台机器上进行通信,网络通信,如Socket(套接字)、Streams等;
管道:通常是指无名管道(因为没有文件名,所以叫无名管道)
特点:
1、它是半双工的(即数据只能在一个方向上流动,一个写一个读),具有固定的读端和写端。
2、它只能用于具有亲缘关系的进程之间的通信(也是父子进程或者兄弟进程之间)。
3、它可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write 等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。
4、管道中的数据被读走了,管道中就没有数据了。
函数原型:无名管道
#include <unistd.h>
int pipe(int pipefd[2]);//pipe函数成功返回0,失败返回-1
当建立一个管道时,由参数fd返回两个文件描述符:fd[0]为读而打开,fd[1]为写而打开,
fd[1]的输出是fd[0]的输入,管道是建立在内核之中的
关闭管道:fd[0]和fd[1]的文件描述符关闭即可
函数例子:在读fd[0]时要关闭写(fd[1]) 写fd[1]时要关闭读fd[0]
#include <stdio.h>
#include <unistd.h>
#include <string.h>
//int pipe(int pipefd[2]);
int main()
{
int fd[2];
int pid;
char buf[128] = {0};
if(pipe(fd) == -1){ //等于-1表示失败
printf("creat pipe fail\n");
}
pid = fork(); //创建进程
if(pid < 0){ //创建进程失败
printf("creat pid fail\n");
}
else if(pid > 0){ //进入父进程
printf("this is father\n");
close(fd[0]); //关闭读
write(fd[1],"hello world",strlen("hello world")); //往fd[1]写字符串hello world
}
else{ //进入子进程
printf("this is child\n");
close(fd[1]); //关闭写
read(fd[0],buf,128); //将父进程中写入的字符串从fd[0]中读出来
printf("read father %s\n",buf); //打印
}
return 0;
}
有名管道(文件类型):有名管道也叫命名管道,是在文件系统目录中存在一个管道文件中,管道文件仅仅是文件系统中的标示,并不在磁盘上占据空间。在使用时,在内存上开辟空间,作为两个进程数据交互的通道。
函数原型:
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
mkfifo函数成功返回0,失败返回-1
mode:和open函数中的权限相似(0600)
pathname:路径名字
函数例子:创建管道
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
if((mkfifo("./file",0600) == -1) && errno != EEXIST){ // EEXIST 表示文件存在错误
printf("mkfifom fail\n");
perror("why");
}
函数创建成功后不会打印错误信息
函数例子:一个文件是将数据写入管道,另一个文件是将第一个写入管道中的数据读出来,然后输出
将管道中的文件读到buf中,再输出
#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};
int nread = 0;
int cnt = 0;
if((mkfifo("./file",0600) == -1) && errno != EEXIST){ //创建管道
printf("mkfifom fail\n");
perror("why");
}
int fd = open("./file",O_RDONLY); //以只读方式打开管道
printf("open success\n");
while(1){
nread = read(fd,buf,30); //将管道中的数据读到buf中
printf("read %d byte read file:%s\n",nread,buf); //打印字节数和读出的内容
cnt++;
if(cnt == 5){
break;
}
}
close(fd); //关闭管道
return 0;
}
这里如果运行read的话会造成read堵塞,因为只读open要阻塞到某个其他进程为写而打开此管道,
这里要运行write时,read才不会堵塞
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
int main()
{
int cnt = 0;
char *str = "hello world"; //要向管道写入的字符串
int fd = open("./file",O_WRONLY); //以只写的方式打开管道
printf("write open success\n");
while(1){ //连续输入5个
write(fd,str,strlen(str)); //将字符串str写入管道fd
sleep(1); //延时一秒
cnt++;
if(cnt == 5){
break;
}
}
close(fd); //关闭管道
return 0;
}