欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 时评 > IPC通信

IPC通信

2024/10/26 1:16:21 来源:https://blog.csdn.net/qq_57106106/article/details/141197622  浏览:    关键词:IPC通信

信号的分类

标准信号(1~31号):在中断处理标准信号的时候,如果handler函数运行时间过长,接收到多个相同信号,自会准确处理第一个,剩余都会丢失

实时信号(33~64):与标准信号相对的,无论发送多少信号,无论每个信号要处理多久,都不会丢失的信号。

信号的常用函数

kill

原型 int kill(pid_t pid, int sig);
调用 kill(pid,SIGINT....)
功能描述:向pid进行发送 sig信号,例如SIGINT或者 SIGTSTP 或者其他信号....

raise

原型 int raise(int sig);
调用 raise(SIGINT...)
功能描述:向当前进程自身发送 SIGINT或者其他信号...

pause

原型:int pause(void);
调用:pause()
功能描述:暂停当前进程的运行,也就是进入阻塞,处于静止态,直到当前进程接收到任意信号并处理完信号为止

总结

信号虽然属于IPC进程间通信,但是信号本身不能夹带数据,只能发送一个标记

信号属于一种终端处理机制

管道

专门用于实现一端写入一端读取的操作

管道必须是一端写入,一端读取

无名管道

无名管道:只有文件描述符,没有实体文件

无名管道只能用在父进程之间:两个进程要访问同一个无名管道,必须依赖父进程创建子进程的时候,子进程会拷贝父进程的除代码段的所有内容

*一定是父进程先创建无名管道,再创建子进程(若是在fork后创建pipe则父子进程各创建一个pipe则不能实现通信)

创建无名管道

函数原型:

int pipe(int pipefd[2]);

调用形式:

int fd[2];

pipe(fd);

功能:

传入一个容量至少为2的整型数组,用来接收创建出来的无名管道的读端和写端。fd[0]存放的是读端描述符,fd[1]存放的写端描述符。

练习:

创建一对父子进程

父进程:负责输入长方形或三角形的边长或三边长

子进程:负责输出长方形或三角形的面积

