一、进程
1.1 进程间通信的概念
线程通信通过全局变量即可。
进程间通信是相互独立的,但是所有进程都共用一份内核空间,所以进程和进程之间的通信可以通过内核去进行。
1.2 进程间通信方式
共7种:
- 传统的进程间通信方式:
- 无名管道
- 有名管道
- 信号
- systemV版本的IPC进程间通信:
- 消息队列
- 共享内存
- 信号灯集
- BSD版本的:
- socket实现本地通信
1.3 无名管道
1.3.1 无名管道的概念和特性
无名管道在内核中开辟一块内存空间,用于进程间的通信。
无名管道创建之后,回想用户返回两个文件描述符,一个读端文件描述符,一个写端文件描述符。读端文件描述符,用于从管道中读取数据,写端文件描述符,用于向管道中写入数据。
无名管道只能用于亲缘间进程的通信。
无名管道大小是64K。
1.3.2 无名管道的API
#include <unistd.h>
int pipe(int pipedf[2]);
功能:创建一个无名管道
参数:pipefd:保存内核返回的管道的两端pipedf[0]:管道的读端pipedf[1]:管道的写端
返回值:成功返回0,失败返回-1,置位错误码
1.3.3 无名管道运行实例:
#include <my_head.h>int main(int argc,const char *argv[]){int ret = 0;int pipedf[2] = {0};//创建无名管道ret = pipe(pipedf);if(-1 == ret){PRINT_ERR("create pipe error");}//创建子进程ret = fork();if(-1 == ret){PRINT_ERR("fork error");}else if(0 == ret){//子进程,关闭读char send_buf[128] = {0};close(pipedf[0]);while(1){fgets(send_buf,sizeof(send_buf),stdin);send_buf[strlen(send_buf)-1] = '\0';write(pipedf[1],send_buf,strlen(send_buf));if(!strcmp(send_buf,"quit"))break;}close(pipedf[1]);}else{//父进程,关闭写char recv_buf[128] = {0};close(pipedf[1]);while(1){memset(recv_buf,0,sizeof(recv_buf));read(pipedf[0],recv_buf,sizeof(recv_buf));if(!strcmp(recv_buf,"quit"))break;printf("我是父进程,我收到了数据[%s]\n",recv_buf);}close(pipedf[0]);wait(NULL);}return 0;
}
运行结果:
无名管道的读写特点:
如果读端关闭,向管道写数据:
管道破裂,祥管道写入数据的进程会收到管道破裂的信号,这个信号会杀死该进程。
如果独断打开(不读),一直写:
有多少写多少,管道满了之后(管道大小是164K),会在write的地方阻塞
如果写端不存在,读数据:
如果管道中有数据,就读数据,如果没有数据就立即返回。
如果写端存在(不写),读数据,有数据就读数据,没数据就在read的地方阻塞
1.4有名管道
1.4.1 有名管道的特点
有名管道在内核中开辟一块内存空间,用于进程间的通信。
有名管道创建之后,会在文件系统中创建一个管道文件。
两个进程想要进行通信的时候,可以通过open函数1打开管道文件,然后向管道中写入内容,或者读取内容,实现进程间的通信。
这个管道文件本质上是保存在内存上的。
有名管道可以用于任意进程间通信。
有名管道大小为64K。
2.4.2 创建有名管道的API
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname,mode_t mode);
功能:创建一个有名管道
参数:pathname:管道文件的路径和名字mode:创建文件的权限(mode & ~umask)
返回值:成功返回0,失败返回-1,置位错误码mkfifo 管道文件名 --- 通过命令创建一个有名管道
1.4.3 有名管道使用示例
mkfifo.c
#include <my_head.h>int main(int argc,const char *argv[]){mkfifo("./fifo",0666);getchar();//system("rm fifo");remove("./fifo");//删除文件return 0;
}
read.c
#include <my_head.h>int main(int argc,const char *argv[]){int fd = 0;//1.打开管道文件,以只读的方式打开fd = open("./fifo",O_RDONLY);if(-1 == fd){PRINT_ERR("open fifo error");}char recv_buf[128] = {0};//2.开始循环读while(1){memset(recv_buf,0,sizeof(recv_buf));read(fd,recv_buf,sizeof(recv_buf));if(!strcmp(recv_buf,"quit"))break;printf("读到了数据[%s]\n",recv_buf);}close(fd);return 0;
}
write.c
#include <my_head.h>int main(int argc,const char *argv[]){int fd = 0;//1.以只读方式打开管道文件fd = open("./fifo",O_WRONLY);if(-1 == fd){PRINT_ERR("open fifo error");}char send_buf[128] = {0};//2.开始循环写 while(1){fgets(send_buf,sizeof(send_buf),stdin);send_buf[strlen(send_buf) - 1] = '\0';write(fd,send_buf,strlen(send_buf));if(!strcmp(send_buf,"quit"))break;}close(fd);return 0;
}
有名管道的读写特点:
如果读端没有打开,写管道:
在open的位置阻塞。
如果读端打开(不读),写管道:
有多少写多少,写满为止,写阻塞。
读端打开后关闭,写管道:
管道破裂,向写管道的进程发送管道破裂信号,杀死该进程。
如果写端没打开,读管道:
在open的位置阻塞。
写端打开(不写),读管道:
有数据就读数据,没数据,在read的地方阻塞。
写端打开后关闭,读管道:
有数据就读数据,没数据就立即返回。