[英]How to properly read a process's file descriptors?
我正在编写一个小程序来列出特定进程的文件描述符,但我很难理解结果。 我正在检查的过程如下所示:
int main() {
int fds1[2];
int fds2[2];
pipe(fds1);
pipe(fds2);
pid_t pid = fork();
if (pid == 0) {
dup2(fds1[0], STDIN_FILENO);
dup2(fds2[1], STDOUT_FILENO);
close(fds1[0]);
close(fds1[1]);
close(fds2[0]);
close(fds2[1]);
sleep(2);
return 0;
}
close(fds1[0]);
close(fds2[1]);
waitpid(pid, NULL, 0);
return 0;
}
fd 检查程序代码如下所示:
let path_str = format!("/proc/{}/fd", self.pid);
let dir = Path::new(&path_str);
let mut fds = Vec::new();
for entry in fs::read_dir(dir).ok()? {
let path = entry.ok()?.path();
let filename = path.file_name()?;
let fd = fname.to_str()?.to_string().parse::<usize>().ok()?
fds.push(fd);
}
一起运行上述程序时ls -l /proc/{pid}/fd
的结果给了我这个列表:
0 -> /dev/pts/6
1 -> /dev/pts/6
2 -> /dev/pts/6
22 -> /dev/pts/1
30 -> /dev/pts/4
4 -> /home/{user}/.spectrwm.conf
5 -> 'pipe:[168640]'
6 -> 'pipe:[168641]'
我很困惑为什么/dev/pts/x
有 5 个符号链接,为什么底部的 3 个 fds 包含在这个进程的文件描述符中,尤其是我的 WM 的配置文件中。 我对pipe
和fork
的工作原理有基本的了解,但我似乎无法理解这里发生了什么。
任何帮助或见解将不胜感激,谢谢!
我要注意的第一件事是与spectrwm.conf
关联的文件描述符可能是由您的 window 管理器以某种方式打开的(可能通过 LD_PRELOAD 或类似的东西)。 您可以使用strace
查看打开了哪些文件描述符以及如何打开(但是,在这种情况下,您应该使用标志-ff
,因为您正在分叉一个新进程)。
您还可以使用 GDB 来识别何时进行某些系统调用(即打开),以识别您的进程在执行的哪个时间点打开与/home/{user}/.spectrwm.conf
关联的文件描述符(参见catchpoints )。
至于其他文件描述符,为了帮助您了解发生了什么,我再次运行了您的代码。 以下是父进程的文件描述符:
user@pop-os:~$ ls -l /proc/39783/fd
total 0
lrwx------ 1 user user 64 Mar 21 14:03 0 -> /dev/pts/0
lrwx------ 1 user user 64 Mar 21 14:03 1 -> /dev/pts/0
lrwx------ 1 user user 64 Mar 21 14:03 2 -> /dev/pts/0
l-wx------ 1 user user 64 Mar 21 14:03 4 -> 'pipe:[544306]'
lr-x------ 1 user user 64 Mar 21 14:03 5 -> 'pipe:[544307]'
我为父进程看到的文件描述符都是有意义的。 回想一下, STDIN
、 STDOUT
和STDERR
的文件描述符2
是0
和1
。 所有这些文件描述符都指向/dev/pts/0
这是一个伪终端(您用来运行代码的终端)。 接下来,父进程中的文件描述符4
和5
分别对应pipe的读写端。 Recall that the libc pipe
function fills an array of length two for the reading and writing ends (but you close two of the file descriptors associated with your pipes -- the reading end of pipe fds1
and the writing end of pipe fds2
so the open file描述符在父级中有意义)。
以下是子进程的文件描述符:
user@pop-os:~$ ls -l /proc/39784/fd
total 0
lr-x------ 1 user user 64 Mar 21 14:03 0 -> 'pipe:[544306]'
l-wx------ 1 user user 64 Mar 21 14:03 1 -> 'pipe:[544307]'
lrwx------ 1 user user 64 Mar 21 14:03 2 -> /dev/pts/0
这些文件描述符也很有意义。 回想一下dup2
创建文件描述符的副本,但将复制的文件描述符分配给特定编号。 这允许您执行进程间通信(这也是 shell 用来实现 pipe 运算符|
的方式——只需派生n
进程,创建n - 1
管道,并创建适当的dup2
调用)。
In your child process, we can see that you duplicate the pipe fds to STDIN
and STDOUT
, which is why you see the reading end of the first pipe associated with STDIN_FILENO
and the writing end of the second pipe associated with STDOUT_FILENO
. 最后一个文件描述符,本例中的STDERR_FILENO
, /dev/pts/0
仍然连接到终端,因为您没有dup2
调用它。
我不知道你想用你的程序做什么,但我确实有一些问题/注意事项给你:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.