首页 > 编程知识 正文

shell函数调用,汇编语言dup用法

时间:2023-05-04 12:21:35 阅读:22891 作者:3123

正文转载,原文地址: http://blog.csdn.net/Fulin us/article/details/9669177 # comments

1、在具体说出内核中文件描述符的数据结构dup/dup2之前,我认为需要知道内核中文件描述符的形态。 进程存在时,将打开一些文件,并从shell返回一些文件描述符以运行该进程。 默认情况下,在进程的标准输入中存在三个文件描述符: 0、1和2,其中1是进程的标准输出,2是进程的标准错误输出,而1个进程当前打开的文件描述符通过/proc/

下图清楚地说明了问题。 图来自百度百科。

文件表包含文件状态标志、当前文件偏移和v节点指针。 这些在本文件中不重要。 您只需要知道每个打开的文件描述符(fd标志)在工艺表中都有自己的文件表条目,并由文件指针指向。

2、dup/dup2函数APUE和man文档都用一句话简述了这两个函数的作用:复制现有的文件描述符。

# include unistd.hint dup (intoldfd ); intdup2(intoldFD,int newfd; 调用dup函数时,内核将在进程中创建新的文件描述符。 此描述符是当前可用文件描述符的最小值,指向oldfd拥有的文件表条目。

dup2和dup的区别在于,可以在newfd参数中指定新描述符的数字。 如果newfd已经打开,请先将其关闭。 如果newfd等于oldfd,则dup2返回newfd而不关闭。 DP2函数返回的新文件描述符也与参数oldfd共享相同的文件表项。

APUE用别的方法解释了这个问题:

实际上,调用dup(oldFD )与fcntl ) oldFD,F_DUPFD,0 )相同

调用dup2(OLDFD,newfd )相当于关闭(OLDFD )。 fntl(OLDFD、F_DUPFD、newfd );

3、用CGI编写过dup2 CGI程序的人都知道,当浏览器采用开机自检方法提交表格数据时,CGI读取数据从标准输入stdin,写入数据写入标准输出stdout(C )。 按照我们一般的理解,printf的输出应该会显示在终端上。 CGI程序最初使用dup2函数在连接套接字: dup2 ) connfd,STDOUT_FINLENO (此宏由unitstd.h定义,1 )中定义文件描述符

如第一节所述,进程的默认文件描述符1(stdout_fileno )与标准输出stdout相关联,对内核来说,所有打开的文件都由文件描述符引用,内核由stdin、 printf函数输出到stdout的数据最后与标准输入、标准输出和标准错误输出相关联的文件描述符0、1和2是shell和许多APP应用程序的惯例,与内核无关。

可以通过以下流程图说明问题(ps:虽然不是流程关系,但对理解有帮助)。

printf-stdout-stdout_fileno(1) -终端(tty ) ) )

printf的最后一个输出被传送到终端设备,可以理解为文件描述符1指向当前终端,如下。

tdout_fileno=open(「/dev/tty”,O_RDWR );

使用dup2后,printf的输出最后写入到connfd中,因为STDOUT_FILENO指向的是connfd而不是终端设备。 很美吗?

4、如何在CGI程序的fork子流程中恢复STDOUT_FILENO如果您能看到这里,我将非常感谢您的耐心。 很多人可能会觉得有点复杂,但其实我知道复杂的问题是小问题的集合。 所以,只要弄清楚所有的小问题就OK了。 第三节提到STDOUT_FILENO已重定向到connfd套接字。 虽然您可能希望在CGI程序中调用和运行后台脚本,但这些脚本不可避免地需要输入和输出。 在fork之后,子进程继承了父进程的所有文件描述符,因此这些脚本的输入和输出并不像我们希望的那样输出到终端设备,而是如何输出为CCI

方法:在dup2之前保存原有的文件描述符,然后恢复。

代码实现如下:

