> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/4.3-bsd-unix-cao-zuo-xi-tong-she-ji-yu-shi-xian/di-si-bu-fen-jin-cheng-jian-tong-xin/11.2.-tao-jie-zi-xie-yi-jie-kou.md).

# 11.2 套接字-协议接口

套接字例程到通信协议的接口，经由每个协议的协议开关表中定义的用户请求例程 `pr_usrreq()` 和控制输出例程 `pr_ctloutput()`。套接字层需要支撑协议的服务时，调用这两个例程之一。控制输出例程实现 `getsockopt` 和 `setsockopt` 系统调用；其余操作都用用户请求例程。对 `pr_usrreq()` 的调用指定表 11.3 所列请求之一；对 `pr_ctloutput()` 的调用指定 PRCO\_GETOPT 取选项当前值或 PRCO\_SETOPT 设选项值。

表 11.3 pr\_usrreq 例程的请求

| 请求              | 描述               |
| --------------- | ---------------- |
| PRU\_ABORT      | 中止连接并脱离          |
| PRU\_ACCEPT     | 接受来自对端的连接        |
| PRU\_ATTACH     | 把协议附接到套接字        |
| PRU\_BIND       | 把名字绑定到套接字        |
| PRU\_CONNECT    | 建立到对端的连接         |
| PRU\_CONNECT2   | 连接两个套接字          |
| PRU\_CONTROL    | 控制协议操作（`ioctl`）  |
| PRU\_DETACH     | 使协议脱离套接字         |
| PRU\_DISCONNECT | 与对端断开            |
| PRU\_FASTTIMO†  | 服务 200 毫秒超时      |
| PRU\_LISTEN     | 监听连接             |
| PRU\_PEERADDR   | 取对端地址            |
| PRU\_PROTORCV†  | 从下层接收            |
| PRU\_PROTOSEND† | 发送到下层            |
| PRU\_RCVD       | 已取走数据；腾出了空间      |
| PRU\_RCVOOB     | 取回带外数据           |
| PRU\_SEND       | 发送这些数据           |
| PRU\_SENDOOB    | 发送带外数据           |
| PRU\_SENSE      | 感知套接字状态（`fstat`） |
| PRU\_SHUTDOWN   | 不再发送任何数据         |
| PRU\_SLOWTIMO†  | 服务 500 毫秒超时      |
| PRU\_SOCKADDR   | 取套接字的地址          |

† 仅供协议内部使用的请求。

**协议用户请求例程**

给定指向协议开关表项 `pr` 的指针，对用户请求例程的调用形如：

```c
    error = (*pr->pr_usrreq)(so, req, m, addr, rights);
      struct socket *so;
      int req;
      struct mbuf *m, *addr, *rights;
```

mbuf 数据链 *m* 用于输出操作及某些要返回结果的操作。地址 *addr* 用于面向地址的请求，如 PRU\_BIND、PRU\_CONNECT 和 PRU\_SEND（指定地址时，如 `sendto`）。*rights* 参数是指向可选的、装着用户指定访问权的 mbuf 链的指针（见 10.6 节）。输出操作中数据 mbuf 链的处置由各协议负责。用户请求例程返回非零表示应传给更高层软件的 UNIX 错误号。各可能请求描述如下。

