socket() 函数的内部机制是什么?

What is the internal mechanics of socket() function?

我正在尝试使用 BlueZ HCI 功能:

int hci_open_dev(int dev_id) {...}

它在内部尝试创建这样的套接字:

socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI);

我试图理解 socket() 的 linux 内核代码,但感到迷茫。

我想知道为给定域 (AF_BLUETOOTH)、数据传输类型 (SOCK_RAW) 和协议 (BTPROTO_HCI) 创建套接字究竟意味着什么。

手册页只是说明它采用这些参数,创建套接字和 returns 设备描述符。

但我想了解到底发生了什么以及创建套接字所涉及的确切内核步骤。

这里是一个非常广泛的描述(希望有助于理解主要方案)。
内核开发人员可能会被吓坏了...

一个套接字是许多不同通信方式的通用抽象接口。
它提供了许多通用操作,例如关闭、sending/receiving数据、setting/retrieving选项,几乎可以在任何类型的套接字上使用。

创建套接字意味着指定此通信方式的确切属性。
有点像实现接口的具体类型的实例化。

这些属性首先由协议族组织;这是 socket() 调用的第一个参数。
例如:

  • PF_INET用于依赖IPv4的通信,
  • PF_INET6用于依赖IPv6的通信,
  • PF_LOCAL用于inter-process系统内部通信(管道类),
  • PF_NETLINK用于与OS内核通信,
  • PF_PACKET用于与网络接口直接通信,
  • ...(存在很多)

一旦选择了一个协议族,你必须指定,你想在这个族提供的协议中使用哪个协议;这是 socket() 调用的第二个参数。
例如:

  • SOCK_DGRAM 用于 IPv4 或 IPv6 上的 UDP,或 PF_LOCAL、
  • 中的不同消息
  • SOCK_STREAM用于IPv4或IPv6上的TCP,或PF_LOCAL、
  • 中的连续字节流
  • SOCK_RAW,直接访问是家族中原始的底层协议(例如IPv4,或IPv6),
  • ...(每个家庭可以提供很多)

一些协议可以接受一些变体或一些限制;这是 socket() 调用的第三个参数。
通常 0 就足够了,但是例如我们可以找到:

  • PF_PACKET、SOCK_RAW、htons(ETH_P_ALL) 捕获在网络接口上接收到的任何类型的网络数据包,
  • PF_PACKET, SOCK_RAW, htons(ETH_P_ARP) 只捕获 ARP 帧,

当我们请求使用这三个参数创建套接字时,操作系统会创建一个与将要获取的套接字句柄关联的内部资源。
当然,此资源的确切结构取决于所选择的 family/protocol/variant,并且它与特定于它的内核回调相关联。
每次在此套接字上调用操作(通过系统调用)时,都会调用特定的回调。

请看这里:这是对 BlueZ Linux 蓝牙堆栈实现的很好的 high-level 描述:

Linux Without Wires The Basics of Bluetooth。具体来说,它可以让您很好地了解这些 BlueZ 内核驱动程序:

  • bluetooth.ko, which contains core infrastructure of BlueZ. It exports sockets of the Bluetooth family AF_BLUETOOTH. All BlueZ modules utilise its services.

  • Bluetooth HCI packets are transported over UART or USB. The corresponding BlueZ HCI implementation is hci_uart.ko and hci_usb.ko.

  • The L2CAP layer of Bluetooth, which is responsible for segmentation, reassembly and protocol multiplexing, is implemented by l2cap.ko.

  • With the help of bnep.ko, TCP/IP applications can run over Bluetooth. This emulates an Ethernet port over the L2CAP layer. The kernel thread named kbnepd is responsible for BNEP connections.

  • rfcomm.ko is responsible for running serial port applications like the terminal. This emulates serial ports over the L2CAP layer. The kernel thread named krfcommd is responsible for RFCOMM connections.

  • hidp.ko implements the HID (human interface device) layer. The user mode daemon hidd allows BlueZ to handle input devices like Bluetooth mice.

  • sco.ko implements the synchronous connection oriented (SCO) layer to handle audio. SCO connections do not specify a channel to connect to a remote host; only the host address is specified.

另一个优秀的资源是 BlueZ 项目页面: