套接字描述符vs文件描述符

16

read(2)和write(2)可同时适用于套接字描述符和文件描述符。对于文件描述符,它会先访问用户文件描述符表->文件表,最后到inode表中检查文件类型(普通文件/字符设备/块设备),并相应地进行读取。对于字符特殊文件,它会从字符设备开关中获取基于文件主设备号的函数指针,并调用为该设备注册的适当的读写例程。 类似地,从块设备开关获取函数指针,将为块特殊文件调用适当的读/写例程。

当在套接字描述符上调用read/write时,您能否告诉我实际发生了什么。如果read/write适用于套接字描述符,我们为什么不能使用open来获取描述符呢?

当在套接字描述符上调用read/write时,数据被发送到网络或者从网络接收,并且传输的数据是按照协议进行封装的。open系统调用不包含任何这样的语义,因此无法用于套接字。要获得套接字描述符,需要调用socket系统调用。

无法告诉你发生了什么(如果你真的想知道,请查看内核源代码),但基本上它会将请求传递给TCP驱动程序,后者会将其进一步传递到网络堆栈下面,直到达到网络接口卡的驱动程序。如果您想以一般术语了解网络堆栈的每个层次所做的事情,请查阅OSI模型。至于“open”与“socket”的区别:它们需要不同的参数,因为需要指定的信息取决于您是要打开文件还是套接字。 - David
我想知道在调用socket()时分配了哪些数据结构,inode表中存储了哪些信息,以及在调用read/write时它是如何最终到达网络接口卡驱动程序的。 - Ganesh Kundapur
1
请注意,读/写包装系统调用。大部分工作都在内核空间完成。这是一种抽象或“虚拟化”:只需将块文件、套接字或许多其他东西视为“文件”。文件具有读取、写入、打开等操作。但是,从套接字或磁盘文件中读取的真正实现是在内核中定义的。如果需要,甚至可以将“写入”定义为从文件中读取。 - tristan
3个回答

18
据我所知,文件描述符中包含标志来识别此FD的文件系统类型。内核将根据文件系统类型调用相应的处理程序函数。您可以在Linux内核中查看源代码read_write.c。
简而言之,内核执行了以下操作:
  1. 在read_write.c中,有一个file_system_wrapper函数,它根据fd的文件类型(ext2 / ext3 / socket /..)调用相应的处理程序函数。
  2. 在socket.c中,有一个socket_type_wrapper函数;它根据socket的类型(ipv4、ipv6、atm等)调用相应的套接字处理程序函数。
  3. 在socket_ipv4.c中,有一个protocol_type包装函数;它根据协议类型(UDP / TCP)调用相应的协议处理程序函数。
  4. 在tcp_ip4.c中,有一个tcp_sendmsg函数,当写入tcp ipv4类型的FD时将调用该函数。
希望这样清楚明了。 谢谢, Houcheng

6

Socket描述符也与文件结构相关联,但是用于该结构的一组file_operations函数与通常不同。因此,这些描述符的初始化和使用也不同。内核级接口的读取和写入部分恰好完全等效。


我想知道在调用socket()时分配了哪些数据结构,inode表中存储了哪些信息,以及在调用read/write时它是如何最终到达网络接口卡驱动程序的。 - Ganesh Kundapur
并非偶然发生,而是故意制造成相同的。 - Yerken

0

在某些状态下,读写对于某些类型的套接字是有效的;这完全取决于内核中传递的各种结构。

原则上,open()可以创建套接字描述符,但BSD套接字API从未定义过这种方式。

还有一些其他(有点特定于Linux的)文件描述符类型是通过系统调用而不是open()打开的,例如epoll_create或timerfd_create。它们的工作方式相同。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接