#include <stdio.h>
#include <string.h>
#include <stdlib.h>	
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>
#include <math.h>typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;
int main(int argc, const char *argv[])
{int fd[2]={0};pipe(fd);pid_t pid=fork();if(pid>0){close(fd[0]);while(1){sleep(1);printf("请输入:\n");double arr[3];scanf("%lf",arr+0);while(getchar()!=10);scanf("%lf",arr+1);while(getchar()!=10);	scanf("%lf",arr+2);while(getchar()!=10);                 //输入三边长,如果是长方形,最后一个输入0write(fd[1],arr,24);}}else{close(fd[1]);while(1){double arr[3];read(fd[0],arr,24);if(arr[2]==0){printf("长方形的面积=%lf\n",arr[0]*arr[1]);}else{//最好再判断一下输入的三边长是否满足三角形,但我懒得写了double i,S,s;i=(arr[0]+arr[1]+arr[2])/2;S=i*(i-arr[0])*(i-arr[1])*(i-arr[2]);s=sqrt(S);                                     //海伦公式printf("三角形的面积=%lf\n",s);}}}return 0;
}

创建两个.c文件

1#文件:负责输入长方形或三角形的边长或三边长

2#文件:负责输出长方形或三角形的面积

用无名管道实现

1#文件:read写死

#include <stdio.h>
#include <string.h>
#include <stdlib.h>	
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>
#include <math.h>typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;
int main(int argc, const char *argv[])
{int fd[2]={0};pipe(fd);pid_t pid=fork();if(pid>0){close(fd[0]);while(1){sleep(1);printf("请输入:\n");double arr[3];scanf("%lf",arr+0);while(getchar()!=10);scanf("%lf",arr+1);while(getchar()!=10);	scanf("%lf",arr+2);while(getchar()!=10);                 //输入三边长,如果是长方形,最后一个输入0write(fd[1],arr,24);}}else{close(fd[1]);execl("./1","1",NULL);}return 0;
}

将read的参数传给2#文件

2#文件:read被写死

#include <stdio.h>
#include <string.h>
#include <stdlib.h>	
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>
#include <math.h>typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;
int main(int argc, const char *argv[])
{while(1){double arr[3];read(3,arr,24);    //read的第一个参数被写死if(arr[2]==0){printf("长方形的面积=%lf\n",arr[0]*arr[1]);}else                                                                   {//最好再判断一下输入的三边长是否满足三角形,但我懒得写了double i,S,s;i=(arr[0]+arr[1]+arr[2])/2;S=i*(i-arr[0])*(i-arr[1])*(i-arr[2]);s=sqrt(S);                                     //海伦公式printf("三角形的面积=%lf\n",s);}}return 0;
}

接收来自1#文件传输的read的第一个参数

有名管道

操作流程和文件IO一样:先打开文件,再读/写,最后关闭文件

区别:文件IO的open只能创建普通文件不能创建管道文件

操作有名管道之前,需要判断管道文件是否存在,如果不存在则创建一个管道文件

判断存在的函数(access),创建有名管道的函数(mkfifo)

mkfifo函数

函数原型:

int mkfifo(const char *pathname, mode_t mode);

调用形式:

mkfifo("./myfifo",0666);

功能:

以mode权限创建一个有名管道

参数 pathname:文件名

参数 mode:创建权限

有名管道的工作模式

半双工模式:同一段时间内,数据的流通是单向的

还有两种工作模式:

单工:任意时刻,数据的流通就是单向的

全双工:任意时刻数据的流通都是双向的

建立两个流向相反的管道就能实现数据的双向流通。

管道与文件IO的区别

管道通过以下方式,保证2个进程的同步性(两个进程先写后读)。文件IO不能保证同步性。

  1. 当一个进程打开管道的一段之后,当前进程会被阻塞,直到管道的另一端被打开。
  2. 当管道读端用read读取管道中内容时,如果管道中没有内容,则read函数被阻塞,直到管道中被写入内容为止。

管道破裂

当管道的任意一段的进程结束运行的时候,这根管道就会破裂,破裂的管道会导致管道读端的read从阻塞状态变为非阻塞。

处理方式:

根据read的返回值判断管道是否破裂(返回值为0,则管道破裂,此需要结束read)

练习:

使用有名管道,实现两个终端的相互通信(异步)

1#终端:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>	
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;int fd1,fd2;void* task0(void *arg)
{	while(1){char arr[128]={0};printf("1#请输入:");scanf("%s",arr);while(getchar()!=10);write(fd1,arr,strlen(arr));}
}void* task1(void *arg)
{while(1){char arr[128];int r=read(fd2,arr,127);if(0==r){exit(0);}printf("读取到2#终端的数据为:%s\n",arr);}}int main(int argc, const char *argv[])
{if(access("./myfifo1",F_OK)==-1){mkfifo("./myfifo1",0666);}if(access("./myfifo2",F_OK)==-1){mkfifo("./myfifo2",0666);}fd1 = open("./myfifo1",O_WRONLY);fd2 = open("./myfifo2",O_RDONLY);pthread_t id0,id1,id2,id3;pthread_create(&id0,0,task0,0);pthread_create(&id1,0,task1,0);pthread_detach(id0);pthread_detach(id1);while(1);return 0;
}

2#终端:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>	
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;int fd1,fd2;void* task0(void *arg)
{	while(1){char arr[128];int r=read(fd1,arr,127);if(0==r){exit(0);}printf("读取到1#终端的数据为:%s\n",arr);}
}void* task1(void *arg)
{	while(1){char arr[128]={0};printf("2#请输入:");scanf("%s",arr);while(getchar()!=10);write(fd2,arr,strlen(arr));}
}int main(int argc, const char *argv[])
{if(access("./myfifo1",F_OK)==-1){                                                mkfifo("./myfifo1",0666);}	if(access("./myfifo2",F_OK)==-1){                                                mkfifo("./myfifo2",0666);}fd1 = open("./myfifo1",O_RDONLY);fd2 = open("./myfifo2",O_WRONLY);pthread_t id0,id1,id2,id3;pthread_create(&id0,0,task0,0);pthread_create(&id1,0,task1,0);pthread_detach(id0);pthread_detach(id1);while(1);return 0;
}

共享内存

就是进程中占用的那1个G的共享内存和堆空间的操作流程类似,必须先申请共享内存才能使用

*注意:如何让2个进程申请到同一片共享内存的使用权

共享内存的使用流程

创建密钥

多个进程如果想要访问同一片共享内存的话,就必须保证使用的密钥值相同。

函数原型:

key_t ftok(const char *pathname, int proj_id);

调用形式:

key_t key = ftok("文件名",1~255)

功能:

根据pathname以及proj_id的值,创建一个密钥,并将创建出来的密钥向外返回

2个进程,调用fork的时候,仅当传入的pathname和proj_id一样的时候,创建的密钥才一样。

参数 pathname:文件名

参数 proj_id:传 1~255的值即可

返回值:成功返回创建出来的秘钥,失败返回-1

根据密钥申请共享内存

仅当密钥相同的时候,2个进程申请的共享内存才是同一个内存

函数原型:

int shmget(key_t key, size_t size, int shmflg);

调用形式:

shmget(key,1024,IPC_CREAT | 0666);

功能:

根据密钥key,申请大小为size字节的内存。

参数 key:秘钥

参数 size:共享内存大小

参数 shmflg:IPC_CREAT | 0666 表示该共享内存如果是第一次申请的话,则以0666权限申请 如果

申请过的话,则不再申请,直接访问该共享内存

返回值:shmget不会返回申请的共享内存的的地址,而是将共享内存的id号返回出来了。若共享内存申请失败则返回-1。

根据id号获取共享内存的地址

函数原型:

void *shmat(int shmid, const void *shmaddr, int shmflg);

调用形式:

各种数据类型* addr=(各种数据类型*)shmat(id,0,0); //参考mallioc的申请格式

功能:

将shmid这个共享内存,映射到进程独立内存中,被共享内存映射的进程内存将完全代表共享内存。

往被映射的的内存的写入数据,实际上就是往共享内存中写入数据

从被映射的的内存的读取数据,实际上就是从共享内存中读取数据

参数shmid:共享内存的id号

参数shmaddr:被共享内存所映射的进程内存的首地址(如果该参数被传0(一般传0),系统会自动选择一段合适的内存(不太会被使用的一段内存)进行映射)

参数shmflg:有以下两种常用选项:

0:表示共享内存可读可写

SHM_RDONLY:共享内存只读

返回值:获取成功,则返回共享内存映射的地址,获取失败,则返回-1

写入/读取共享内存

练习

共享内存的同步。

1#

#include <stdio.h>
#include <string.h>
#include <stdlib.h>	
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;typedef struct share
{char arr[128];int flag1;int flag2;
}s;int main(int argc, const char *argv[])
{key_t key=ftok("./share",1);int shmid=shmget(key,sizeof(s),IPC_CREAT | 0666);s* addr = (s*)shmat(shmid,0,0);addr->flag1=0;while(1){if(addr->flag1==0){printf("1#请输入:");scanf("%s",addr->arr);while(getchar()!=10);addr->flag1++;}}return 0;
}

2#

#include <stdio.h>
#include <string.h>
#include <stdlib.h>	
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;typedef struct share
{char arr[128];int flag1;int flag2;
}s;int main(int argc, const char *argv[])
{key_t key=ftok("./share",1);int shmid=shmget(key,sizeof(s),IPC_CREAT | 0666);s* addr = (s*)shmat(shmid,0,0);while(1){if(addr->flag1==1){printf("读取1#的数据=%s\n",addr->arr);addr->flag1--;}}return 0;
}

两个终端间的互相聊天。

1#

#include <stdio.h>
#include <string.h>
#include <stdlib.h>	
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;typedef struct share
{char arr[128];int flag1;int flag2;
}s;s* addr;void* task(void* arg)
{while(1){if(addr->flag2==1){printf("读取2#的数据=%s\n",addr->arr);addr->flag2--;}}
}int main(int argc, const char *argv[])
{key_t key=ftok("./share",1);int shmid=shmget(key,sizeof(s),IPC_CREAT | 0666);addr = (s*)shmat(shmid,0,0);pthread_t id;pthread_create(&id,0,task,0);pthread_detach(id);addr->flag1=0;while(1){if(addr->flag1==0){printf("1#请输入:");scanf("%s",addr->arr);while(getchar()!=10);addr->flag1++;}}return 0;
}

2#

#include <stdio.h>
#include <string.h>
#include <stdlib.h>	
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;typedef struct share
{char arr[128];int flag1;int flag2;
}s;s* addr;void* task(void* arg)
{addr->flag2=0;while(1){if(addr->flag2==0){printf("2#请输入:");scanf("%s",addr->arr);while(getchar()!=10);addr->flag2++;}}
}int main(int argc, const char *argv[])
{key_t key=ftok("./share",1);int shmid=shmget(key,sizeof(s),IPC_CREAT | 0666);addr = (s*)shmat(shmid,0,0);pthread_t id;pthread_create(&id,0,task,0);pthread_detach(id);while(1){if(addr->flag1==1){printf("读取1#的数据=%s\n",addr->arr);addr->flag1--;}}return 0;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com