dup,dup2,dup3是linux下非常重要的函数,用来实现流的重定向,可以很方便实现一些很有趣的效果。

   原理:每个进程在内核中有相应的fd记录表,每个fd占用一项。调用dup()后,新产生的newfd与原oldfd指向同一内核文件表项,操作newfd与操作oldfd效果一样,比较常用的应用就是CGI编程。


 

   下面看代码:

 

int main(int argc,char **argv)
{
// 打开文件
int fd = open("data.dat",O_CREAT|O_RDWR|O_TRUNC,S_IRUSR|S_IWUSR);
assert(fd>0);

// 通过新fd写文件
read_write(fd);

// dup实现标准输入重定向到文件
print2file(fd);

// dup2实现标准输入重定向到文件
print2file1(fd);

return 0;
}

void read_write(int fd)
{
// 拷贝fd,返回当前系统最小且没有被使用的fd
int nfd = dup(fd);
printf("old:%d new:%d\n",fd,nfd); // 3 4

char buf[1024];
memset(buf,'\0',1024);

int n;

// 读取控制台输入流,并通过nfd写入文件
while((n = read(STDIN_FILENO,buf,1024))>0)
{
write(nfd,buf,n);
}
}

void print2file(int fd)
{
close(STDOUT_FILENO);

/**
* 关闭标准输出流,调用dup()后返回的系统最小可用fd,此时nfd=1。此时任何目标为STDOUT_FILENO的I/O操作,如printf()等数据都会流入fd对应的文件,太神奇了。
* 如果fd为tcp套接字描述符,则会被发送到与客户端连接的socket上,这就是CGI的实现原理。这就能解释CGI程序中大量的printf()语句
*/
int nfd = dup(fd);

// 这两条打印语句会被写入data.dat文件中
printf("old:%d new:%d\n",fd,nfd);
printf("hello world\n");
}

void print2file1(int fd)
{
/**
* dup2可以指定拷贝后的newfd,原先的newfd会被关闭
* dup2(fd,STDOUT_FILENO); 相当于 cose(STDOUT_FILENO); dup(fd);
*/
int nfd = dup2(fd,STDOUT_FILENO);
printf("old:%d new:%d\n",fd,nfd);
printf("dup2 test\n");
}