父子进程管道通信(附简单样例)

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重要变量

1.result异常变量,用来进行判断一些函数的异常返回情况

2.pid进程变量(在fork函数的使用过程中很重要)

3.read/write buffer 在文件读写的时候创建缓冲区i

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;
}

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LiujiaHuan13

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值