对于Dup2 的理解:

源代码:

 #include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h> #define MSGSIZE 20
#define READ 0
#define WRITE 1 int main(int argc, char const *argv[])
{
int p[], bytes, res, c;
char inbuf[];
int pid;
printf("%c", );
if(pipe(p) == -){// creat the pipe , if pipe is built failed , exit .
perror("pip call");
exit();
}
pid = fork();
if(pid != ){// creat parent pid and child pid.
close(p[READ]);//close parent pipe read
dup2(p[WRITE], );
close(p[WRITE]);//close parent pipe write
execlp(argv[], argv[], NULL);
}
else{ close(p[WRITE]);//close child pipe write dup2(p[READ],); close(p[READ]);//close child pipe read execlp(argv[], argv[], NULL);
}
return ;
}

通过命令行输出:

./a.out “ls” “ps”

仅仅在终端执行了ps的命令, 而没有看到ls 命令的结果。

因此,开始走入了第一个误区:父进程没有执行

通过调试 在父进程执行if条件中加入以下代码:

if(pid != 0){

printf("4556\n");

close(p[READ]);

dup2(p[WRITE], 1);

close(p[WRITE]);

printf("4556\n");

execlp(argv[1], argv[1], NULL);

}

加入了2个printf
, 但是只有dup2 上面的printf
结果输出到屏幕上,因此我注释了 dup2(p[WRITE],
1); 结果在父进程if语句中的dup2
后面的命令都执行并且输出到屏幕上了。通过查找dup2
命令发现了重定向的强大之处。

先解释下
dup2 命令,

int dup2(int filedes, int filedes2);

说明:

用dup2
则可以用filedes2
参数指定新描述符的数值。如果filedes2
已经打开,则先将其关闭。如若filedes
等于filedes2,则返回filedes2,而不关闭它。

dup2(p[WRITE], 1);
这句话可以理解为将标准输出重定向到
p[WRITE], 因此在这句话后面的所有printf
语句打印或者exec
执行的内容都输入到了p[WRITE]中。刚开始有个迷惑,就是既然已经close(1)了,为什么还能输入到p[WRITE]中,通过自己的直觉判断,应当是close(1)关闭了屏幕的输出,但是它有缓冲区保存printf打印出的内容,并且由于重定向的关系,输进了p[WRITE]中。

代码:

 #include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h> #define MSGSIZE 20
#define READ 0
#define WRITE 1 int main(int argc, char const *argv[])
{
int p[], bytes, res, c;
char inbuf[];
int pid;
printf("%c", );
if(pipe(p) == -){// creat the pipe , if pipe is built failed , exit .
perror("pip call");
exit();
}
pid = fork();
if(pid != ){// creat parent pid and child pid.
close(p[READ]);//close parent pipe read
dup2(p[WRITE], );
close(p[WRITE]);//close parent pipe write
printf("123!\n");
execlp(argv[], argv[], NULL);
perror("execlp");//error output
}
else{
while(){
res = read(p[READ], inbuf, );
if(res>)
printf("%s\n", inbuf);
break;
} close(p[WRITE]);//close child pipe write dup2(p[READ],); close(p[READ]);//close child pipe read execlp(argv[], argv[], NULL);
}
return ;
}

通过在子进程中用while(1)循环读取p[READ]内容,发现读出了父进程本应在屏幕上打印的内容,因此父进程是执行了所有命令行,只是通过重定向命令存到了p[WRITE]管道中。

由于有dup2(p[READ], 0) 命令,因此猜测标准输入的文件描述符定向到了p[READ] , 因此如果猜测没错,通过getchar()读取文件标准输入并把P[READ]的内容输出到屏幕上则证明我猜想没错。

代码:

 #include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h> #define MSGSIZE 20
#define READ 0
#define WRITE 1 int main(int argc, char const *argv[])
{
int p[], bytes, res, c;
char inbuf[];
int pid;
printf("%c", );
if(pipe(p) == -){// creat the pipe , if pipe is built failed , exit .
perror("pip call");
exit();
}
pid = fork();
if(pid != ){// creat parent pid and child pid.
close(p[READ]);//close parent pipe read
dup2(p[WRITE], );
close(p[WRITE]);//close parent pipe write
printf("123!\n");
execlp(argv[], argv[], NULL);
perror("execlp");//error output
}
else{
// while(1){
// res = read(p[READ], inbuf, 10240);
// if(res>0)
// printf("%s\n", inbuf);
// break;
// } close(p[WRITE]);//close child pipe write dup2(p[READ],);
while((c=getchar()) != -){
printf("%c", c);
}
close(p[READ]);//close child pipe read execlp(argv[], argv[], NULL);
}
return ;
}

