嵌入式Linux进程间的通信方式

2019-07-12 16:24发布

【1】分类
早期进程间通信方式:
无名管道
有名管道
信号通信

system V
消息队列
共享内存
信号灯集

BSD
scoket(套接字)通信 【2】本质
任何一个进程在32位操作里面都会有4G的虚拟空间,包含1G内核空间和3G用户空间,进程间能够通信,就是在内核空间进行读写数据。 共享内存效率最高,它是直接获取到物理内存的地址,对物理内存直接操作。 前六种进程间通信方式只能实现在同一台主机的多个进程之间通信,而套接字通信可以实现在不同的主机的进程之间通信 【3】无名管道
(1)性质
只能用于具有亲缘关系的进程之间的通信,半双工的通信模式,具有固定的读端和写端。 管道可以看成是一种特殊的文件,对于它的读写可以使用文件IO如read、write函数。 管道是基于文件描述符的通信方式
当一个管道建立时,它会创建两个文件描述符fd[0]和fd[1]。
fd[0]固定用于读管道,fd[1]固定用于写管道。 (2)创建无名管道 #include
int pipe(int fd[2]); 功能:创建一个无名管道
参数
fd:操作无名管道的数组,有两个成员,第一个负责读,第二个负责写
返回值
成功:0
失败:-1 #include #include #include int main(int argc, const char *argv[]) { //创建一个无名管道 int fd[2]; if(pipe(fd) < 0) { perror("fail to pipe"); exit(1); } //printf("fd[0] = %d ", fd[0]); //printf("fd[1] = %d ", fd[1]); //无名管道可以使用文件io的函数直接操作 //read write //fd[1]负责写数据 //往无名管道写数据,下一次写的数据会放在第一个写的后面,以追加的方式写数据 char s1[32] = "hello world"; char s2[32] = "nihao beijing"; write(fd[1], s1, sizeof(s1)); write(fd[1], s2, sizeof(s1)); //fd[0]负责读数据 //从无名管道读取数据,读取的数据会从无名管道里面删除 char buf[32] = {}; read(fd[0], buf, sizeof(buf)); printf("buf = %s ", buf); read(fd[0], buf, sizeof(buf)); printf("buf = %s ", buf); return 0; } (3)无名管道的读写规律
如果读写端都存在,如果只读不写,如果管道内有数据,会正常读取,但是如果没有数据,就会一直阻塞。 #include #include #include int main(int argc, const char *argv[]) { int fd[2]; if(pipe(fd) < 0) { perror("fail to pipe"); exit(1); } //如果读写端都存在,如果只读不写,如果管道内有数据,会正常读取,但是如果没有数据,就会一直阻塞 char s[32] = "hello world"; write(fd[1], s, sizeof(s)); char buf[32] = {}; read(fd[0], buf, sizeof(buf)); printf("buf = %s ", buf); read(fd[0], buf, sizeof(buf)); printf("buf = %s ", buf); return 0; } 如果读写端都存在,如果只写不读,当管道写满是,就会阻塞,默认无名管道64k字节。 #include #include #include int main(int argc, const char *argv[]) { int fd[2]; if(pipe(fd) < 0) { perror("fail to pipe"); exit(1); } //如果读写端都存在,如果只写不读,当管道写满是,就会阻塞,默认无名管道64k字节 char s[4] = "yes"; int n = 0; while(1) { write(fd[1], s, 4); n++; printf("n = %d ", n); } return 0; } 如果只有读端没有写端,如果管道内有数据,则正常读取,如果没有数据,则read返回0。 #include #include #include int main(int argc, const char *argv[]) { int fd[2]; if(pipe(fd) < 0) { perror("fail to pipe"); exit(1); } //如果只有读端没有写端,如果管道内有数据,则正常读取,如果没有数据,则read返回0 write(fd[1], "hello world", 32); close(fd[1]); char buf[32] = {}; ssize_t bytes; bytes = read(fd[0], buf, sizeof(buf)); printf("bytes = %d ", bytes); printf("buf = %s ", buf); bytes = read(fd[0], buf, sizeof(buf)); printf("bytes = %d ", bytes); printf("buf = %s ", buf); return 0; } 如果只有写端没有读端,当运行到write时,就会产生SIGPIPE(管道破裂),当前信号默认的处理方式是结束整个进程,所以程序直接退出。 #include #include #include int main(int argc, const char *argv[]) { int fd[2]; if(pipe(fd) < 0) { perror("fail to pipe"); exit(1); } //如果只有写端没有读端,当运行到write时,就会产生SIGPIPE(管道破裂), //当前信号默认的处理方式是结束整个进程,所以程序直接退出 close(fd[0]); char s[4] = "yes"; int n = 0; ssize_t bytes; while(1) { bytes = write(fd[1], s, 4); printf("bytes = %d ", bytes); n++; printf("n = %d ", n); } return 0; } 以下是父子进程,通过无名管道实现互相通信: #include #include #include #include #define N 32 int main(int argc, const char *argv[]) { int fd1[2], fd2[2]; if(pipe(fd1) < 0) { perror("fail to pipe"); exit(1); } if(pipe(fd2) < 0) { perror("fail to pipe"); exit(1); } pid_t pid; if((pid = fork()) < 0) { perror("fail to fork"); exit(1); } else if(pid > 0) //父进程 { //父进程先往管道写入数据 char buf[N] = {}; while(1) { fgets(buf, N, stdin); buf[strlen(buf) - 1] = '