【问题标题】:Is it possible that linux file descriptor 0 1 2 not for stdin, stdout and stderr?linux文件描述符0 1 2是否可能不适用于stdin、stdout和stderr?
【发布时间】:2014-03-13 02:28:47
【问题描述】:

程序启动时,默认情况下,stdin、stdout 和 stderr 是否采用文件描述符 0、1 和 2?并且 API 调用(如 open(...)、socket(...))不会返回 0、1 和 2,因为这些值已经被采用了吗?是否存在 open(...) 或 socket(...) 会返回 0、1 或 2 的情况。而 0、1 和 2 与 stdin、stdout 和 stderr 无关。

【问题讨论】:

  • 正如我所回答的,您的问题没有多大意义。文件描述符 0 始终是标准输入。

标签: linux sockets kernel


【解决方案1】:

file descriptor级别,stdin被定义为文件描述符0stdout被定义为文件描述符1; stderr 被定义为文件描述符 2。见this

即使你的程序 - 或 shell - 改变(例如使用 dup2(2) 重定向)什么是文件描述符 0,它总是保持 stdin (因为根据定义 STDIN_FILENO 是 0)。

当然,stdin 可以是管道、套接字或文件(​​不是终端)。如果是 tty,您可以使用 isatty(3) 进行测试,和/或使用 fstat(2) 获取其状态信息。

open(2)pipe(2)socket(2) 这样的系统调用可能会给出例如STDIN_FILENO(即 0)如果该文件描述符是空闲的(例如,因为它以前是 close(2)-d)。但是当这种情况发生时,它仍然是 stdin 根据定义。

当然,在stdio(3) 中,FILEstdin 有点复杂。你的程序可以fclose(3), freopen(3), fdopen(3) ...

当神奇地将/sbin/init 启动为第一个过程。

【讨论】:

    【解决方案2】:

    虽然已经有几个答案,但我发现它们的信息量不足以解释完整的故事。

    由于我继续进行了更多研究,因此我正在添加我的发现。

    每当一个进程启动时,一个正在运行的进程的条目就会被添加到/proc/<pid> 目录中。这是保存与流程相关的所有数据的地方。此外,在进程启动时,内核会为进程分配 3 个文件描述符,用于与称为 stdinstdoutstderr 的 3 个数据流进行通信。
    linux 内核使用一种算法来始终创建具有最小可能整数值的 FD,因此这些数据流被映射到数字 012

    由于这些只是对流的引用,因此我们可以关闭流。可以很容易地调用close(<fd>),在我们的例子中是close(1),来关闭文件描述符。

    在执行ls -l /proc/<pid>/fd/ 时,我们只看到02 列出了2 个FD。
    如果我们现在调用open(),内核将创建一个新的FD来映射这个新的文件引用,并且由于内核使用最低整数优先算法,它将获取整数值1

    所以现在,新创建的 FD 指向我们打开的文件(使用 open() 系统调用)
    现在发生的任何数据传输都不是通过之前链接的默认数据流,而是通过我们打开的新文件。

    所以是的,我们可以将 FD 012 映射到任何文件,而不需要 stdinstdoutstderr

    【讨论】:

    • fwiw,dup/dup2 手册页记录了这种行为(分配最低的可用句柄)。所以是官方的。最好不要关闭标准手柄而不用其他东西替换它们。 :-P
    【解决方案3】:
    1. 程序启动时,stdin、stdout 和 stderr 是否默认使用文件描述符 0 1 2?

      如果您在交互式 shell 中正常启动程序,是的。

      @EJP:

      如果程序由 inetd 或其他任何行为相同的程序启动,也会将套接字继承为 FD 0。

    2. open(...)、socket(...) 等 API 是否不会返回 0 1 2,因为这些值已经被取走。

      是的。

    3. 是否存在 open(...) 或 socket(...) 会返回 0 1 2 的情况。

      是的,如果你做类似的事情

      close(0);
      close(1);
      close(2);
      open(...); /* this open will return 0 if success */
      

    【讨论】:

    • 如果程序由 inetd 或其他任何行为相同的方式启动,也会发生将套接字继承为 FD 0 的情况。
    • 请注意,当您要求它重定向这些流时,这实质上就是shell 所做的——它会重新打开这些文件句柄,以便它们按照您的请求指向文件或管道。 (我一直在编写 WebSphere 启动逻辑中的一些代码,这些代码类似于设置 WebSphere 的 native_stdout.log 和 native_stderr.log 处理。)
    • @keshlam I/O 重定向也可以通过使用dup()dup2() 来实现。
    猜你喜欢
    • 2018-05-10
    • 1970-01-01
    • 2021-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-27
    • 1970-01-01
    相关资源
    最近更新 更多