saveFD=dup(stdout_fileno ); /savefd此时指向终端/

DUP2(connfd,STDOUT_FILENO );

.

DUP2(saveFD,STDOUT_FILENO );

很遗憾,CGI程序不能使用此方法。 更改web服务器不是一个好主意,因为dup2它们是在web服务器上实现的,而不是CGI程序。

方法2: 追本溯源,打开当前终端恢复STDOUT_FILENO。

分析第一

三节的流图,STDOUT_FILENO是如何和终端关联的?我们重头做一遍不就行了,代码实现如下:
  ttyfd = open(“/dev/tty”, O_RDWR);
  dup2(ttyfd, STDOUT_FILENO);
  close(ttyfd);
  /dev/tty是程序运行所在的终端,这个应该通过一种方法获得。实践证明这种方法是可行的,但是个人总感觉有些不妥,不知道为什么,可能一些潜在的问题还没出现。

5、实例

  dup函数实例:

[lingyun@localhost dup]$ cat dup.c /********************************************************************************* * Copyright: (C) 2013 fulinux<fulinux@sina.com> * All rights reserved. * * Filename: dup.c * Description: This file * * Version: 1.0.0(07/31/2013~) * Author: fulinux <fulinux@sina.com> * ChangeLog: 1, Release initial version on "07/31/2013 04:00:06 PM" * ********************************************************************************/#include <stdio.h>#include <unistd.h>#include <sys/stat.h>#include <fcntl.h>int main(int argc, char* argv[]){ int fd = open("hello", O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR); if(fd < 0) { printf("Open Error!!n"); return 0; } int nfd = dup(fd); if(nfd < 0) { printf("Error!!n"); return 0; } char buf[1000]; int n; while((n = read(STDIN_FILENO, buf,1000)) > 0) { if(write(nfd, buf, n) != n) { printf("Write Error!!n"); return 0; } } return 0;}

  上面代码中,nfd 拷贝了 fd,所以 write ( nfd, buf, n ) 这语句写到 nfd 所代表的文件时也就是写到 fd 所代表的文件。程序执行完后可以在相应的目录的hello文件中看到输出。

[lingyun@localhost dup]$ gcc dup.c [lingyun@localhost dup]$ lsa.out dup.c[lingyun@localhost dup]$ ./a.out hello world^C[lingyun@localhost dup]$ lsa.out dup.c hello[lingyun@localhost dup]$ cat hello hello world[lingyun@localhost dup]$

dup2函数实例:

[lingyun@localhost dup2]$ cat dup2.c /********************************************************************************* * Copyright: (C) 2013 fulinux<fulinux@sina.com> * All rights reserved. * * Filename: dup2.c * Description: This file * * Version: 1.0.0(07/31/2013~) * Author: fulinux <fulinux@sina.com> * ChangeLog: 1, Release initial version on "07/31/2013 08:22:19 PM" * ********************************************************************************/#include <stdio.h>#include <unistd.h>#include <sys/stat.h>#include <fcntl.h>int main(int argc, char* argv[]){ int fd = open("hello.file", O_CREAT|O_RDWR|O_TRUNC,S_IRUSR|S_IWUSR); if(fd < 0) { printf("Open Error!!n"); return 0; } int nfd = dup2(fd, STDOUT_FILENO); if(nfd < 0) { printf("Error!!n"); return 0; } char buf[5]; int n; while((n = read(STDIN_FILENO, buf, 5)) > 0) if(write(STDOUT_FILENO, buf, n) != n) { printf("Write Error!!n"); return 0; } return 0;}

  上面的例子使用dup2将标准输出重定向为hello.file文件,如下所示:

[lingyun@localhost dup2]$ lsdup2.c[lingyun@localhost dup2]$ gcc dup2.c [lingyun@localhost dup2]$ ./a.out hello world^C[lingyun@localhost dup2]$ cat hello.file hello world[lingyun@localhost dup2]$

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。