文件描述符继承
子进程会继承父进程的文件描述符
验证
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
void dump(int fd)
{
char buf[128];
int count;
count = read(fd, buf, sizeof(buf));
buf[count] = 0;
puts(buf);
}
int main()
{
pid_t pid;
int fd;
fd = open("/etc/passwd", O_RDONLY);
pid = fork();
if (pid == 0)
dump(fd);
return 0;
}
output:
$ ./a.out
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:s
$ _
dup
原型
#include <unistd.h>
int dup(int oldfd);
功能
- 通过复制文件描述符oldfd,创建一个新的文件描述符newfd
newfd和oldfd指向相同的文件
参数
- oldfd, 被复制的文件描述符
返回值
- 如果成功,返回新复制的文件描述符
- 如果失败,返回非0
Q:既然文件描述符是int,为什么还要用dup?
A:还要修改文件描述符表
dup2
原型
#include <unistd.h>
int dup2(int oldfd, int newfd);
功能
- 通过复制文件描述符oldfd,创建一个新的文件描述符newfd
newfd和oldfd指向相同的文件
参数
- oldfd, 被复制的文件描述符
- newfd, 新创建的文件描述符
返回值
- 如果成功,返回新复制的文件描述符
- 如果失败,返回非0
重定向至log
初始时的文件描述符表
打开log后的表
修改后的表
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd;
fd = open("log.txt", O_CREAT|O_RDWR, 0666);
dup2(fd, 1);
close(fd);
write(1, "hello\n", 6);
return 0;
}
输出:
$ ./a.out
$ ls
a.out ex0.c log
$ cat log
hello
$ _
pipe
原型
#include <unistd.h>
int pipe(int fd[2]);
功能
创建一个可读写的管道,管道具备读端和写端
参数
- fd[0]为管道的读端
- fd[1]为管道的写端
返回值
- 如果成功,返回0
- 如果失败,返回非0
- 创建一个先进先出队列用于存储数据
- 创建两个file结构体
- 管道的读端,从先进先出队列中读取数据
管道的写端,向先进先出队列中写入数据 - 返回两个文件描述符fd[0]和fd[1]
fd[0]指向管道的读端
fd[1]指向管道的写端
例子:管道连接父子进程
子进程写,父进程读
初始时的表
使用pipe()后
使用fork()后
使用dup()
关闭父子进程的fd
#include <stdio.h>
#include <unistd.h>
int main()
{
int pid;
int fd[2];
char buf[32];
pipe(fd);
pid = fork();
if (pid == 0) {
// child
dup2(fd[1], 1);
close(fd[0]);
close(fd[1]);
write(1, "hello", 6);
exit(0);
}
// parent
dup2(fd[0], 0);
close(fd[0]);
close(fd[1]);
read(0, buf, sizeof(buf));
printf("Receive:%s\n", buf);
return 0;
}
output:
$ cc ex3.c
$ ./a.out
Receive:hello
$ _