1.信号
信号是比较复杂的通信方式,用于通知接收进程有某种事情发生,除了用于进程间通信外,进程还可以发送信号给进程本身;linux除了支持Unix早期信息语义函数signal外,还支持语义符合Posix 1标准的信号函数sigaction。
- signal() 告诉系统内核怎么处理该信号
- sigaction() 也是处理信号,但比signal更健壮
- kill() 发送信号
- alarm() 经过预定时间后发送SIGALARM信号
2.mmap文件映射:
也是一种共享内存,但是它是直接映射到磁盘中具体的文件,会涉及到磁盘的读写和io占用,不如shm共享内存效率高,但因为它的实际存储并没有反映到内存上,可以申请比较大的存储空间。
3.管道及有名管道
管道可用于具有亲缘关系进程间的通信,例如父子进程,但是有名管道允许无关系的进程间通信。管道其实就是建立一个FIFO文件,一个进程往里面写数据,另外的进程读取数据。
demo如下:
#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/wait.h> #include <stdlib.h> void sys_err(const char *str) { perror(str); exit(1); } int main() { pid_t pid; char buf[1024]; int fd[2]; char *p = "test for pipe\n"; if (pipe(fd) == -1) sys_err("pipe"); pid = fork(); if (pid < 0) { sys_err("fork err"); } else if(pid == 0) { //父进程 close(fd[1]); int len = read(fd[0], buf, sizeof(buf)); write(STDOUT_FILENO, buf, len); //输出到屏幕 close(fd[0]); } else { //子进程 close(fd[0]); write(fd[1], p, strlen(p)); //写入test for pipe wait(NULL); close(fd[1]); } return 0; }
4.消息队列
消息队列也叫报文队列,消息队列是消息的链接表,包括Posix消息队列和SystemV消息队列,有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的信息,消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
发送消息demo如下:
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> struct my_msg_st { long int my_msg_type; char some_text[BUFSIZ]; }; int main(void) { int running = 1; struct my_msg_st some_data; int msgid = 0; char buffer[BUFSIZ] = {0}; memset((void*)&some_data, 0, sizeof(some_data)); /*创建消息队列*/ msgid=msgget((key_t)1234,0666 | IPC_CREAT); if(msgid==-1) { fprintf(stderr,"msgget failed with error:%d\n",errno); exit(EXIT_FAILURE); } /*循环向消息队列中添加消息*/ while(running) { memset(buffer, 0, sizeof(buffer)); printf("Enter some text:"); fgets(buffer,BUFSIZ,stdin); some_data.my_msg_type=1; strcpy(some_data.some_text,buffer); /*添加消息*/ if(msgsnd(msgid,(void *)&some_data,BUFSIZ,0)==-1) { fprintf(stderr,"msgsed failed\n"); exit(EXIT_FAILURE); } /*用户输入的为“end”时结束循环*/ if(strncmp(buffer,"end",3)==0) { running=0; } } exit(EXIT_SUCCESS); }
接收消息demo如下:
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> struct my_msg_st { long int my_msg_type; char some_text[BUFSIZ]; }; int main(void) { int running=1; int msgid = 0; struct my_msg_st some_data; long int msg_to_receive=0; memset((void*)&some_data, 0, sizeof(some_data)); /*创建消息队列*/ msgid=msgget((key_t)1234,0666 | IPC_CREAT); if(msgid==-1) { fprintf(stderr,"msgget failed with error: %d\n",errno); exit(EXIT_FAILURE); } /*循环从消息队列中接收消息*/ while(running) { /*读取消息*/ if(msgrcv(msgid,(void *)&some_data,BUFSIZ,msg_to_receive,0)==-1) { fprintf(stderr,"msgrcv failed with error: %d\n",errno); exit(EXIT_FAILURE); } printf("接收到的消息为: %s",some_data.some_text); /*接收到的消息为“end”时结束循环*/ if(strncmp(some_data.some_text,"end",3) == 0) { running=0; } } /*从系统内核中移走消息队列*/ if(msgctl(msgid,IPC_RMID,0) == -1) { fprintf(stderr,"msgctl(IPC_RMID) failed\n"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }
5.共享内存
共享内存是一种文件映射,使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其他通信机制,如信号量结合使用,来达到进程间的同步及互斥。
demo如下:
写入共享内存:
#include<stdlib.h> #include <sys/ipc.h> #include <sys/shm.h> #include<string.h> #include<errno.h> typedef struct _Teacher { char name[64]; int age; }Teacher; int main(int argc, char *argv[]) { int ret = 0; int shmid = 0; //创建共享内存 ,相当于打开文件,文件不存在则创建 shmid = shmget(0x2234, sizeof(Teacher), IPC_CREAT | 0666); if (shmid == -1) { perror("shmget err"); return errno; } printf("shmid:%d \n", shmid); Teacher *p = NULL; //将共享内存段连接到进程地址空间 p = (Teacher*)shmat(shmid, NULL, 0);//第二个参数shmaddr为NULL,核心自动选择一个地址 if (p == (void *)-1 ) { perror("shmget err"); return errno; } strcpy(p->name, "aaaa"); p->age = 33; //将共享内存段与当前进程脱离 shmdt(p); printf("键入1 删除共享内存,其他不删除\n"); int num = 0; scanf("%d", &num); if (num == 1) { //用于控制共享内存 ret = shmctl(shmid, IPC_RMID, NULL);//IPC_RMID为删除内存段 if (ret < 0) { perror("rmerrr\n"); } } return 0; }
从共享内存读取:
#include<stdio.h> #include <unistd.h> #include<stdlib.h> #include <sys/ipc.h> #include <sys/shm.h> #include<string.h> #include<errno.h> typedef struct _Teacher { char name[64]; int age; }Teacher; int main(int argc, char *argv[]) { int ret = 0; int shmid = 0; //打开获取共享内存 shmid = shmget(0x2234, 0, 0); if (shmid == -1) { perror("shmget err"); return errno; } printf("shmid:%d \n", shmid); Teacher *p = NULL; //将共享内存段连接到进程地址空间 p = (Teacher*)shmat(shmid, NULL, 0); if (p == (void *)-1 ) { perror("shmget err"); return errno; } printf("name:%s\n", p->name); printf("age:%d \n", p->age); //将共享内存段与当前进程脱离 shmdt(p); printf("键入1 程序暂停,其他退出\n"); while(1) { sleep(1); } return 0; }
6.socket
socket也就是套接字,最普遍的进程间通信机制,可用于不同机器之间的进程间通信,具体见网络编程。