Wednesday, January 26, 2011

进程间通信—dup & dup2

dup & dup2

轉: http://xgc94418297.blog.163.com/blog/static/112966040200922593724989/

轉: http://xgc94418297.blog.163.com/blog/static/112966040200922593724989/ 

 

    dup和dup2也是两个非常有用的调用,它们的作用都是用来复制一个文件的描述符。它们经常用来重定向进程的stdin、stdout和stderr。这两个函数的原形如下: 

#include <unistd.h>
int dup( int oldfd );
int dup2( int oldfd, int targetfd );

 

 dup : 

   重定向标准输出到一个文件, 为当前进程关闭标准输出,并重新设置标准输出到一个pfd文件,并关闭原始的文件描述符


    原型 : int dup(int file_desc);
    作用:  复制一个和file_desc指向同一个文件的文件描述符, 并且新的文件描述符总是取最小的可用值。
这样一来就可有一个诀窍:因为标准输入描述符总是0,并且dup函数调用总是取最小可用的数字,如果关闭0,再调用dup函数,新的文件描述符就是0了。

 

(1). Example:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
    int fd;
    /* 读写方式打开一个文件, 没有就创建 */
    if ((fd = open("test",O_RDWR|O_CREAT))<0) {
       perror("open error");
       exit(1);
    }
    close(1);      //先关闭stdout
    dup(fd);       //重定向到fd,也就是test文件中
    //调用命令
    if (execl("/bin/ls","ls","-al",NULL)<0) {
       perror("error");
       exit(1);
    }

    return 0;
}
执行的命令“ls -al”就会被重定向到文件test中 


dup2 :

dup2函数跟dup函数相似,但dup2函数允许调用者规 定一个有效描述符和目标描述符的id。dup2函数成功返回时,目标描述符(dup2函数的第二个参数)将变成源描述符(dup2函数的第一个参数)的复 制品,换句话说,两个文件描述符现在都指向同一个文件,并且是函数第一个参数指向的文件。(还是不太明白)
利用函数dup,我们可以复制一个描述符。传给该函数一个既有的描述符,它就会返回一个新的描述符,这个新的描述符是传给它的描述符的拷贝。这意味着,这 两个描述符共享同一个数据结构。例如,如果我们对一个文件描述符执行lseek操作,得到的第一个文件的位置和第二个是一样的。
需要注意的是,我们可以在调用fork之前建立一个描述符,这与调用dup建立描述符的效果是一样的,子进程也同样会收到一个复制出来的描述符。
注意:dup函数会将打开的文件描述符重定向到当前进程最小的,未使用的描述符 
由于关闭了标准输出,因此起就是标准输出的描述符。

(1). Example 1 -
用dup2实现: ls –al | more
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
int main()
{
    int fd[2];
    pid_t pid;
    if ( pipe(fd)<0 )
    {
       perror("pipe error");
       exit(1);
    }  
    if ((pid=fork())<0 )
    {
       perror("fork error");
       exit(1);
    }
    else if (pid == 0)
    {
       close(1);
       dup2(fd[1],1);
       close(fd[0]);
       execlp("ls","ls","-al",NULL);
    }
    else
    {
       close(0);
       dup2(fd[0],0);
       close(fd[1]);
       execlp("more","more",NULL);
    }

    return 0;
}
创建一个管道,程序有两个进程,一个子进程,一个父进程。
子进程中,先关闭stdout描述符,用dup2重定向到管道的输入端,关闭输出端,用execlp把子进程映像替换成ls –al,
父进程中,先关闭stdin描述符,就不从标准输入设备读取以,而从其他程序接收数据,用dup2重定向到管道的输出端,关闭输入端,用execlp,把父进程映像替换成more,more命令把管道的内容做为它的输入。
我们的子进程把它的输出重定向的管道的输入,然后,父进程将它的输入重定向到管道的输出。


 (2). Example - 
重定向錯誤輸出stderr到標準輸出stdout  --  dup2(1, 2);

看看这段示范代码
#include <stdio.h>
#include <unistd.h >
int main()
{
//dup2(1, 2);
 
fprintf(stdout, "stdout\n");
fprintf(stderr, "stderr\n");
 
return 0;
}
 
分别往stdout和stderr输出”stdout”, “stderr”, 看看运行结果
$ ./r > 1.txt
stderr
$ cat 1.txt
stdout
显然是符合预期的, 我们把上面那段代码的dup2(1, 2) 启用,重新看看执行结果
$ ./r > 2.txt
$ cat 2.txt
stderr
stdout
明显,就是stderr已经重定向到stdout了,内容都输出到stdout里面了


(3). Example -
fprintf 和printf:printf是键盘和显示器终端输出,而fprintf是设备

#include <stdio.h>
#define err_quit printf
int main(int argc, char *argv[])
{
        int fd;
        if(argc!=2) {
                err_quit("Usage :filename");
        }
        if((fd=creat(argv[1],0644))<0) {
                err_quit("create file failed");
        }
        close(1);/*close the stdout,so can redirect to file*/
        dup(fd);
        close(fd);
        printf("what are you thinking???\n");
        FILE *fp;
        fp = fopen("ceshi1.txt","w");
        if(fp==NULL)
                return ;
        fprintf(fp,"%s\n","hello");
}

(4). Example -

#include <stdio.h>

#define err_quit printf

int main(int argc, char *argv[])
{
        int fd,fd2, fd3, fd4;
        FILE *fp2, *fp3, *fp4;

        if(argc!=2) {
          err_quit("Usage :filename");
        }
        if((fd=creat(argv[1],0644))<0) {
          err_quit("create file failed");
        }
        //close(1);/*close the stdout,so can redirect to file*/
        fd2 = dup(fd);
        fd3 = dup(fd);
        close(1);
        fd4 = dup(fd2);
        //close(1);
        //dup(fd4);
        printf("fd(%d), fd2(%d), fd3(%d), fd4(%d)", fd, fd2, fd3, fd4);
        close(fd);

        printf("what are you thinking???\n");
        //FILE *fp;
        //fp = fopen("ceshi1.txt","w");
        //if(fp==NULL)
        //        return ;
        //fprintf(fp,"%s\n","hello");
}

No comments:

Post a Comment