Linux进程的通信有很多种方式,比如无名管道,有名管道,共享内存,Android进程通信采用的确是Binder机制~~~
在学习进程通信之前先学习一下System,Fork,Execive的机制,System调用的是另一个进程跟自己毫无关系 用的比较少。Fork创建的是父子进程,父进程的内存会被复制到
字进程的内存空间区别就是PID的不同。Execive调用的进程就会保留内存空间但是执行的是调用程序的代码。
首先看一下这三种创建进程的方法区别:
Execive:
#include <stdlib.h>执行到execive是内存空间会被/bin/ls占据,后面的打印语句就会被取消没有打印出来
#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;
}
重点看一下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>父进程必须使用wait等待子进程结束掉才能关闭掉,通过status获得返回值,如果子进程死掉,父进程活着,子进程就会变成僵尸进程占据资源
#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;
}
~
nt main(int arg,char*args[])这个时候通过ps aux可以看到子进程已经僵死
{
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;
}
~
~
~
~
#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>通过pipe()方法创建无名管道,父进程写数据,子进程读数据直到管道文件被关闭
#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;
}
有名管道需要通过命令mkfifo创建
案例如下:
#include <unistd.h>打开管道文件testfifo,然后从管道读数据
#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;
}
#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 基本学习到此