传统进程间通信
通过文件实现进程间通信 必须人为保证先后顺序 A--->硬盘---> B(B不知道A什么时候把内容传到硬盘中)
1.无名管道
2.有名管道
3.信号
IPC进程间通信
4.消息队列
5.共享内存
6.信号灯集
7.socket通信
一、无名管道(亲缘关系的进程 64K)
原理:
如果A和B进程想要通过无名管道通信,那就必须在内核空间创建一个无名管道(64K),A和B进程必须是亲缘关系的进程,A进程向管道的一端写数据,B进程可以从管道的另外一端读数据。在A进程和B进程进行数据传输的时候是不允许使用lseek函数的。无名管道是半双工的通信方式。如果A进程一直向管道中写数据写满64K的时候A进程阻塞,直到B进程读一部分数据之后A才能继续写。如果B进程在读数据的时候,无名管道是空的,B进程阻塞。(PS:使用无名管道时,不会创建管道文件,使用有名管道文件,会创建)
API
int pipe(int pipefd[2]);
功能:创建一个无名管道
参数:@pipefd[2]:返回的管道的两端pipefd[1]:写端pipefd[0]:读端
返回值:成功返回0,失败返回-1置位错误码
实例
#include <head.h>
// 子进程从终端读取字符串 通过无名管道 父进程读 然后打印到终端
int main(int argc, const char *argv[])
{int pipefd[2];if (-1 == pipe(pipefd)){perror("pipe error");exit(-1);};char buff[128] = {0};pid_t pid;pid = fork();if (pid == -1){perror("fork error");exit(-1);}else if (pid == 0){// 子进程close(pipefd[0]); // 关闭子进程的读端 因为父子进程同时各自拥有读和写 把对应的关一个while (1){memset(buff, 0, sizeof(buff));fgets(buff, sizeof(buff), stdin); // 从终端读取数据if ((buff[strlen(buff) - 1]) == '\n'){buff[strlen(buff) - 1] = '\0';}write(pipefd[1], buff, sizeof(buff)); // 将读到的写入到管道if (strcmp(buff, "quit") == 0){break;}}close(pipefd[1]);exit(0);}else{// 父进程close(pipefd[1]); // 关闭父进程的写端while (1){memset(buff, 0, sizeof(buff));read(pipefd[0], buff, sizeof(buff)); // 父进程从管道中读printf("父进程data:%s\n", buff);if (strcmp(buff, "quit") == 0){break;}}close(pipefd[2]);wait(NULL);}return 0;
}
结果
二、有名管道(任意进程间的通信 64K)
有名管道可以实现任意进程间的通信,有名管道的大小也是64K,有名管道也是不支持lseek,有名管道也是半双工的通信方式。有名管道创建之后会在用户空间产生一个管道文件(p),这个管
道文件是在内存上存储的。如果A和B两个进程想要通过有名管道通信,就打开管道文件,向管道中写向管道中读就可。
API
int mkfifo(const char *pathname, mode_t mode);
功能:创建有名管道
参数:@pathname:有名管道文件的路径及名字@mode: 管道文件的权限(mode & ~umask)
返回值:成功返回0,失败返回-1置位错误码
实例
01mkfifo.c
#include <head.h>
#define FIFO_PATH "./myfifo"
int main(int argc,const char * argv[])
{//创建管道文件if(mkfifo(FIFO_PATH,0666)==-1){perror("mkfifo error");exit(-1);}//阻塞等待读写getchar();//删除管道文件char buff[128]={0};snprintf(buff,sizeof(buff),"rm -rf %s",FIFO_PATH);system(buff);return 0;
}
02read.c
#include <head.h>
#define FIFO_PATH "./myfifo"
int main(int argc, const char *argv[])
{int fd;char buff[128] = {0};if (-1 == (fd = open(FIFO_PATH, O_RDONLY))){perror("open error");exit(-1);}while (1){memset(buff, 0, sizeof(buff));read(fd, buff, sizeof(buff));printf("read:[%s]\n", buff);if (strcmp(buff, "quit") == 0){break;}}close(fd);return 0;
}
03write.c
#include <head.h>
#define FIFO_PATH "./myfifo"
int main(int argc, const char *argv[])
{int fd;char buff[128] = {0};if (-1 == (fd = open(FIFO_PATH, O_WRONLY))){perror("open error");exit(-1);}while (1){memset(buff, 0, sizeof(buff));printf("input:");fgets(buff,sizeof(buff),stdin);if(buff[strlen(buff)-1]=='\n'){buff[strlen(buff)-1]='\0';}write(fd, buff, sizeof(buff));if (strcmp(buff, "quit") == 0){break;}}close(fd);return 0;
}
结果
三、信号
信号软件层面对中断一种模拟,用户可以给进程发送信号,内核也可以给进程发送信号,进程对信号的响应方式有三种:捕捉,默认,忽略