我试图了解网络驱动程序在 Linux 下如何工作。本次问答表明 Linux 中的网络设备不是由设备文件表示的。它指出网络驱动程序与sockets
.
例如,这参考如何通过ioctl
呼叫设置网络设备。ioctl
然而需要一个文件描述符,鉴于没有网络驱动程序的设备文件,唯一可以传递的文件描述符是来自套接字的文件描述符。
这让我想到了问题的重点。到目前为止,网络接口(物理网卡的软件表示)实际上是一个比套接字低级的对象。
但从这个抽象意义上讲,套接字是什么?它只是支持推送通知的设备文件的另一个名称吗?我根据用户空间应用程序绑定到网络接口上的地址:端口对的连接点来理解 TCP 套接字。我不明白套接字是设置网络接口的先决条件。
Linux 上的网络接口(如
eth0
列出的ifconfig
)可以在没有套接字的情况下存在吗?某些网络管理器守护程序是否
ifconfig
保持套接字打开以允许我们设置网络接口选项?
答案1
让我们快速回顾一下设备文件:在Linux中,应用程序通过以下方式向内核传达读写操作:文件描述符。这对于文件来说非常有效,而且事实证明相同的 API 也可以用于字符设备产生和消耗字符流,以及块设备在随机访问地址读取和写入固定大小的块,只需假装它们也是文件。
但是需要一种方法来配置这些设备(设置波特率等),为此,读写控制电话被发明了。它只是传递特定于设备的数据结构和用于内核的 I/O 控制类型,并以相同的数据结构返回结果,因此它是一个非常通用的可扩展 API,可用于很多事情。
现在,网络运营如何适应?一个典型的网络服务器应用程序想要绑定到某个网络地址,听在某个端口上(例如 HTTP 为 80,ssh 为 22),并且如果客户端连接,它想要发送数据至 和收到来自该客户端的数据。并为客户端进行双重操作。
如何将其与文件操作相适应并不明显(尽管可以做到,请参阅计划9),这就是 UNIX 设计者发明新 API 的原因:插座。您可以在socket
、bind
、listen
、connect
和send
的第 2 部分手册页中找到详细信息recv
。请注意,虽然它与文件 I/O API 不同,但该socket
调用仍然返回一个文件描述符。网上有很多关于如何使用套接字的教程,google一下。
到目前为止,这都是纯粹的 UNIX,在发明套接字时没有人谈论网络接口。而且因为这个 API 确实很旧,所以它是为 Internet 协议之外的各种网络协议定义的(查看常量AF_*
),尽管 Linux 中只支持其中的一小部分。
但随着计算机开始配备多个网卡,需要对此进行一些抽象。在 Linux 中,那就是网络接口(你)。它不仅用于硬件,还用于各种隧道,以及充当 OpenVPN 等隧道的用户应用程序端点。正如所解释的,套接字 API 不基于(特殊)文件,并且独立于文件系统。同样,网络接口也不会出现在文件系统中。但是,NI 在文件/proc
系统/sys
(以及其他网络可调参数)中可用。
NI 是网络数据包进入和离开内核的端点的简单内核抽象。另一方面,套接字用于与应用程序进行数据包通信。不需要套接字参与数据包的处理。例如,当启用转发时,数据包可能会在一个 NI 上进入并在另一个 NI 上离开。从这个意义上说,套接字和网络接口是完全独立的。
但是必须有一种方法来配置 NI,就像您需要一种方法来配置块和字符设备一样。由于套接字已经返回了一个文件描述符,因此只允许ioctl
该文件描述符上的一个在某种程度上是合乎逻辑的。这就是网络设备您链接的界面。
还有很多其他以类似方式滥用系统调用的行为,例如数据包过滤、数据包捕获等。
所有这一切都是一点一点地发展起来的,而且在很多地方并不是特别合乎逻辑。如果一次性设计出来,人们可能会制作出更加正交的 API。