简体   繁体   English

linux 文件描述符 0 1 2 是否可能不适用于 stdin、stdout 和 stderr?

[英]Is it possible that linux file descriptor 0 1 2 not for stdin, stdout and stderr?

When a program begins, does it take file descriptors 0, 1 and 2 for stdin, stdout and stderr by default?.当程序开始时,默认情况下是否为 stdin、stdout 和 stderr 使用文件描述符 0、1 和 2? And will API calls such as open(...), socket(...) not return 0, 1 and 2 since these values are already taken?.并且诸如 open(...)、socket(...) 之类的 API 调用是否不会返回 0、1 和 2,因为这些值已经被采用了?。 Is there any case in which open(...) or socket(...) would return 0, 1 or 2. And 0, 1 and 2 are not related with stdin, stdout, and stderr.是否存在 open(...) 或 socket(...) 会返回 0、1 或 2 的任何情况。并且 0、1 和 2 与 stdin、stdout 和 stderr 无关。

At the file descriptor level, stdin is defined to be file descriptor 0 , stdout is defined to be file descriptor 1 ;文件描述符层面, stdin定义为文件描述符 0stdout定义为文件描述符 1 and stderr is defined to be file descriptor 2 .并且stderr被定义为文件描述符 2 See this .看到这个

Even if your program -or the shell- changes (eg redirect with dup2(2) ) what is file descriptor 0, it always stays stdin (since by definition STDIN_FILENO is 0).即使您的程序 - 或外壳程序 - 更改(例如使用dup2(2)重定向文件描述符 0 是什么,它也始终保持标准输入(因为根据定义STDIN_FILENO为 0)。

So of course stdin could be a pipe or a socket or a file (not a terminal).所以当然stdin可以是管道、套接字或文件(​​不是终端)。 You could test with isatty(3) if it is a tty, and/or use fstat(2) to get status information on it.您可以使用isatty(3)测试它是否是 tty,和/或使用fstat(2)获取有关它的状态信息。

Syscalls like open(2) or pipe(2) or socket(2) may give eg STDIN_FILENO (ie 0) if that file descriptor is free (eg because it has been close(2) -d before).如果该文件描述符是空闲的(例如,因为它之前已close(2) -d),则像open(2)pipe(2)socket(2) 之类的系统调用可能会给出例如STDIN_FILENO (即 0)。 But when that occurs, it is still stdin by definition.但是当发生这种情况时,根据定义它仍然是标准输入

Of course, in stdio(3) , the FILE stream stdin is a bit more complex.当然,在stdio(3) 中FILEstdin稍微复杂一些。 Your program could fclose(3) , freopen(3) , fdopen(3) ...你的程序可以fclose(3) , freopen(3) , fdopen(3) ...

Probably the kernel sets stdin , stdout , and stderr file descriptors to the console when magically starting /sbin/init as the first process./sbin/init作为第一个进程神奇地启动时,内核可能会将 stdinstdoutstderr文件描述符设置到控制台。

  1. When a program begins, does it take file descriptor 0 1 2 for stdin, stdout and stderr by default .当程序开始时,默认情况下是否为 stdin、stdout 和 stderr 使用文件描述符 0 1 2 。

    If you launch your program in an interactive shell normally, yes.如果您通常在交互式 shell 中启动您的程序,是的。

    By @EJP:来自@EJP:

    Inheriting a socket as FD 0 also happens if the program is started by inetd, or anything else that behaves the same way.如果程序由 inetd 或其他任何行为相同的方式启动,则将套接字继承为 FD 0 也会发生。

  2. will the API such as open(...), socket(...) not return 0 1 2 since these value are already be taken.诸如 open(...)、socket(...) 之类的 API 是否不会返回 0 1 2,因为这些值已被采用。

    Yes.是的。

  3. Is there any case that open(...) or socket(...) would return 0 1 2.是否有任何情况 open(...) 或 socket(...) 会返回 0 1 2。

    Yes, if you do something like是的,如果你做类似的事情

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

Though a couple of answers already existed but I didn't find them informative enough that they explained the complete story.尽管已经存在一些答案,但我发现它们的信息量不足以解释完整的故事。

Since I went ahead and researched more, I am adding my findings.由于我继续进行并进行了更多研究,因此我正在添加我的发现。

Whenever a process starts, an entry of the running process is added to the /proc/<pid> directory.每当进程启动时,正在运行的进程的条目都会添加到/proc/<pid>目录中。 This is the place where all of the data related to the process is kept.这是保存与流程相关的所有数据的地方。 Also, on process start the kernel allocates 3 file-descriptors to the process for communication with the 3 data streams referred to as stdin , stdout and stderr .此外,在进程启动时,内核为进程分配 3 个文件描述符,用于与 3 个数据流(称为stdinstdoutstderr
the linux kernel uses an algorithm to always create a FD with the lowest possible integer value so these data-streams are mapped to the numbers 0 , 1 and 2 . linux 内核使用一种算法来始终创建一个具有尽可能低的整数值的 FD,因此这些数据流被映射到数字012

Since these are nothing but references to a stream and we can close a stream.由于这些只是对流的引用,因此我们可以关闭流。 One can easily call close(<fd>) , in our case close(1) , to close the file descriptor.可以很容易地调用close(<fd>) ,在我们的例子中是close(1) ,来关闭文件描述符。

on doing ls -l /proc/<pid>/fd/ , we see only 2 FDs listed there 0 and 2 .在执行ls -l /proc/<pid>/fd/ ,我们只看到02列出了 2 个 FD。
If we now do an open() call the kernel will create a new FD to map this new file reference and since kernel uses lowest integer first algorithm, it will pick up the integer value 1 .如果我们现在调用open() ,内核将创建一个新的 FD 来映射这个新的文件引用,并且由于内核使用最低整数优先算法,它将获取整数值1

So now, the new FD created points to the file we opened (using the open() syscall)所以现在,新创建的 FD 指向我们打开的文件(使用open()系统调用)
Any of the data transfer that happens now is not via the default data-stream that was earlier linked but the new file that we opened.现在发生的任何数据传输都不是通过先前链接的默认数据流,而是通过我们打开的新文件。

So yes, we can map the FD 0 , 1 or 2 to any of the file and not necessary stdin , stdout or stderr所以是的,我们可以将 FD 012映射到任何文件,而不需要stdinstdoutstderr

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM