Linux进程通信(无名管道,有名管道,共享内存)的实现
2015-09-17 16:11
579 查看
Linux进程的通信有很多种方式,比如无名管道,有名管道,共享内存,Android进程通信采用的确是Binder机制~~~
在学习进程通信之前先学习一下System,Fork,Execive的机制,System调用的是另一个进程跟自己毫无关系 用的比较少。Fork创建的是父子进程,父进程的内存会被复制到
字进程的内存空间区别就是PID的不同。Execive调用的进程就会保留内存空间但是执行的是调用程序的代码。
首先看一下这三种创建进程的方法区别:
Execive:
重点看一下Fork机制:
这个案例会发现父子进程共享文件描述符,然后execve打印在控制台/dev/pts/1上
OK 理解了父子进程 进程创建的方式开始讲一下进程通信:
管道是管道文件,无名管道限于父子进程之间的通信,有名管道是任何两个进程的通信,共享内存也是。
无名管道通信如下:
有名管道需要通过命令mkfifo创建
案例如下:
下面将一些共享内存 首先通过
然后通过命令ipcs -m 查看共享内存的信息 返回共享内存的id
下面就是进程在自己内存开辟一块内存与共享内存进行关联,当进程在自己的内存中读写数据会同步到共享内存中(进程是不能直接操作共享内存的)
Ok 基本学习到此
在学习进程通信之前先学习一下System,Fork,Execive的机制,System调用的是另一个进程跟自己毫无关系 用的比较少。Fork创建的是父子进程,父进程的内存会被复制到
字进程的内存空间区别就是PID的不同。Execive调用的进程就会保留内存空间但是执行的是调用程序的代码。
首先看一下这三种创建进程的方法区别:
Execive:
#include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <errno.h> int main(void) { printf("start\n"); char* args[] = {"/bin/ls","-l",NULL}; execve("/bin/ls",args,NULL); printf("end\n"); return EXIT_SUCCESS; }执行到execive是内存空间会被/bin/ls占据,后面的打印语句就会被取消没有打印出来
重点看一下Fork机制:
#include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <errno.h> int main(int arg,char*args[]) { printf("begin\n"); pid_t child = fork(); if(child == -1) { return -1; } if(child == 0) { printf("is child\n"); printf("child pid = %d\n",getpid()); }else { printf("is parent\n"); printf("parent i pid = %d\n",getpid()); } printf("end\n"); return EXIT_SUCCESS; } ~
#include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <sys/wait.h> int main(int arg,char*args[]) { int status; pid_t child = fork(); if(child == -1) { return -1; } if(child == 0) { printf("child start\n"); sleep(5); printf("child end\n"); return 100; }else { printf("parent start\n"); wait(&status); printf("status = %d\n",WEXITSTATUS(status)); printf("parent end"); } printf("end\n"); return EXIT_SUCCESS; } ~父进程必须使用wait等待子进程结束掉才能关闭掉,通过status获得返回值,如果子进程死掉,父进程活着,子进程就会变成僵尸进程占据资源
nt main(int arg,char*args[]) { int status; pid_t child = fork(); if(child == -1) { return -1; } if(child == 0) { exit(0); }else { printf("parent start\n"); sleep(30); printf("parent end"); } printf("end\n"); return EXIT_SUCCESS; } ~ ~ ~ ~这个时候通过ps aux可以看到子进程已经僵死
#include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <sys/wait.h> int main(int arg,char*args[]) { close(STDOUT_FILENO); open("/dev/pts/1",O_WRONLY); pid_t child = fork(); if(child == -1) { return -1; } if(child == 0) { char* args[] = {"/bin/ls","-l",NULL}; execve("/bin/ls",args,NULL); }else { exit(0); } printf("end\n"); return EXIT_SUCCESS; } ~ ~ ~ ~ ~ ~ ~
这个案例会发现父子进程共享文件描述符,然后execve打印在控制台/dev/pts/1上
OK 理解了父子进程 进程创建的方式开始讲一下进程通信:
管道是管道文件,无名管道限于父子进程之间的通信,有名管道是任何两个进程的通信,共享内存也是。
无名管道通信如下:
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> int main(int arg,char* args[]) { int fd[2]; char message[100]; int len; pipe(fd); memset(message,0,sizeof(message)); int pid = fork(); if(pid == 0) { close(fd[1]); while((len = read(fd[0],message,sizeof(message))) > 0 ) { write(STDOUT_FILENO,message,len); } close(fd[0]); }else { close(fd[0]); strcpy(message,"shaozhongqi come from nanjing"); write(fd[1],message,sizeof(message)); close(fd[1]); waitpid(pid,NULL,0); } return EXIT_SUCCESS; }通过pipe()方法创建无名管道,父进程写数据,子进程读数据直到管道文件被关闭
有名管道需要通过命令mkfifo创建
案例如下:
#include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main(int arg,char* args[]) { char buf[100]; int len; int fd = open("testfifo",O_RDONLY); memset(buf,0,sizeof(buf)); while((len = read(fd,buf,sizeof(buf))) > 0) { write(STDOUT_FILENO,buf,strlen(buf)); memset(buf,0,sizeof(buf)); } return EXIT_SUCCESS; }打开管道文件testfifo,然后从管道读数据
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main(int arg,char* args[]) { char buf[100]; int fd = open("testfifo",O_WRONLY); memset(buf,0,sizeof(buf)); while(1) { read(STDIN_FILENO,buf,sizeof(buf)); if(buf[0] == '0') { close(fd); break; }else { write(fd,buf,strlen(buf)); memset(buf,0,sizeof(buf)); } } return EXIT_SUCCESS; } ~ ~ ~ ~打开管道文件写数据 直到这完成了单向的管道读写数据
下面将一些共享内存 首先通过
#include <sys/types.h> #include <sys/wait.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ipc.h> #include <sys/shm.h> int main(int arg,char* args[]) { int shmid = shmget(IPC_PRIVATE,1024,0666); if(shmid < 0) { printf("failure\n"); }else { printf("id:%d\n",shmid); } return EXIT_SUCCESS; }
然后通过命令ipcs -m 查看共享内存的信息 返回共享内存的id
下面就是进程在自己内存开辟一块内存与共享内存进行关联,当进程在自己的内存中读写数据会同步到共享内存中(进程是不能直接操作共享内存的)
、include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ipc.h> #include <sys/shm.h> int main(int arg,char* args[]) { char* shmbuf; int shmid = 0; if(arg < 2) { return -1; } shmid = atoi(args[1]); shmbuf = shmat(shmid,0,0); if(atoi(args[2]) == 1) { //read printf("%s\n",shmbuf); }else if(atoi(args[2]) == 2) { //write scanf("%s\n",shmbuf); } shmdt(shmbuf); return EXIT_SUCCESS; } ~ ~
Ok 基本学习到此
相关文章推荐
- Linux系统下部署maven nexus私服和手动同步中央仓库索引
- linux添加静态路由表,重新启动继续有效
- Linux signal() 信号处理函数
- [CentOS] 常用工具软件包
- Linux用到的指令
- Linux用到的指令<小记>
- linux 上下文切换带来的影响
- Linux 获取网口详细信息
- centos 安装FTP server详情
- Centos 建立一个新用户 详细讲解
- linux yum命令详解
- linux双向链表分析之list_del中的技巧
- linux下openssl-1.0.0c编写openssl服务器和客户端
- 操作系统的CPU监控,基于Unix/linux系统
- Linux_day01_primaryCommand
- centos6.6安装web版GIT --gogs
- Linux命令英文全称
- Centos 7 巨大变动之 systemd 取代 SysV的Init
- CentOS环境使用MonaServer
- linux