我试图研究文件描述符以及它们如何与Rust中的tcp连接交互,我对Rust编程和Unix都很陌生。
最后,我想通过匹配文件描述符来将一些程序的stdio绑定到tcp发送/接收。现在,我只想了解文件描述符是如何分配的,以及为什么它们会得到不同的值。
我写了这个简单的代码来做实验:
use std::{
net::TcpListener,
os::fd::AsFd
};
fn main() {
let listener = TcpListener::bind("0.0.0.0:1024").unwrap();
println!("Listener fd: {:?}", listener.as_fd());
for stream in listener.incoming() {
let stream = stream.unwrap();
println!("Stream fd: {:?}", stream.as_fd());
}
}
字符串
当我运行这个程序时,我得到的第一行是:
Listener fd: BorrowedFd { fd: 3 }
型
当我随后向tcp侦听器发送一些数据时,它会像我期望的那样打印出如下行:
Stream fd: BorrowedFd { fd: 4 }
型
我想了解的是:
- 为什么文件描述符不同?
- 每个文件描述符对应于什么,即使用3对应于连接的传入数据,使用4对应于我可以写回流的数据?
1条答案
按热度按时间oyxsuwqo1#
文件描述符是内核向某些功能公开的不透明句柄。在您的情况下,文件描述符#3由
socket()
和bound获取到端口。这反过来允许您在其上调用accept()
以获取更多文件描述符(例如您的#4),这些描述符可用于与不同连接的客户端进行通信。文件描述符#4是你对连接的对等体的句柄。它支持像
read()
和write()
这样的操作(以及许多其他操作,如select()
)。这些操作通常在对应于打开文件的文件描述符上提供,这就是Unix提供多态性的方式。对同一个文件描述符的读写操作不会相互干扰,因为它们是不同的操作,操作系统足够聪明,可以区分它们。在数字4后面,内核保留了一个完整的数据结构,其中包含单独的读写缓冲区,控制流标志等等。只有在用户空间中,它才被表示为一个数字,你可以把它看作是内核中保存的一个表的索引。