赞
踩
进程间通信(IPC)的概念:进程间通信是指在不同进程间进行信息传输或交换,IPC的方式通常有管道,消息队列,信号量,共享存储,Socket,Stream等
无名管道,UNIX系统最古老的形式
特点:①.半双工,具有固定的读写
②:只能用于父子进程和兄弟进程
③:.可以看做是一种普通文件,他的读写可以用read和write等函数,但不是普通文件,他只存在于内存当中。
- #include <stdio.h>
- #include <unistd.h>
- #include <string.h>
- #include <stdlib.h>
-
- int main(){
- int fd[2];
- char buf[128];
- int pid;
- char *writeData = "this is write_data";
- if(pipe(fd) == -1){
- printf("pipe create failed!\n");
- }
-
- pid = fork();
-
- if(pid == 0){
- sleep(1);
- close(fd[1]);
- read(fd[0],buf,128);
- printf("read data: %s\n",buf);
- exit(0);
- }
- close(fd[0]);
- write(fd[1],writeData,strlen(writeData));
- wait(NULL);
- return 0;
- }

有名管道
函数有:
mkfifo(path,mod); 创建管道
path路径名,mod模式
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <errno.h>
- #include <stdlib.h>
-
- int main(){
- if(mkfifo("./file",0600)==-1 && errno == EEXIST){
- printf("mkfifo failed!\n");
- perror("why");
- exit(0);
- }
- printf("mkfifo success!\n");
- return 0;
- }
这是以创建一个文件来进行管道传输的,使用这个有名管道进行通信时,要么读,要么写,不能同时
读的代码:
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <errno.h>
- #include <stdlib.h>
- #include <fcntl.h>
-
- int main(){
- char buf[30]={0};
- int n_read;
- int fd = open("./file",O_RDONLY);
- printf("open success\n");
- n_read = read(fd,buf,30);
- while(n_read > 0){
- sleep(1);
- n_read = read(fd,buf,30);
- printf(buf);
- }
- close(fd);
- return 0;
- }

写的代码
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <errno.h>
- #include <stdlib.h>
- #include <fcntl.h>
- #include <string.h>
- int main(){
- int i;
- char *str = "this is write data\n";
- int fd = open("./file",O_WRONLY);
- printf("open success\n");
- for(i = 0; i<5;i++){
- write(fd,str,strlen(str));
- }
- close(fd);
- return 0;
- }

3.消息队列,是消息的链接表,存放在内核中,一个消息队列由一个标识符即队列ID来标识。
特点:1.消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级
2.消息队列独立于发送与接收进程,进程终止时,消息队列及其内容并不会被删除。
3.消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。
创建队列msgget
接收消息 msgrcv
发送消息 msgsnd
操作队列msgctl
收发消息的函数原型
- int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
-
- ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
代码demo6
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
- #include <string.h>
-
- /*
- int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
- ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
- int msgflg);*
- */
-
- struct msgbuf {
- long mtype; /* message type, must be > 0 */
- char mtext[128]; /* message data */
- };
-
-
- int main(){
- key_t key = ftok(".",1);
- int msgId;
- struct msgbuf msgread;
- //创建队列
- if(msgId = msgget(key,IPC_CREAT|0700) == -1){
- printf("create queue failed\n");
- }
- //接收消息
- msgrcv(msgId,&msgread,sizeof(msgread.mtext),888,0);
- printf("receive:%s\n",msgread.mtext);
-
- //再发消息
- struct msgbuf msgsend = {999,"thanks!"};
- msgsnd(msgId,&msgsend,strlen(msgsend.mtext),0);
- //删除队列
- msgctl(msgId,IPC_RMID,NULL);
- return 0;
- }

代码demo7
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
- #include <string.h>
-
- /*
- nt msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
- ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
- int msgflg);*
- */
-
- struct msgbuf {
- long mtype; /* message type, must be > 0 */
- char mtext[128]; /* message data */
- };
-
-
- int main(){
- key_t key = ftok(".",1);
- int msgId;
- struct msgbuf msgwrite = {888,"aaa"};
- //创建队列
- if(msgId = msgget(key,IPC_CREAT|0700) == -1){
- printf("create queue failed\n");
- }
- //发送消息
- msgsnd(msgId,&msgwrite,strlen(msgwrite.mtext),0);
- //再接收消息
- struct msgbuf msgrece;
- msgrcv(msgId,&msgrece,sizeof(msgrece.mtext),999,0);
- printf("rece:%s\n",msgrece.mtext);
- //删除队列
- msgctl(msgId,IPC_RMID,NULL);
- return 0;
- }

4.共享内存
//创建或获取一个共享内存,成功则返回ID,失败返回-1
//映射共享内存(连接当前进程的地址空间和共享内存,成功返回指向共享内存的指针,失败返回-1)
//写入东西,就相当于直接copy内容到当前进程的映射地址即可
//断开连接共享内存
//删除共享内存
下面这两个是命令行指令
ipcs -m 在控制台能够查看现在共享内存的使用情况,
ipcrm -m XX 删除shmid == XX的这个共享内存
5.信号
5.1信号低级版
有分低级版和高级版
低级版就是没有进行消息的传输
代码如下
demo10,对命令行命令kill进行替换 ,可以使用kill -l 查看详细的对应字段
- #include <stdio.h>
- #include <signal.h>
-
- void handler(int signum){
- printf("input sinnum is : %d",signum);
- switch(signum){
- case 2:
- printf("SIGINT\n");
- break;
- case 9:
- printf("SIGKILL\n");
- break;
- case 10:
- printf("SIGUSR1\n");
- break;
- }
-
- printf("can't kill\n");
-
- }
-
-
- int main(){
- signal(SIGINT,handler);
- signal(SIGKILL,handler);
- signal(SIGUSR1,handler);
- while(1);
- return 0;
- }