* **PRU\_ATTACH：把协议附接到套接字** 协议首次绑定到套接字（`socket` 系统调用）时，带 PRU\_ATTACH 请求调用协议模块。协议模块负责分配一切必要资源。attach 请求总在其他请求之前，且至多出现一次。
* **PRU\_DETACH：使协议脱离套接字** 这一操作与 attach 相对，在套接字删除时使用。协议模块可释放分配给套接字的资源。
* **PRU\_BIND：把地址绑定到套接字** 套接字最初创建时没有绑定地址。这一请求表示应把一个地址绑定到既有套接字。协议模块必须核实所请求的地址有效且可用。
* **PRU\_LISTEN：监听入局连接** listen 请求表示用户想在关联的套接字上监听入局连接请求。协议模块应做实现这一请求所需的状态变化（若可能）。listen 请求总在任何接受连接的请求之前。
* **PRU\_CONNECT：把套接字连接到对端** connect 请求表示用户想建立一个关联。所给的 `addr` 参数描述要连接的对端。connect 请求的效果因协议而异：虚电路协议用它发起网络连接的建立；数据报协议只是把对端地址记进私有数据结构，用来标记所有外出的分组。attach 之后 connect 请求的使用次数不受限制。
* **PRU\_ACCEPT：接受未决连接** 成功的 listen 请求之后到来一条或多条连接时，这一请求表示用户即将从已完成连接的套接字队列中接受一个套接字。作为参数给出的套接字正被 **接受**；协议模块应把与该套接字相连的对端地址填进所给的缓冲。
* **PRU\_DISCONNECT：断开已连接的套接字** 消除由 connect 请求建立的关联。这一请求在数据报套接字上用于新关联建立之前；面向连接的协议只在套接字关闭时使用它。
* **PRU\_SHUTDOWN：关闭套接字数据发送** 这一调用表示不再发送数据。协议可自行决定释放与关闭相关的数据结构和/或通知相连的对端。
* **PRU\_RCVD：用户已收到数据** 只有协议开关表项含 PR\_WANTRCVD 标志时才发这一请求。套接字层从接收队列取走数据交给用户时，向协议模块发送该请求。协议可用它触发确认、刷新窗口信息、发起数据传输等。
* **PRU\_SEND：发送用户数据** 每次用户发送数据的请求被翻译成一个或多个 PRU\_SEND 请求。协议在协议描述中指定 PR\_ATOMIC 标志，即可要求单次用户发送请求必须翻译成单次 PRU\_SEND 请求。待发数据以 mbuf 链呈交协议，可选地址放在 `addr` 参数中。协议若不能立即发送数据、或日后可能需要（如重传），负责把数据保存在套接字的发送队列中。
* **PRU\_ABORT：异常终止服务** 这一请求表示服务的异常终止，协议应删除既有的关联。
* **PRU\_CONTROL：执行控制操作** 用户对套接字做 `ioctl` 系统调用而 `ioctl` 未被套接字例程拦截时，产生 control 请求。它允许在公共套接字接口的范围之外提供协议专有的操作。`addr` 参数含指向内核数据区的指针，可在其中获取或返回相关信息；`m` 参数含实际的 `ioctl` 请求码；`rights` 参数在 `ioctl` 操作涉及特定网络接口时含指向网络接口结构的指针。
* **PRU\_SENSE：感知套接字状态** 用户对套接字做 `fstat` 系统调用时产生 sense 请求，查询关联套接字的状态。返回标准 `stat` 结构，通常只含连接的最优传输大小（基于缓冲大小、窗口信息和最大分组大小）。
* **PRU\_RCVOOB：接收带外数据** 返回当前可用的任何 **带外** 数据。向协议模块传一个 mbuf，协议应把数据放进 mbuf，或单个 mbuf 空间不足时在其上再接新 mbuf。带外数据（尚）不可用或已被消费时可以返回错误。`addr` 参数含执行本请求时应遵守的任何选项，如 MSG\_PEEK。
* **PRU\_SENDOOB：发送带外数据** 类似发送请求，用于带外数据。
* **PRU\_SOCKADDR：取本地套接字地址** 返回套接字的本地地址（若已绑定）。地址（以域专有格式）在 `addr` 参数传入的 mbuf 中返回。
* **PRU\_PEERADDR：取对端套接字地址** 返回套接字所连对端的地址。套接字必须处于连接状态才能向协议发这一请求。地址（以域专有格式）在 `addr` 参数所指 mbuf 中返回。
* **PRU\_CONNECT2：不绑定地址连接两个套接字** 给协议模块两个套接字，请求（若可能）在两者之间建立连接而不绑定任何地址。这一调用用于实现 `socketpair` 系统调用。

**内部请求**

以下请求仅供协议模块内部使用，套接字例程从不产生。某些场合它们只是为追踪协议运作提供方便（如慢超时请求）。

* **PRU\_FASTTIMO：服务快超时** 快超时发生。协议的 `pr_fasttimo()` 例程中发生超时时发出这一请求。`addr` 参数指明哪个定时器到期。
* **PRU\_SLOWTIMO：服务慢超时** 慢超时发生。协议的 `pr_slowtimo()` 例程中发生超时时发出这一请求。`addr` 参数指明哪个定时器到期。
* **PRU\_PROTORCV：为协议接收数据** 这一请求用于协议之间，套接字层不用；请求接收发给协议而非用户的数据。目前没有协议使用这一设施。
* **PRU\_PROTOSEND：向协议发送数据** 允许协议向另一个协议模块（而非用户）发送数据。数据如何标记为“发给协议”而不是“发给用户”，留待协议模块自行处理。目前没有协议使用这一设施。

**协议控制输出例程**

对控制输出例程的调用形如：

```c
error = (*pr->pr_ctloutput)(op, so, level, optname, mp);
    struct socket *so;
    int level, optname;
    struct mbuf **mp;
```

*op* 设选项值时为 PRCO\_SETOPT，取值时为 PRCO\_GETOPT。`level` 参数指明应解释选项请求的软件层：控制套接字层的选项指定 SOL\_SOCKET；选项由套接字层之下的协议模块处理时，`level` 设为相应的协议号（与 `socket` 系统调用所用相同）。每层有自己的选项名集合，名字只被目标软件层解释。最后一个参数是指向 mbuf 链指针的指针：设置时既有的链含选项的新值；获取时用该指针返回含选项值的 mbuf 链。设置选项值时传给控制输出例程的 mbuf 必须由协议释放；获取选项值时返回选项值的 mbuf 由协议分配、交还套接字层，数据复制给用户后在那里释放。

支持 `getsockopt` 和 `setsockopt` 系统调用时，套接字层总是调用套接字所附协议的控制输出例程。要访问更低层的协议，每个控制输出例程必须把不属于自己的控制输出请求向 **下** 传递给协议层次中的下一个协议。第 12 章描述 Internet 和 XNS 通信域中协议提供的部分选项。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://book.bsdcn.org/4.3-bsd-unix-cao-zuo-xi-tong-she-ji-yu-shi-xian/di-si-bu-fen-jin-cheng-jian-tong-xin/11.2.-tao-jie-zi-xie-yi-jie-kou.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
