Linux进程通信(无名管道,有名管道,共享内存)的实现

时间:2021-12-18 15:09:41

   Linux进程的通信有很多种方式,比如无名管道,有名管道,共享内存,Android进程通信采用的确是Binder机制~~~

   在学习进程通信之前先学习一下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;
}
~

Linux进程通信(无名管道,有名管道,共享内存)的实现


#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可以看到子进程已经僵死

Linux进程通信(无名管道,有名管道,共享内存)的实现

#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

Linux进程通信(无名管道,有名管道,共享内存)的实现


下面就是进程在自己内存开辟一块内存与共享内存进行关联,当进程在自己的内存中读写数据会同步到共享内存中(进程是不能直接操作共享内存的)

、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  基本学习到此