通过在dup2(p[READ],
0) 后面while循环读入输入流输入的字符并且打印出来,
发现结果果然是p[READ]的内容,猜疑没错。

为了更清楚的理解dup2的重定向含义,想理解dup2(fd,0)和dup2(0,fd)功能相同吗?

为了得到答案,找些资料发现,答案是不同。

测试代码:

 #include <stdio.h>
#include <unistd.h>
#include <fcntl.h> #define BUFMAXSIZE 4096 int main(int argc, char *argv[])
{
int fd;
int n;
char buf[BUFMAXSIZE];
int fs;
fs = open("test", O_RDWR);
if((fd = open("duan", O_RDWR )) == -)
{
perror("open error!");
return();
} dup2(fd, ); // dup2(0,fd); while((n = read(fs, buf, BUFMAXSIZE)) > )
{
printf("begin to read...\n");
if(write(STDOUT_FILENO, buf, n) != n)
{
perror("write error!");
return();
}
printf("end to write...\n");
}
if(n < )
{
perror("read error");
return();
} return ;
}

dup(fd, 0) 这段代码测试, 打印出了 duan 文件里面的内容。

之后创建个文件 Levi 里面写和duan 文件不同的内容。

通过./a. out < Levi输出:

第一个输出是 dup(fd, 0) 输出了Duan 文件的内容。即是fd的内容

第二个输出是 dup(0, fd) 输出了 Levi 文件的内容。即是 通过文件重定向到标准输入的内容。

从图中的输出结果已经可以看到两者的区别了。

第一种dup2(fd,0)之前已经将 fd 初始化指向到文本 Duan了,

并且不会被后面的代码所修改。

第二种dup2(0,fd)则将 fd 重新指向到文件描述符0所代表的文件(即终端标准输入)了。

那么可以看到,程序的执行中不会再读取 Duan 文件了。

而是进入了一种交互模式。

另外,这时“输入重定向”也可以生效了。

文件描述符0被 “<” 重定向到 Duan 了

所以,这里直接输出了该文本的内容。

dup2(fd,0) 相当于“输入重定向”的功能,

dup2(0,fd) 不是表示 fd 所指的文件接收来自终端的输入,因为,fd 已经不再指向原来的那个文件了。

它和文件描述符0 已经在共享同一个文件表项(即指向终端标准输入的那个表项)了。

“输出重定向”的功能可以用 dup2(fd ,1) 替代。

dup2(fd,1) 和 dup2(1,fd) 也是大同小异。

