进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息。
IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams等。其中 Socket和Streams支持不同主机上的两个进程IPC
1.半双工,具有固定的写端和读端
2.只能用与具有亲缘关系的进程之间的通信(父子进程和兄弟进程之间)
3.可以看成一种特殊的文件,不属于其他任何文件系统,只存在于内存中
4.管道中的数据读走就没了
int pipe(int pipefd[2])
返回值:成功返回0,失败返回-1
fd[0]:读端,为读而打开
fd[1]:写端,为写而打开
关闭管道:关闭读端和写端
使用write函数进行写入,使用read函数进行读出,使用close函数关闭
- #include <stdio.h>
- #include <unistd.h>
- #include <string.h>
- #include <stdlib.h>
- int main()
- {
- int fd[2];
-
- int pid;
-
- char buf[128];
-
- // int pipe(int pipefd[2]);
-
- if(pipe(fd) == -1){
- printf("creat pipe failed\n");
- }
- pid = fork();
-
- if(pid<0){
- printf("creat child failed\n");
- }
- else if(pid > 0){
- sleep(3);
- printf("this is father\n");
-
- close(fd[0]);
- write(fd[1],"hello from father",strlen("hello form father"));
- wait();
- }else{
- printf("this is child\n");
- close(fd[1]);
- read(fd[0],buf,128);
- printf("read from father: %s\n",buf);
- exit(0);
- }
-
-
- return 0;
- }
1.可以在无关的进程之间交换数据
2.有路径名,以一种特别设备文件形式存在于文件系统中,可以用一般的文件I/O函数操作
int mkfifo(const char *pathname, mode_t mode);
返回值:成功返回0,失败返回-1
write.c
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <stdio.h>
- #include<errno.h>
- #include <fcntl.h>
- #include <string.h>
-
- // int mkfifo(const char *pathname, mode_t mode);
- int main()
- {
- int cnt = 0;
- char *str = "message from fifo";
-
- if( (mkfifo("./file",IPC_CREAT|0600) == -1) && errno!=EEXIST){
- printf("mkfifo failuer\n");
- perror("why");
- }
-
- int fd = open("./file",O_WRONLY);
- printf("write open success\n");
-
- while(1){
-
- write(fd, str, strlen(str));
- sleep(1);
- if(cnt == 5){
- break;
- }
- }
- close(fd);
- return 0;
- }
-
-
read.c
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <stdio.h>
- #include<errno.h>
- #include <fcntl.h>
-
- // int mkfifo(const char *pathname, mode_t mode);
- int main()
- {
- char buf[30] = {0};
- int nread = 0;
-
-
- if( (mkfifo("./file",0600) == -1) && errno!=EEXIST){
- printf("mkfifo failuer\n");
- perror("why");
- }
-
- int fd = open("./file",O_RDONLY);
- printf("open success\n");
-
- while(1){
- nread = read(fd,buf,30);
-
- printf("read %d byte from fifo,context:%s\n",nread,buf);
- }
- close(fd);
- return 0;
- }
-
-
1.消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先权
2.消息队列对立与发送与接收进程,进程终止时,消息队列及其内容并不会被删除
3.消息队列可以实现消息的随即查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取
1.创建或打开消息队列
int msgget(key_t key, int msgflg);
返回值:成功返回队列ID,失败返回-1
2.添加消息
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
返回值:成功返回0,失败返回-1
3.读取消息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
返回值:成功返回消息数据的长度,失败返回-1
4.控制消息队列
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
返回值:成功返回0,失败返回-1
msgget创建一个新队列:
1.如果没有与键值key对应的消息队列,并且flag中包含了IPC_CREAT标志位
2.key参数为IPC_PRIVATE,创建一个私有消息队列
msgrcv在读取时的type参数
| type | 含义 |
| ==0 | 返回消息队列中的第一个消息 |
| >0 | 返回队列中消息类型为type的第一个消息 |
| <0 | 返回队列中消息类型值小于或等于type绝对值的消息,如果有多个,则取类型值最小的消息 |
msgSend.c
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
- #include <string.h>
- // int msgget(key_t key, int msgflg);
- // 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[256]; /* message data */
- };
-
-
- int main()
- {
- //1.huoqu
- struct msgbuf sendBuf = {888,"this is message from quen"};
- struct msgbuf readBuf;
-
- memset(&readBuf,0,sizeof(struct msgbuf));
- key_t key;
- key = ftok(".",'m');
- printf("key=%x\n",key);
-
- int msgId = msgget(key, IPC_CREAT|0777);
-
- if(msgId == -1 ){
- printf("get que failuer\n");
- }
-
- msgsnd(msgId,&sendBuf,strlen(sendBuf.mtext),0);
- printf("send over\n");
-
- msgrcv(msgId, &readBuf,sizeof(readBuf.mtext),988,0);
- printf("reaturn from get:%s\n",readBuf.mtext);
-
- msgctl(msgId,IPC_RMID,NULL);
-
- return 0;
- }
msgGet.c
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
- #include <string.h>
- // int msgget(key_t key, int msgflg);
- // 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[256]; /* message data */
- };
-
-
- int main()
- {
- //1.huoqu
- struct msgbuf readBuf;
-
-
- key_t key;
- key = ftok(".",'m');
- printf("key=%x\n",key);
-
- int msgId = msgget(key, IPC_CREAT|0777);
- if(msgId == -1 ){
- printf("get que failuer\n");
- }
- memset(&readBuf,0,sizeof(struct msgbuf));
-
- msgrcv(msgId, &readBuf,sizeof(readBuf.mtext),888,0);
- printf("read from que:%s\n",readBuf.mtext);
-
- struct msgbuf sendBuf = {988,"thank you for reach"};
- msgsnd(msgId,&sendBuf,strlen(sendBuf.mtext),0);
-
- msgctl(msgId,IPC_RMID,NULL);
-
- return 0;
- }
共享内存大小以M对齐
1.创建或获取一个共享内存
int shmget(key_t key, size_t size, int shmflg);
返回值:成功返回共享内存ID,失败返回-1
2.连接共享内存到当前进程的地址空间
void *shmat(int shmid, const void *shmaddr, int shmflg);
返回值:成功返回指向共享内存的指针,失败返回-1
shmflg = 0即为可读可写
shmaddr = 0即让内存分配共享空间
3.断开与共享内存的连接
int shmdt(const void *shmaddr);
返回值:成功返回0,失败返回-1
4.控制共享内存的相关信息
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
返回值:成功返回0,失败返回-1
ipcs -m:查看系统中有哪些共享内存
ipcrm -m 共享内存ID :删除共享内存
shmw.c
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
-
- //int shmget(key_t key, size_t size, int shmflg);
- int main()
- {
-
- int shmid;
- char *shmaddr;
-
-
- key_t key;
- key = ftok(".",1);
-
- shmid = shmget(key,1024*4,IPC_CREAT|0666);
- if(shmid == -1){
- printf("shmget noOk\n");
- exit(-1);
- }
- shmaddr = shmat(shmid,0,0);
-
- printf("shmat ok\n");
- strcpy(shmaddr,"chenlichen");
-
- sleep(5);
- shmdt(shmaddr);
- shmctl(shmid, IPC_RMID, 0);
-
- printf("quit\n");
-
- return 0;
- }
shmr.c
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
-
- //int shmget(key_t key, size_t size, int shmflg);
- int main()
- {
-
- int shmid;
- char *shmaddr;
-
-
- key_t key;
- key = ftok(".",1);
-
- shmid = shmget(key,1024*4,0);
- if(shmid == -1){
- printf("shmget noOk\n");
- exit(-1);
- }
- shmaddr = shmat(shmid,0,0);
-
- printf("shmat ok\n");
- printf("data: %s\n:",shmaddr);
-
- shmdt(shmaddr);
-
- printf("quit\n");
-
- return 0;
- }
kill -l:查看系统中所有信号
信号处理:忽略、捕捉或默认动作
SIGKILL、SIGSTOP不可忽略
1.信号处理函数的注册
sighandler_t signal(int signum, sighandler_t handler);
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
忽略信号:SIG_IGN
kill -信号id 进程号:给指定进程发送指定信号
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *); //最后一个参数非空为有数据,为空就是没数据
sigset_t sa_mask; //默认阻塞,处理一个信号
时不处理其他信号
int sa_flags; //SA_SIGINFO:收数据
};
2.信号发送函数
int kill(pid_t pid, int sig);
int sigqueue(pid_t pid, int sig, const union sigval value);
union sigval {
int sival_int;
void *sival_ptr;
};
signalDemo1.c
- #include
- #include
-
- // typedef void (*sighandler_t)(int);
-
- // sighandler_t signal(int signum, sighandler_t handler);
-
- void handler(int signum)
- {
- printf("get signum=%d\n",signum);
- switch(signum){
- case 2:
- printf("SIGINT\n");
- break;
- case 9:
- printf("SIGKILL\n");
- break;
- case 10:
- printf("SIGUSR1\n");
- break;
-
- }
-
-
-
-
- printf("never quit\n");
- }
-
- int main()
- {
- signal(SIGINT,SIG_IGN);
- signal(SIGKILL,SIG_IGN);
- signal(SIGUSR1,handler);
- while(1);
- return 0;
- }
-
-
signalDemo1CON.c
- #include
- #include
- #include
-
-
- int main(int argc ,char **argv)
- {
- int signum;
- int pid;
-
- char cmd[128]={0};
-
- signum = atoi(argv[1]);
- pid = atoi(argv[2]);
-
- printf("num=%d,pid=%d\n",signum,pid);
-
- // kill(pid, signum);
- sprintf(cmd,"kill -%d %d",signum,pid);
-
-
- system(cmd);
-
- printf("send signal ok");
- return 0;
- }
-
-
NiceSignal.c
- #include <signal.h>
- #include <stdio.h>
-
- // int sigaction(int signum, const struct sigaction *act,
- // struct sigaction *oldact);
-
- void handler(int signum , siginfo_t *info, void *context)
- {
- printf("get signum %d\n",signum);
-
- if(context != NULL){
-
- printf("from:%d\n",info->si_pid);
- // printf("get data=%d\n",info->si_int);
- // printf("get data=%d\n",info->si_value.sival_int);
- // printf("get data=%s\n",context);
- printf("get data=%d\n",*(int *)(info->si_value.sival_ptr));
- }
- }
-
- int main()
- {
- struct sigaction act;
- printf("pid = %d\n",getpid());
-
- act.sa_sigaction = handler;
- act.sa_flags = SA_SIGINFO; //be able to get message
-
-
- sigaction(SIGUSR1,&act,NULL);
- while(1);
- return 0;
-
- }
-
sendSignal.c
- #include
- #include
- #include
- #include
- #include
-
- // int sigqueue(pid_t pid, int sig, const union sigval value)
-
- int main(int argc, char **argv)
- {
- int signum;
- int pid;
- union sigval value;
-
- signum = atoi(argv[1]);
- pid = atoi(argv[2]);
- value.sival_int = 100;
-
- sigqueue(pid,signum,value);
-
- printf("%d,done\n",getpid());
-
- return 0;
- }
信号量是一个计数器,用于实现进程间的互斥与同步,而不是用于存储进程间通信数据
1.信号量用于进程间同步,若要在进程间传递数据需结合共享内存
2.信号量基于操作系统的PV操作,程序对信号量的操作都是原子操作
3.每次对信号量的PV操作不仅限于对信号量值加1或减1,而且可以加减任意正整数
4.支持信号量组
1.创建或获取一个信号量组
int semget(key_t key, int nsems, int semflg);
返回值:返回成功返回信号量集ID,失败返回-1
2.对信号量组进行操作
int semop(int semid, struct sembuf *sops, size_t nsops);
返回值:成功返回0,失败返回-1
3.控制信号量的相关信息
int semctl(int semid, int semnum, int cmd, ...);
返回值:成功返回0,失败返回-1
P操作:取信号量
V操作:存信号量
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/sem.h>
- #include <unistd.h>
-
- // int semget(key_t key, int nsems, int semflg);
- // int semctl(int semid, int semnum, int cmd, ...);
- // int semop(int semid, struct sembuf *sops, size_t nsops);
-
- 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) */
- };
-
- void pHandler(int semid)
- {
- struct sembuf sop;
-
- sop.sem_num = 0;
- sop.sem_op = -1;
- sop.sem_flg = SEM_UNDO;
-
- semop(semid,&sop,1);
- printf("get key\n");
- }
-
- void vHandler(int semid)
- {
- struct sembuf sop;
-
- sop.sem_num = 0;
- sop.sem_op = 1;
- sop.sem_flg = SEM_UNDO;
-
- semop(semid,&sop,1);
- printf("put back key\n");
- }
-
- int main()
- {
- key_t key;
- int semid;
- union semun initsem;
- int pid;
-
- key = ftok(".",2);
- semid = semget(key,1,IPC_CREAT|0666);
-
- initsem.val = 0;
-
- semctl(semid,0,SETVAL,initsem);
-
- pid = fork();
- if(pid > 0){
- pHandler(semid);
- printf("this is father\n");
- vHandler(semid);
- semctl(semid,0,IPC_RMID);
- }else if(pid == 0){
- printf("this is child\n");
- vHandler(semid);
- }else{
- printf("fork falied\n");
- }
-
- return 0;
- }
send.c
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/sem.h>
- #include <sys/shm.h>
- #include <unistd.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) */
- };
-
- void pHandler(int semid)
- {
- struct sembuf sop;
-
- sop.sem_num = 0;
- sop.sem_op = -1;
- sop.sem_flg = SEM_UNDO;
-
- semop(semid,&sop,1);
- printf("get key\n");
- }
-
- void vHandler(int semid)
- {
- struct sembuf sop;
-
- sop.sem_num = 0;
- sop.sem_op = 1;
- sop.sem_flg = SEM_UNDO;
-
- semop(semid,&sop,1);
- printf("put back key\n");
- }
-
- int main()
- {
- key_t key;
- int semid;
- union semun initsem;
- int shmid;
- char *shm;
-
- key = ftok(".",3);
- semid = semget(key,1,IPC_CREAT|0666);
- printf("semid = %d\n",semid);
- initsem.val = 0;
- semctl(semid,0,SETVAL,initsem);
-
- shmid = shmget(key,1024*4,IPC_CREAT|0666);
- shm = shmat(shmid,0,0);
-
- sprintf(shm,"ccy handsome");
- vHandler(semid);
-
- sleep(5);
-
- pHandler(semid);
- printf("context:%s\n",shm);
- vHandler(semid);
-
- shmdt(shm);
- shmctl(shmid,IPC_RMID,NULL);
-
- return 0;
- }
read.c
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/sem.h>
- #include <sys/shm.h>
- #include <unistd.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) */
- };
-
- void pHandler(int semid)
- {
- struct sembuf sop;
-
- sop.sem_num = 0;
- sop.sem_op = -1;
- sop.sem_flg = SEM_UNDO;
-
- semop(semid,&sop,1);
- printf("get key\n");
- }
-
- void vHandler(int semid)
- {
- struct sembuf sop;
-
- sop.sem_num = 0;
- sop.sem_op = 1;
- sop.sem_flg = SEM_UNDO;
-
- semop(semid,&sop,1);
- printf("put back key\n");
- }
-
- int main()
- {
- key_t key;
- int semid;
- union semun initsem;
- int shmid;
- char *shm;
-
- key = ftok(".",3);
- semid = semget(key,1,IPC_CREAT|0666);
- printf("semid = %d\n",semid);
- initsem.val = 0;
- semctl(semid,0,SETVAL,initsem);
-
- shmid = shmget(key,1024*4,IPC_CREAT|0666);
- shm = shmat(shmid,0,0);
- pHandler(semid);
- printf("context:%s\n",shm);
- vHandler(semid);
-
- pHandler(semid);
- sprintf(shm,"thank you for using");
- vHandler(semid);
-
- shmdt(shm);
- shmctl(shmid,IPC_RMID,NULL);
-
- return 0;
- }