demo11 ,下面的代码功能是,运行程序时传入signum和pid参数,对应的是你要在命令行执行的
kill -XX XX的指令 例如 kill -2 进程ID,原本执行的功能是中断,但替换后不会执行原有功能,而是执行我们自己编写的handler的功能
- #include <stdio.h>
- #include <signal.h>
- #include <sys/types.h>
-
- int main(int argc,char **argv){
- int signum;
- int pid;
- char cmd[128] = {0};
-
- //这里要把数组里的字符串转换为int,用atoi char to int
- signum = atoi(argv[1]);
- pid = atoi(argv[2]);
-
- sprintf(cmd,"kill -%d %d",signum,pid);
- printf(cmd);
- system(cmd);
- return 0;
- }

5.2信号高级版
就是加入的消息的传输,个人认为有点操蛋。直接上代码吧。
函数原型
- //函数原型
- //int sigaction(int signum, const struct sigaction *act,
- // struct sigaction *oldact);
-
- /**
- *
- *struct sigaction {
- void (*sa_handler)(int);
- void (*sa_sigaction)(int, siginfo_t *, void *);
- sigset_t sa_mask;
- int sa_flags;
- void (*sa_restorer)(void);
- };
- */
具体使用代码
接收端:
- #include <stdio.h>
- #include <signal.h>
- #include <stdlib.h>
-
-
- void handler(int signum,siginfo_t *info,void *context){
- printf("get signum : %d\n",signum);
- if(context != NULL){
- printf("siginfo1 : %d\n",info->si_int);
- printf("siginfo2 : %d\n",info->si_value.sival_int);
- }
- }
-
- int main(){
- struct sigaction act;
- act.sa_sigaction = handler;
- act.sa_flags = SA_SIGINFO;
-
- sigaction(SIGUSR1,&act,NULL);
- while(1);
- return 0;
- }

发送端:
- #include <stdio.h>
- #include <signal.h>
-
- int main(int argc,char **argv){
- int signum;
- int pid;
- signum = atoi(argv[1]);
- pid = atoi(argv[2]);
-
- union sigval value;
- value.sival_int = 100;
-
- sigqueue(pid,signum,value);
- printf("over\n");
- return 0;
- }

6.信号量集
①信号量用于进程间同步,若要在进程间传递胡数据需要结合共享内存。
②信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作。(P操作:拿锁。V操作:放回锁)
③每次对信号量的 PV 操作不仅限于对信号量值加 1 或 减1 ,而且可以加加减任意正整数。
④支持信号量组。
- //创建或获取一个信号量组,成功会返回信号量集 ID ,失败返回 -1
- int semget(key_t key, int nsems, int semflg);
- //对信号量组进行操作,改变信号量的值,成功返回 0,失败返回 -1 (用于 PV 操作)
- int semop(int semid, struct sembuf *sops, unsigned nsops);
- //控制信号量的相关信息 (用于给信号量初始化)
- int semctl(int semid, int semnum, int cmd, ...);
示例代码:
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/sem.h>
- #include <stdlib.h>
- //int semget(key_t key, int nsems, int semflg);
-
-
-
-
- union semun {
- int val; /* Value for SETVAL */
- struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
- unsigned short *array; /* Array for GETALL, SETALL */
- struct seminfo *__buf; /* Buffer for IPC_INFO
- (Linux-specific) */
- };
-
- //
- 对信号量组进行操作,改变信号量的值,成功返回 0,失败返回 -1 (用于 PV 操作)
- //int semop(int semid, struct sembuf *sops, unsigned nsops);
-
- //拿锁
- void getKey(int semid){
- struct sembuf mysem1;
- mysem1.sem_num = 0;
- mysem1.sem_op = -1;
- mysem1.sem_flg = SEM_UNDO;
- semop(semid,&mysem1,1);
- printf("getkey\n");
- }
- //还锁
- void putKey(int semid){
- struct sembuf mysem1;
- mysem1.sem_num = 0;
- mysem1.sem_op = 1;
- mysem1.sem_flg = SEM_UNDO;
- semop(semid,&mysem1,1);
- printf("putKey\n");
- }
- int main(){
- //创建一个信号量集
- key_t key;
-
- int semid = semget(key,0,IPC_CREAT|0700);
-
- //int semctl(int semid, int semnum, int cmd, ...);
- //初始化信号量集
- union semun initsem;
- initsem.val = 0;
- semctl(semid,0,SETVAL,initsem);
-
- //用父子进程来操作这个信号量
- int pid = fork();
- if(pid == 0){
- printf("this is son\n");
- //拿锁
- getKey(semid);
- exit(0);
- }
- printf("this is father\n");
- //还锁
- putKey(semid);
- wait();
- //拿锁
- getKey(semid);
- //还锁
- putKey(semid);
- return 0;
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。