Linux系统编程:dup2()重定向的更多相关文章

  1. linux系统编程(一)概述

    glibc库封装了linux系统调用,并提供c语言接口 所以学习linux系统编程,主要参考glibc库系统调用相关api 一.进程控制: fork 创建一个新进程 clone 按指定条件创建子进程 ...

  2. linux系统编程之文件与io(五)

    上一节中已经学习了文件描述符的复制,复制方法有三种,其中最后一种fcntl还并未使用到,关于这个函数,不光只有复制文件描述符的功能,还有其它一些用法,本节就对其进行一一剖析: fcntl常用操作: 这 ...

  3. Linux 系统编程 学习:03-进程间通信1:Unix IPC(2)信号

    Linux 系统编程 学习:03-进程间通信1:Unix IPC(2)信号 背景 上一讲我们介绍了Unix IPC中的2种管道. 回顾一下上一讲的介绍,IPC的方式通常有: Unix IPC包括:管道 ...

  4. Linux系统编程温故知新系列 --- 01

    1.大端法与小端法 大端法:按照从最高有效字节到最低有效字节的顺序存储,称为大端法 小端法:按照从最低有效字节到最高有效字节的顺序存储,称为小端法 网际协议使用大端字节序来传送TCP分节中的多字节整数 ...

  5. linux系统编程之错误处理

    在linux系统编程中,当系统调用出现错误时,有一个整型变量会被设置,这个整型变量就是errno,这个变量的定义在/usr/include/errno.h文件中 #ifndef _ERRNO_H /* ...

  6. LINUX系统编程 由REDIS的持久化机制联想到的子进程退出的相关问题

    19:22:01 2014-08-27 引言: 以前对wait waitpid 以及exit这几个函数只是大致上了解,但是看REDIS的AOF和RDB 2种持久化时 均要处理子进程运行完成退出和父进程 ...

  7. Linux系统编程-setitimer函数

    功能:linux系统编程中,setitimer是一个经常被使用的函数,可用来实现延时和定时的功能. 头文件:sys/time.h 函数原型: int setitimer(int which, cons ...

  8. Linux系统编程@进程通信(一)

    进程间通信概述 需要进程通信的原因: 数据传输 资源共享 通知事件 进程控制 Linux进程间通信(IPC)发展由来 Unix进程间通信 基于System V进程间通信(System V:UNIX系统 ...

  9. Linux 系统编程

    简介和主要概念 Linux 系统编程最突出的特点是要求系统程序员对它们工作的的系统的硬件和操作系统有深入和全面的了解,当然它们还有库和系统调用上的区别. 系统编程分为:驱动编程.用户空间编程和网络编程 ...

  10. Linux C 程序 文件操作(Linux系统编程)(14)

    文件操作(Linux系统编程) 创建一个目录时,系统会自动创建两个目录.和.. C语言实现权限控制函数 #include<stdio.h> #include<stdlib.h> ...

随机推荐

  1. zoj3791(An Easy Game) DP

    意甲冠军:给定两个01弦s1,s2.每一个变化s1在m字 - 位.要求k制作步骤之后s1变s2有多少种方法. 解法:DP,关键是状态的设计.考虑还是唯一性和可传递性.dp[i][j]表示第i步后有j个 ...

  2. Swift使用单个案件管理FMDB数据库

    下班... 抢 我曾经Swift使用单一个案管理FMDB数据库的方法共享出来: // Created by 秦志伟 on 14-6-12. import UIKit class ZWDBManager ...

  3. 安德鲁斯 建立与各种听众自己定义的ScrollView

    === 建立与各种听众自己定义的ScrollView === 尽管安卓5.1已经release, 可是ScrollView的封装和对外API依然少的可怜, 尽管它优化得非常好了. 所以问题来了: Sc ...

  4. ASP.NET MVC+EF框架+EasyUI实现权限管理系列(11)-验证码实现和底层修改

    原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(11)-验证码实现和底层修改 ASP.NET MVC+EF框架+EasyUI实现权限管系列  (开篇)   (1):框架搭建    ...

  5. crawler_wireshark 过滤基础知识

    一.IP过滤:包括来源IP或者目标IP等于某个IP比如:ip.src addr==192.168.0.208  or ip.src addr eq 192.168.0.208 显示来源IP       ...

  6. 我的MYSQL学习心得(七)

    原文:我的MYSQL学习心得(七) 我的MYSQL学习心得(七) 我的MYSQL学习心得(一) 我的MYSQL学习心得(二) 我的MYSQL学习心得(三) 我的MYSQL学习心得(四) 我的MYSQL ...

  7. 大约HR升级版的设计为组汇总

    该公司刚刚完成HR系统升级,系统从单一公司实现使用更多的公司使用变更.在一个月的时间升级,虽然很苦,但他们自己的系统架构的感觉获益,有以下的详细的见解: 一.MVC还是非常重要 系统框架是五年前用de ...

  8. linux 虚拟文件系统

    转自:https://www.ibm.com/developerworks/cn/linux/l-cn-vfs/ Linux 允许众多不同的文件系统共存,并支持跨文件系统的文件操作,这是因为有虚拟文件 ...

  9. gpu显存(全局内存)在使用时数据对齐的问题

    全局存储器,即普通的显存,整个网格中的随意线程都能读写全局存储器的任何位置. 存取延时为400-600 clock cycles  很easy成为性能瓶颈. 訪问显存时,读取和存储必须对齐,宽度为4B ...

  10. asp.net mvc3 数据验证(二)——错误信息的自定义及其本地化

    原文:asp.net mvc3 数据验证(二)--错误信息的自定义及其本地化 一.自定义错误信息         在上一篇文章中所做的验证,在界面上提示的信息都是系统自带的,有些读起来比较生硬.比如: ...