IPC :Internal Processes Communication
进程间通信 实现:(信息)数据的交换
管道: pipe 无名管道
fifo 有名管道
信号: signal
消息队列 System V 消息队列 / POSIX消息队列(两套不同的机制)
信号量 System V 信号量 / POSIX 信号量
共享内存 System V 共享内存 / POSIX 共享内存
socket通信: Unix域协议
在以前进程间通信的方式 都是通过文件!
但是这种方式 他有一个缺点: 他的效率太低了
管道
无名管道 pipe
管道虽然是一个文件 但是它在文件系统中没有名字(没有inode)
他的内容是在内核中 访问pipe的方式还是通过文件系统的API函数(read/write)
但是它又不能用open(因为它没有名字 ) 问题是read/write又需要一个文件描述符才能对文件进行操作。
所以在创建pipe的时候 就必须要返回文件描述符!
pipe在创建的时候 在内核中开辟一块缓冲区 作为pipe文件内容的存储空间 同时返回两个文件描述符(一个用来读 一个用来写)
它还有如下特点:
(1)pipe有两端 一端用来写 一端是用来读
(2)按顺序读 不支持lseek
(3)内容读走了 就没有了
(4)pipe(无名管道)随进程持续性
NAME
pipe - create pipe
SYNOPSIS
#include <unistd.h>
int pipe(int pipefd[2]);
函数功能: 创建一个无名管道pipe 并返回两个文件描述符
头文件: 如上
参数列表:
pipefd: 是一个具有两个int类型元素大小的数组
用来保存返回的两个文件描述符
pipefd[0] 保存读的文件描述符
pipefd[1] 保存写的文件描述符
返回值:
成功返回0
失败返回-1 并且errno被设置
使用管道实现进程间通信
进程间可以利用全局变量通信吗?
不行!全局变量不共享,相当于进程只是把该变量复制了一份
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<errno.h>
#include<pthread.h>
void sys_err(char *str)
{
perror(str);
exit(1);
}
int main(int argc,char * argv[])
{
int ret;
int fd[2]; //fd[0]是读端 fd[1]是写段
char *str="hello!!!\n";
char buf[1024];
ret=pipe(fd);
if(ret==-1)
{
sys_err("pipe error\n");
}
pid_t pid =fork();
if(pid == 0) //子进程
{
close(fd[1]); //关闭写端
ret=read(fd[0],buf,sizeof(buf)); //从管道中读到数据 存在buf中
write(STDOUT_FILENO,buf,ret); //在终端读出数据
close(fd[0]); //关闭读端
}
else //父进程
{
close(fd[0]); //关闭读端
write(fd[1],str,strlen(str)); //把数据写入管道中
sleep(1);
close(fd[1]); //关闭写端
}
return 0;
}
有名管道 fifo
fifo是在pipe地基础上 给fifo在文件系统中创建一个inode(他会在文件系统中有一个文件名)
但是同样地 fifo文件地内容却是在内核中
fifo的创建则为:
NAME
mkfifo - make a FIFO special file (a named pipe)
SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
函数功能: 创建一个有名管道
头文件: 如上
参数列表:
pathname : 你要创建的有名管道的路径名
注意:不要创建在共享文件夹下 windows不支持fifo
mode: 创建的有名管道的权限 有两种方式指定:
a. S_IRUSR S_IWUSR S_IXUSR S_IRGRP ...
b. 0660
返回值:
成功返回0
失败返回-1 并且errno被设置
fifo的创建有两种形式:
1.通过如上的函数mkfifo
mkfifo("/home/china/test.fifo",0666);
2.通过指令命令mkfifo
mkfifo ~/test.fifo
FIFO(有名管道)和PIPE(无名管道)类似,除了他在文件系统中有一个名字,它可以被多个进程打开用来读或写
当进程用FIFO来交换数据时 内核根本没有把数据写到文件系统中 而是保存在内核的内部 因此FIFO在文件系统中根本没有内容 它仅作为文件系统的一个引用入口 提供一个文件名 给其他进程去open它
在数据交换前 FIFO的两端(read/write)必须都被打开
通常情况下 你打开FIFO的一端 会阻塞 直到另外一端也被打开
一个进程同样可以以“非阻塞”方式(O_NONBLOCK)去打开 在这种情况下,只读打开总会成功 即便是写端没有被打开
只写打开总会失败 并且errno == EENXIO 除非读端已经打开