其他进程间通信https://www.cnblogs.com/xiaoxiaolinux/p/13714608.html
XSI中有三种通信机制:消息队列、信号量数组、共享内存。可以用于有血缘关系的进程间通信,也可以用于无血缘关系的进程间通信。通过命令“ipcs”可以查看当前系统中有无这三种机制。如图所示,键(key)是保证无血缘关系的进程间通信的关键,是为了通信双方都能拿到同一个通信机制。
如何拿到key?
#include<sys/ipc.h> key_t ftok(const char*pathname,int id);//pathname是一个现有文件
1、message queue
几个关键的函数
#include<sys/msg.h> int msgget(ket_t key,int flag);//成功返回消息队列id,失败返回-1 //向消息队列发送数据 int msgsnd(int msgid,const void* ptr,size_t bytes,int flag);
//参数1,msgget的返回值,参数2,发送数据的结构体指针,参数3,数据的实际大小,
//参数4,可以指定非阻塞IPC_NOWAIT,如果消息队列已满,指定非阻塞可以使函数立即返回EAGAIN
//参数4,也可以指定MSG_NOERROR,如果消息过长可以截断为所指定的bytes //接受消息 size_t msgrcv(int msgid,void *ptr,size_t bytes,long type,int flag);
//参数2指向事先定义好的结构体,总体分为两部分,一是long型的mtype,二是message data //参数4可以指定接受哪一个数据包,由此可见,“消息队列”并非是“队列”,其余与上述类似 int msgctl(int msgid,int cmd,struct msqid_ds *buf); //cmd指定IPC_RMID表示删除消息队列
消息队列的消息结构。
struct msg { long mtype; //说明消息的类型 char text[521];//消息的数据部分 }
一个demo
协议部分
1 #ifndef _PROTO_H_ 2 #define _PROTO_H_ 3 4 #define PATHNAME "/etc/services" 5 #define KEYPROJ 'a' //产生key的材料 6 struct msg_st 7 { 8 long mtype; 9 char name[64]; 10 int chinese; 11 int math; 12 }; 13 #endif
接受方
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include"proto.h" 4 #include<sys/types.h> 5 #include<sys/ipc.h> 6 #include<sys/msg.h> 7 #include<signal.h> 8 int msgid; 9 //当按下ctrl+c时销毁消息队列 10 void func(int signum) 11 { 12 13 msgctl(msgid,IPC_RMID,NULL); 14 puts("cath"); 15 } 16 int main() 17 { 18 key_t key; 19 struct msg_st sbuf; 20 //注册一个信号捕捉函数 21 struct sigaction act; 22 act.sa_handler=func; 23 sigemptyset(&(act.sa_mask)); 24 act.sa_flags=0; 25 sigaction(SIGINT,&act,NULL); 26 //产生双方约定的key 27 key=ftok(PATHNAME,KEYPROJ); 28 if(key<0) 29 { 30 perror("ftok()"); 31 exit(1); 32 } 33 //先运行的一方创建消息队列 34 msgid=msgget(key,IPC_CREAT|0600); 35 if(msgid<0) 36 { 37 perror("magget()"); 38 exit(1); 39 } 40 while(1) 41 { 42 //从消息队列中取数据 43 if(msgrcv(msgid,&sbuf,sizeof(sbuf)-sizeof(long),0,0)<0) 44 { 45 perror("msgrcv()"); 46 exit(0); 47 } 48 printf("name=%s\n",sbuf.name); 49 printf("chinese=%d\n",sbuf.chinese); 50 printf("math=%d\n",sbuf.math); 51 52 } 53 54 exit(0); 55 56 }
发送方
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<sys/types.h> 4 #include"proto.h" 5 #include<string.h> 6 #include<sys/ipc.h> 7 int main() 8 { 9 key_t key; 10 struct msg_st buf; 11 //产生消息 12 buf.mtype=1; 13 strcpy(buf.name,"liming"); 14 buf.chinese=90; 15 buf.math=90; 16 17 key=ftok(PATHNAME,KEYPROJ); 18 if(key<0) 19 { 20 perror("ftok()"); 21 exit(1); 22 } 23 //接受方已经创建好了一个消息队列 24 int msgid=msgget(key,0); 25 if(msgid<0) 26 { 27 perror("magget()"); 28 exit(1); 29 } 30 if(msgsnd(msgid,&buf,sizeof(buf)-sizeof(long),0)<0) 31 { 32 perror("msgsnd()"); 33 exit(1); 34 } 35 puts("ok"); 36 exit(0); 37 }
2、semaphore arrays
信号量是一个计数器,用于为多个进程提供对共享数据的访问。常用的信号量是二元信号量,控制单个资源,初始值为1。XSI的信号量要指定信号量的数量和初始值。
几个重要的函数
#include<sys/sem.h> int semget(key_t key,int sems,int flag); //参数1,如果是血缘进程可以不用约定key,使用宏IPC_PRIVATE;参数2,信号量个数; //对信号量设初始值或者删除信号量 int semctl(int semid,int semnum,int cmd,....);//参数2 指定SETVAL/IPC_RMID //P、V操作由此函数完成 int semop(int semid,struct sembuf semoparray[] ,size_t nops);//c参数3,数组中操作的数量 struct sembuf { unsigned short sem_num; //信号量数组下标 short sem_op; //如果是正值,表示释放资源,如果是负值,表示想要获取资源 short sem_flg; //IPC_NOWAIT,SEM_UNDO }
一个demo
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<unistd.h> 4 #include<fcntl.h> 5 #include<sys/wait.h> 6 #include<sys/ipc.h> 7 #include<sys/types.h> 8 #include<sys/sem.h> 9 #include<errno.h> 10 static int semid; 11 static void P() 12 { 13 struct sembuf op; 14 op.sem_num=0; 15 op.sem_op=-1; 16 op.sem_flg=0; 17 while(semop(semid,&op,1)<0) 18 { 19 if(errno!=EINTR|| errno!=EAGAIN) 20 { 21 perror("semop error"); 22 exit(1); 23 } 24 } 25 } 26 static void V() 27 { 28 struct sembuf op; 29 op.sem_num=0; 30 op.sem_op=1; 31 op.sem_flg=0; 32 if(semop(semid,&op,1)<0) 33 { 34 perror("semop"); 35 exit(1); 36 } 37 } 38 static void func_add() 39 { 40 FILE *fp; 41 int fd; 42 char buf[BUFSIZ]; 43 fp=fopen("/tmp/out","r+"); 44 if(NULL==fp) 45 { 46 perror("fopen()"); 47 exit(1); 48 } 49 P(); 50 fgets(buf,BUFSIZ,fp); 51 fseek(fp,0,SEEK_SET); 52 fprintf(fp,"%d\n",atoi(buf)+1); 53 V(); 54 fclose(fp); 55 return ; 56 } 57 int main() 58 { 59 int i; 60 pid_t pid; 61 semid= semget(IPC_PRIVATE,1,0600);//有一个资源 62 if(semid<0) 63 { 64 perror("semget()"); 65 exit(1); 66 } 67 if(semctl(semid,0,SETVAL,1)<0) 68 { 69 perror("semctl()"); 70 exit(1); 71 }//初始化 72 //产生20个子进程对用一文件执行读写操作 73 for(i=0;i<20;i++) 74 { 75 pid=fork(); 76 if(pid==0) 77 { 78 func_add(); 79 exit(0); 80 } 81 if(pid<0) 82 { 83 perror("fork()"); 84 exit(1); 85 } 86 87 } 88 for(i=0;i<20;i++) 89 { 90 wait(NULL); 91 } 92 //删除信号量 93 semctl(semid,0,IPC_RMID); 94 exit(0); 95 }
3、共享内存
使用函数mmap创建的共享映射区是在多进程将一个文件映射到他们的地址空间。XSI共享内存不需要相关文件,XSI共享存储段是内存的匿名段。
几个重要的函数
#include<sys/shm.h> //获取共享存储标识符 int shmget(key_t key,size_t size,int flag); //进程调用此函数将共享存储段映射到他的地址空间中 void *shmat(int shmid,const void *addr,int flag);
//参数2默认填0,参数3如果指定SHM_RDONLY,以只读方式连接共享存储段 //与共享存储段分离 int shmdt(const void *addr); //对共享存储段操作,一般是删除该共享存储 int shmctl(int shmid,int cmd,struct shmid_ds* buf);
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<sys/wait.h> 5 #include<sys/ipc.h> 6 #include<sys/shm.h> 7 #include<unistd.h> 8 int main() 9 { 10 pid_t pid; 11 int shmid; 12 void* ptr; 13 shmid=shmget(IPC_PRIVATE,BUFSIZ,0600); 14 if(shmid<0) 15 { 16 perror("shmget()"); 17 exit(1); 18 } 19 pid=fork(); 20 if(pid<0) 21 { 22 perror("fork()"); 23 exit(1); 24 } 25 else if(pid==0) 26 { 27 ptr=shmat(shmid,NULL,0); 28 if(ptr==(void *)-1) 29 { 30 perror("shmat()"); 31 exit(1); 32 } 33 strcpy(ptr,"liming"); 34 shmdt(ptr); 35 exit(0); 36 }else 37 { 38 wait(NULL); 39 ptr=shmat(shmid,NULL,0); 40 if(ptr==(void*)-1) 41 { 42 perror("shmat"); 43 exit(1); 44 } 45 puts(ptr); 46 shmdt(ptr); 47 shmctl(shmid,IPC_RMID,NULL); //父进程负责销毁 48 exit(0); 49 50 } 51 }
在这个例子中,并没有调用ftok()来产生一个key,而指定一个匿名IPC,因为在具有血缘关系的两个进程通信并不关心key是多少,只要给我一个key能产生同一个id就行。