⽗⼦进程管道通信(附简单样例)
0x00思路
为了给TinyHTTPd源码分析打下基础,先写⼀个简单⽗⼦进程管道通信的样例
1,先定义,并绑定read,write函数和缓冲区,创建pipe管道数组(下标0对于读段,1对应写端,这是强制规定的)
2.⽗进程fork后,⽗⼦进程各有⼀套1中的变量,且代码执⾏是同步的,只不过储存空间不在⼀起,然后对⽗⼦进程的管道进⾏操作使之可以通信0x01函数
write
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
将buf所指的内存中的count个字节,写⼊到⽂件描述符fd所指的⽂件中去。
read
number = read(handle, buffer ,n);
上述read调⽤函数中,各个参数的定义如下:
handle: 这是⼀个已经打开的⽂件标识符,表⽰从这个⽂件句柄所代表的⽂件读取数据。
buffer: 指缓冲区,即读取的数据会被放到这个缓冲区中去。
n: 表⽰调⽤⼀次read操作,应该读多少数量的字符。
number:表⽰系统实际所读取的字符数量。
pipe
进程通信方式头⽂件: #include<unistd.h>
函数原型:int pipe(int filedes[2]);
函数说明:pipe()会建⽴管道,并将⽂件描述词由参数filedes数组返回。
filedes[0]为管道⾥的读取端
filedes[1]则为管道的写⼊端。
返回值: 若成功则返回零,否则返回-1,错误原因存于errno中。
错误代码:
EMFILE 进程已⽤完⽂件描述词最⼤量
ENFILE 系统已⽆⽂件描述词可⽤。
EFAULT 参数 filedes 数组地址不合法。
fork
头⽂件:#include <unistd.h>
#include<sys/types.h>
函数原型:pid_t fork( void);
创建⼀个新的进程。(pid_t 是⼀个宏定义,其实质是int 被定义在#include<sys/types.h>中)
fork后发⽣了什么
1.由fork创建的新进程被称为⼦进程(child process)。该函数被调⽤⼀次,但返回两次。两次返回的区别是⼦进程的返回值是0,
2.⽽⽗进程的返回值则是新进程(⼦进程)的进程 id。将⼦进程id返回给⽗进程的理由是:因为⼀个进程的⼦进程可以多于⼀个,没有⼀个函数使⼀个进程可以获得其所有⼦进程的进程id。
3.对⼦进程来说,之所以fork返回0给它,是因为它随时可以调⽤getpid()来获取⾃⼰的pid;也可以调⽤getppid()来获取⽗进程的id。(进程id为0的总是由交换进程使⽤,所以⼀个⼦进程的进程id不可能为0)。
4.fork之后,操作系统会复制⼀个与⽗进程完全相同的⼦进程。虽说是⽗⼦关系,但是在操作系统看来,他们更像兄弟关系,这2个进程共享代码空间,但是数据空间是互相独⽴的,⼦进程数据空间中的内容是⽗进程的完整拷贝,指令指针也完全相同,⼦进程拥有⽗进程当前运⾏到的位置(两进程的程序计数器pc值相同。也就是说,⼦进程是从fork返回处开始执⾏的)
5.但有⼀点不同,如果fork成功,⼦进程中fork的返回值是0,⽗进程中fork的返回值是⼦进程的进程号,如果fork不成功,⽗进程会返回错误。
可以这样想象,2个进程⼀直同时运⾏,⽽且步调⼀致,在fork之后,他们分别作不同的⼯作,也就是分岔了。
注意:
fork()函数主要是以⽗进程为蓝本复制⼀个进程,其ID号和⽗进程的ID号不同。对于结果fork出来的⼦进程的⽗进程ID号是执⾏fork()函数的进程的ID号;
例如:
⽗进程, fork返回值是:17025, ID:17024 ,⽗进程ID:16879
⼦进程, fork返回值是:0, ID:17025 ,⽗进程ID:17024
close
⽤这个函数来关闭管道的⼀端
0x02重要变量
2.pid进程变量(在fork函数的使⽤过程中很重要)
4.fd[2]pipe读写端数组 实现管道通信
0x03遇到的问题
1.对管道通信pipe读写端在不同进程下是怎样的关系不明确
2.fork函数两个返回值的利⽤实现⽗⼦进程过程不清楚
3.为什么TinyHTTPd要两个管道,⽽这个简单例⼦只需要⼀个管道
0x04解决问题
1.见下图
2.见下图
3.因为这个样例不需要双向通信,⼦进程并没有反馈给⽗进程0x05代码
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
#include<string.h>
int main(void){
// pid_t pid;
int i=0;
int result = -1;
int fd[2],nbytes;
char string[100];
char readbuffer[80];
//int *write_fd = &fd[1];
//int *read_fd = &fd[0];
printf("Please input data:");
scanf("%s",string);
result = pipe(fd); ⽤fd建⽴了pip管道链接
if(-1 == result)
{
perror("pipe");
return -1;
}
/*pid=fork(); ⽗⼦进程分开
if(-1 == pid) //此处为了验证⽗⼦进程是否创建成功,如果未创建成功,则返回-1
{
perror("fork");
return -1;
}
else if(0 == pid)//如果是⼦进程
{
printf(“this is child %d\n”, getpid());
close(*read_fd);//关掉⼦进程的读端,只剩下写端
result = write(*write_fd,string,strlen(string));//向string写⼊,写⼊到⽂件描述符pipe写端
return 0;
}*/
else//如果不是⼦进程
{
printf(“this is parent %d\n”, getpid());
close(*write_fd);//关闭⽗进程的pip写端,只留下读端
nbytes = read(*read_fd,readbuffer,sizeof(readbuffer)-1);//从read_fd中读⼊,先放⼊readbuffer printf("receive %d data:%s\n",nbytes,readbuffer);
}
return 0;
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论