第 10 章 网络操作 --- 10.3.4 AFD驱动与Winsock
本节剖析 AFD(Ancillary Function Driver,afd.sys)与 Winsock(ws2_32.dll + msafd.dll)的实现。 AFD 是 内核态 Winsock ,实现 socket 内核对象、bind/connect/accept、select/异步通知。Winsock 是 用户态 API,把 socket 调用翻译为对 AFD 设备的 IOCTL。ReactOS 的 AFD 实现在 drivers/network/afd/afd/(file:///d:/reactos/drivers/network/afd/afd/),Winsock 在 dll/win32/ws2_32/(file:///d:/reactos/dll/win32/ws2_32/) 和 dll/win32/msafd/(file:///d:/reactos/dll/win32/msafd/)。
概述
Winsock 在 Windows 网络栈中的位置:
- 用户态 API :
ws2_32.dll提供socket()、bind()、connect()等 BSD 风格 API - 服务提供者 :
msafd.dll是 Service Provider,把 Winsock 调用翻译为对\Device\Afd的 IOCTL - 内核态实现 :
afd.sys实现 socket 状态机、select 通知、异步操作 - 协议栈:通过 TDI 与 TCP/IP 通信
本节内容概览
- 10.3.4.0 框架图
- 10.3.4.1 Winsock DLL 入口
- 10.3.4.2
ws2_32.dll核心 API - 10.3.4.3
msafd.dllService Provider - 10.3.4.4 AFD 驱动初始化
- 10.3.4.5 AFD 内部结构
- 10.3.4.6 AFD 派发函数
- 10.3.4.7 socket/connect/accept 实现
- 10.3.4.8 send/recv 与异步通知
- 10.3.4.9 总结与代码索引
学习目标
- 理解 Winsock 用户态/内核态划分
- 掌握 AFD 与 TCP/IP 之间的 TDI 接口
- 知道
socket()调用到 AFD 的路径 - 跟踪 select 通知机制
涉及的内核子系统
| 子系统 | 头文件/源文件 | 核心作用 |
|---|---|---|
| AFD 主 | drivers/network/afd/afd/main.c(file:///d:/reactos/drivers/network/afd/afd/main.c) | DriverEntry |
| AFD bind | bind.c(file:///d:/reactos/drivers/network/afd/afd/bind.c) | AfdBind |
| AFD connect | connect.c(file:///d:/reactos/drivers/network/afd/afd/connect.c) | AfdConnect |
| AFD listen | listen.c(file:///d:/reactos/drivers/network/afd/afd/listen.c) | AfdListen |
| AFD read | read.c(file:///d:/reactos/drivers/network/afd/afd/read.c) | AfdReceive |
| AFD write | write.c(file:///d:/reactos/drivers/network/afd/afd/write.c) | AfdSend |
| AFD select | select.c(file:///d:/reactos/drivers/network/afd/afd/select.c) | AfdSelect |
| AFD event | event.c(file:///d:/reactos/drivers/network/afd/afd/event.c) | 异步事件 |
| AFD 头 | afd.h(file:///d:/reactos/drivers/network/afd/afd/afd.h) | 数据结构 |
| Winsock DLL | dll/win32/ws2_32/(file:///d:/reactos/dll/win32/ws2_32/) | ws2_32.dll |
| MSAFD | dll/win32/msafd/(file:///d:/reactos/dll/win32/msafd/) | Service Provider |
| TCP/IP | drivers/network/tcpip/tcpip/(file:///d:/reactos/drivers/network/tcpip/tcpip/) | TCP/IP 协议栈 |
10.3.4.0 框架图
+-------------------------------------+
| 应用 (浏览器/游戏) |
| socket(), bind(), connect(), ... |
+-------------------------------------+
|
v
+-------------------------------------+
| ws2_32.dll (用户态 Winsock) |
| 翻译 API 为 IOCTL |
+-------------------------------------+
|
v
+-------------------------------------+
| msafd.dll (Service Provider) |
| 翻译 socket 调用为 IOCTL |
+-------------------------------------+
|
v DeviceIoControl
+-------------------------------------+
| AFD (afd.sys) 内核态 Winsock | 本节主题
| - socket 内核对象 |
| - bind/connect/accept |
| - select/异步通知 |
+-------------------------------------+
|
v TDI IOCTL
+-------------------------------------+
| TCP/IP (tcpip.sys) |
+-------------------------------------+
10.3.4.1 Winsock DLL 入口
ws2_32/(file:///d:/reactos/dll/win32/ws2_32/) 包含:
socket.c:socket()、bind()、connect()ws2_32.spec:导出表dllmain.c:DllMainasync.c:异步 select
socket() 调用路径
c
// ws2_32/socket.c
SOCKET WSAAPI socket(int af, int type, int protocol) {
SOCKET s;
// 1. 打开 \Device\Afd
HANDLE h = CreateFileW(L"\\Device\\Afd", ...);
// 2. IOCTL_AFD_CREATE 创 socket
AFD_CREATE_REQUEST req = {af, type, protocol};
AFD_CREATE_RESPONSE resp;
DeviceIoControl(h, IOCTL_AFD_CREATE, &req, sizeof(req), &resp, sizeof(resp), ...);
// 3. 复制句柄到调用方进程
s = resp.Handle;
return s;
}
bind() 调用路径
c
int WSAAPI bind(SOCKET s, const struct sockaddr *name, int namelen) {
AFD_BIND_REQUEST req = {s, name, namelen};
DeviceIoControl(s, IOCTL_AFD_BIND, &req, sizeof(req), ...);
return 0;
}
10.3.4.2 ws2_32.dll 核心 API
ws2_32.dll 导出的核心 API:
| API | 作用 | IOCTL |
|---|---|---|
socket |
创建 socket | IOCTL_AFD_CREATE |
bind |
绑定地址 | IOCTL_AFD_BIND |
connect |
连接 | IOCTL_AFD_CONNECT |
listen |
监听 | IOCTL_AFD_LISTEN |
accept |
接受连接 | IOCTL_AFD_ACCEPT |
send/WSASend |
发送 | IOCTL_AFD_SEND |
recv/WSARecv |
接收 | IOCTL_AFD_RECV |
closesocket |
关闭 | IOCTL_AFD_CLOSE |
WSAAsyncSelect |
异步通知 | IOCTL_AFD_EVENT_SELECT |
select |
多路复用 | IOCTL_AFD_SELECT |
getsockname |
名字 | IOCTL_AFD_GET_SOCK_NAME |
ioctlsocket |
IOCTL | IOCTL_AFD_SET_SOCK_MODE 等 |
connect() 路径
c
int WSAAPI connect(SOCKET s, const struct sockaddr *name, int namelen) {
AFD_CONNECT_REQUEST req = {s, name, namelen};
DWORD bytesReturned;
if (DeviceIoControl(s, IOCTL_AFD_CONNECT, &req, sizeof(req), NULL, 0, &bytesReturned, NULL)) {
return 0;
}
// 阻塞 vs 非阻塞
if (WSAGetLastError() == WSAEWOULDBLOCK) {
// 等待 select 通知
}
return SOCKET_ERROR;
}
10.3.4.3 msafd.dll Service Provider
msafd.dll 是 Microsoft Ancillary Function Driver 的用户态代理:
- 实现 Winsock 2 Service Provider Interface (SPI)
- 注册到
ws2_32.dll的 SPI 表 - 把所有 Winsock 调用翻译为对 AFD 设备的 IOCTL
SPI 表
msafd.dll 提供 WSPStartup 函数,填表如下:
c
int WSPAPI WSPStartup(WORD VersionRequested, LPWSPDATA WSPData,
LPWSAPROTOCOL_INFOW ProtocolInfo,
WSPUPCALLTABLE UpcallTable, LPWSPPROC_TABLE ProcTable)
{
ProcTable->lpWSPSocket = WSPSocket;
ProcTable->lpWSPBind = WSPBind;
ProcTable->lpWSPConnect = WSPConnect;
ProcTable->lpWSPAccept = WSPAccept;
ProcTable->lpWSPSend = WSPSend;
ProcTable->lpWSPRecv = WSPRecv;
// ...
}
应用通过 WSAStartup → WSPStartup 链获取 SPI。
WSPSocket
c
SOCKET WSPAPI WSPSocket(int af, int type, int protocol, ...) {
// 翻译为 IOCTL_AFD_CREATE
return WSPCommonSocket(af, type, protocol, ...);
}
SOCKET WSPCommonSocket(int af, int type, int protocol, ...) {
HANDLE h = OpenAfdDevice(); // 打开 \Device\Afd
AFD_CREATE_REQUEST req = {af, type, protocol};
AFD_CREATE_RESPONSE resp;
// 复制句柄
DuplicateHandle(GetCurrentProcess(), resp.Handle, GetCurrentProcess(), &s, ...);
return s;
}
10.3.4.4 AFD 驱动初始化
main.c(file:///d:/reactos/drivers/network/afd/afd/main.c):
c
NTSTATUS NTAPI
DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
UNICODE_STRING DeviceName;
PDEVICE_OBJECT DeviceObject;
// 1. 创建设备对象 \Device\Afd
RtlInitUnicodeString(&DeviceName, L"\\Device\\Afd");
IoCreateDevice(DriverObject, 0, &DeviceName, FILE_DEVICE_AFD, 0, FALSE, &DeviceObject);
AfdDeviceObject = DeviceObject;
// 2. 注册派发
DriverObject->MajorFunction[IRP_MJ_CREATE] = AfdCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = AfdClose;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = AfdCleanup;
DriverObject->MajorFunction[IRP_MJ_READ] = AfdRead;
DriverObject->MajorFunction[IRP_MJ_WRITE] = AfdWrite;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = AfdDispatchDeviceControl;
// 3. 初始化全局
InitializeListHead(&AfdEndpointListHead);
ExInitializeFastMutex(&AfdGlobalLock);
return STATUS_SUCCESS;
}
10.3.4.5 AFD 内部结构
端点(FCB)
c
typedef struct _AFD_ENDPOINT {
// 文件对象关联
PFILE_OBJECT FileObject;
// 状态
LONG State; // 监听/连接/关闭
LONG DisconnectMode; // 主动/被动
LONG EventFlags; // FD_READ | FD_WRITE | ...
// 地址
SOCKADDR LocalAddress;
ULONG LocalAddressLength;
SOCKADDR RemoteAddress;
ULONG RemoteAddressLength;
// 协议
LONG AddressFamily; // AF_INET
LONG SocketType; // SOCK_STREAM/SOCK_DGRAM
LONG Protocol; // IPPROTO_TCP/UDP
// TDI 句柄
HANDLE TdiAddressHandle;
HANDLE TdiConnectionHandle;
// 异步 I/O
PAFD_POLL PollList; // select 多路复用列表
LIST_ENTRY SelectListEntry;
// 缓冲
LIST_ENTRY ReceiveQueue;
LIST_ENTRY SendQueue;
// 工作项
PIO_WORKITEM WorkItem;
// 锁
FAST_MUTEX Lock;
} AFD_ENDPOINT, *PAFD_ENDPOINT;
10.3.4.6 AFD 派发函数
AfdDispatchDeviceControl(主派发)
c
NTSTATUS AfdDispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp);
ULONG IoControlCode = IoStack->Parameters.DeviceIoControl.IoControlCode;
PAFD_ENDPOINT Endpoint = IoStack->FileObject->FsContext;
switch (IoControlCode) {
case IOCTL_AFD_BIND:
Status = AfdBindSocket(Endpoint, ...);
break;
case IOCTL_AFD_CONNECT:
Status = AfdConnectSocket(Endpoint, ...);
break;
case IOCTL_AFD_LISTEN:
Status = AfdListenSocket(Endpoint, ...);
break;
case IOCTL_AFD_ACCEPT:
Status = AfdAcceptSocket(Endpoint, ...);
break;
case IOCTL_AFD_SEND:
Status = AfdSend(Endpoint, ...);
break;
case IOCTL_AFD_RECV:
Status = AfdReceive(Endpoint, ...);
break;
case IOCTL_AFD_SELECT:
Status = AfdSelect(Endpoint, ...);
break;
case IOCTL_AFD_EVENT_SELECT:
Status = AfdEventSelect(Endpoint, ...);
break;
// ...
}
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
10.3.4.7 socket/connect/accept 实现
AfdCreate(socket)
c
NTSTATUS AfdCreate(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp);
PAFD_CREATE_REQUEST CreateReq = IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
PAFD_ENDPOINT Endpoint;
// 1. 分配端点
Endpoint = ExAllocatePoolWithTag(NonPagedPool, sizeof(AFD_ENDPOINT), 'pdaF');
RtlZeroMemory(Endpoint, sizeof(AFD_ENDPOINT));
// 2. 初始化
Endpoint->AddressFamily = CreateReq->AddressFamily;
Endpoint->SocketType = CreateReq->SocketType;
Endpoint->Protocol = CreateReq->Protocol;
Endpoint->State = SOCKET_STATE_CREATED;
// 3. 打开协议设备
switch (CreateReq->AddressFamily) {
case AF_INET:
if (CreateReq->SocketType == SOCK_STREAM) {
Endpoint->TdiDeviceName = L"\\Device\\Tcp";
} else {
Endpoint->TdiDeviceName = L"\\Device\\Udp";
}
break;
}
ZwCreateFile(&Endpoint->TdiAddressHandle, ..., Endpoint->TdiDeviceName, ...);
// 4. 关联 FileObject
IoStack->FileObject->FsContext = Endpoint;
return STATUS_SUCCESS;
}
AfdBind
bind.c(file:///d:/reactos/drivers/network/afd/afd/bind.c):
c
NTSTATUS AfdBindSocket(PAFD_ENDPOINT Endpoint, PAFD_BIND_REQUEST BindReq) {
// 1. 打开地址对象
TDI_REQUEST_KERNEL_SET_ADDRESS_KERNEL_PARAMETERS SetAddr = {BindReq->Address, ...};
ZwDeviceIoControlFile(Endpoint->TdiAddressHandle, ..., IOCTL_TDI_SET_ADDRESS, ...);
// 2. 通知 TCP/IP 绑定地址
return STATUS_SUCCESS;
}
AfdConnect
connect.c(file:///d:/reactos/drivers/network/afd/afd/connect.c):
c
NTSTATUS AfdConnectSocket(PAFD_ENDPOINT Endpoint, PAFD_CONNECT_REQUEST ConnectReq) {
// 1. 打开连接对象
HANDLE TdiConn;
ZwCreateFile(&TdiConn, ..., "\\Device\\Tcp", ...);
// 2. 关联到地址
ZwDeviceIoControlFile(TdiConn, ..., IOCTL_TDI_ASSOCIATE_ADDRESS, ...);
// 3. 发起连接(TDI_CONNECT)
IO_STATUS_BLOCK IoStatus;
PIRP Irp = TdiBuildInternalDeviceControlIrp(TDI_CONNECT, ...);
// ... 设置超时等
NtStatus = NtIoCallDriver(TdiConn, Irp);
if (NtStatus == STATUS_PENDING) {
// 等待连接完成
}
return NtStatus;
}
AfdAccept
listen.c(file:///d:/reactos/drivers/network/afd/afd/listen.c):
c
NTSTATUS AfdAcceptSocket(PAFD_ENDPOINT Endpoint, PAFD_ACCEPT_REQUEST AcceptReq) {
// 服务端接收客户端连接
// 创建新 socket 表示客户端连接
// 等待连接完成
}
10.3.4.8 send/recv 与异步通知
AfdSend(send)
write.c(file:///d:/reactos/drivers/network/afd/afd/write.c):
c
NTSTATUS AfdSend(PAFD_ENDPOINT Endpoint, PAFD_SEND_INFO SendInfo, ...) {
// 1. 构造 TDI_SEND 请求
TDI_REQUEST_KERNEL_SEND SendRequest;
SendRequest.SendFlags = SendInfo->Flags;
SendRequest.UserData = SendInfo->BufferArray;
SendRequest.UserDataLength = SendInfo->BufferCount;
// 2. 构造 IRP
PIRP Irp = TdiBuildSendDatagram(Endpoint->TdiConnectionHandle, ...);
// 3. 发送
return IoCallDriver(Endpoint->TdiDeviceObject, Irp);
}
AfdReceive(recv)
read.c(file:///d:/reactos/drivers/network/afd/afd/read.c):
c
NTSTATUS AfdReceive(PAFD_ENDPOINT Endpoint, PAFD_RECV_INFO RecvInfo, ...) {
PIRP Irp = TdiBuildReceive(Endpoint->TdiConnectionHandle, ...);
return IoCallDriver(Endpoint->TdiDeviceObject, Irp);
}
异步通知(select / WSAEventSelect)
select.c(file:///d:/reactos/drivers/network/afd/afd/select.c):
c
NTSTATUS AfdSelect(PAFD_ENDPOINT Endpoint, PAFD_POLL PollInfo) {
// 1. 注册 select
Endpoint->PollState = PollInfo->PollState;
Endpoint->EventFlags |= PollInfo->PollEvents;
// 2. 把 Endpoint 加入全局 Poll 列表
InsertTailList(&AfdEndpointListHead, &Endpoint->PollListEntry);
// 3. 立即检查可读/可写
if (数据已到达) {
KeSetEvent(PollInfo->Event, 0, FALSE);
} else {
// 等待
// 数据到达时 AfdReceiveComplete 唤醒
}
return STATUS_PENDING;
}
WSAEventSelect
WSAEventSelect 把 FD_READ 等事件映射为 Windows 事件对象。当对应事件触发时,AFD 设置事件:
c
VOID AfdEventSelectNotify(PAFD_ENDPOINT Endpoint, ULONG EventFlag) {
if (Endpoint->EventFlags & EventFlag) {
KeSetEvent(Endpoint->EventObject, 0, FALSE);
}
}
10.3.4.9 总结
关键要点:
- Winsock 三层结构 :
ws2_32.dll→msafd.dll→afd.sys ws2_32.dll翻译 API 为 IOCTLmsafd.dll是 Service Provider:实现 WSP 表- AFD 是内核 Winsock:维护 socket 状态、select 通知
- TDI 接口:AFD 与 TCP/IP 通过 TDI IOCTL 通信
- 设备对象 :
\Device\Afd、\Device\Tcp、\Device\Udp - 异步通知:通过事件对象或窗口消息
AFD 驱动与 Winsock 的深度技术分析
AFD(Ancillary Function Driver)和 Winsock 共同构成了 Windows 网络编程接口的基础设施。本节深入分析 AFD 驱动的内部实现机制、Winsock 的分层架构以及两者之间的协作方式。
AFD 驱动的核心职责
AFD 驱动(afd.sys)是 Windows 网络栈中的关键组件,它承担了以下核心职责:
-
Socket 对象管理:维护 socket 端点(FCB)的生命周期,包括创建、绑定、连接、监听、关闭等状态转换。
-
协议无关性抽象 :AFD 通过 TDI 接口与底层协议栈通信,使得上层应用无需关心使用的是 TCP 还是 UDP。AFD 根据 socket 类型(SOCK_STREAM 或 SOCK_DGRAM)自动选择正确的 TDI 设备(
\Device\Tcp或\Device\Udp)。 -
异步 I/O 支持:AFD 实现了完整的异步 I/O 机制,包括重叠 I/O、事件选择、异步选择等。这使得应用可以在不阻塞线程的情况下进行网络通信。
-
多路复用(select) :AFD 实现了 BSD 风格的
select系统调用,允许应用同时监控多个 socket 的可读、可写、异常状态。 -
缓冲管理:AFD 维护发送和接收缓冲区,协调应用层和协议栈之间的数据流。
AFD 端点(FCB)的详细结构
AFD 使用 AFD_FCB(File Control Block)结构表示每个 socket 端点。这个结构包含 socket 的所有状态信息:
c
typedef struct _AFD_FCB {
// 基础信息
LONG ReferenceCount; // 引用计数
FAST_MUTEX Lock; // 状态锁
// Socket 属性
LONG AddressFamily; // AF_INET, AF_INET6
LONG SocketType; // SOCK_STREAM, SOCK_DGRAM
LONG Protocol; // IPPROTO_TCP, IPPROTO_UDP
// 状态机
AFD_SOCKET_STATE State; // 当前状态
LONG DisconnectMode; // 断开模式
// 地址信息
PSOCKADDR LocalAddress; // 本地地址
ULONG LocalAddressLength;
PSOCKADDR RemoteAddress; // 远程地址
ULONG RemoteAddressLength;
// TDI 句柄
HANDLE TdiAddressHandle; // 地址对象句柄
HANDLE TdiConnectionHandle; // 连接对象句柄
PDEVICE_OBJECT TdiDeviceObject; // TDI 设备对象
// I/O 队列
LIST_ENTRY ReceiveQueue; // 接收 IRP 队列
LIST_ENTRY SendQueue; // 发送 IRP 队列
// 事件通知
LONG EventFlags; // FD_READ | FD_WRITE | ...
PKEVENT EventObject; // 事件对象
// select 支持
LIST_ENTRY PollList; // select 列表
LONG PollEvents; // 关心的事件
// 缓冲
ULONG ReceiveBufferSize;
ULONG SendBufferSize;
// 工作项
PIO_WORKITEM WorkItem; // 异步工作项
} AFD_FCB, *PAFD_FCB;
这个结构通过文件对象的 FsContext 字段关联,每个 socket 调用都通过文件对象找到对应的 FCB。
AFD 状态机
AFD 端点的状态机是 socket 生命周期的核心。状态转换如下:
CREATED → BOUND → LISTENING → CONNECTED → DISCONNECTING → CLOSED
↘ CONNECTING ↗
每个状态转换都有严格的前置条件:
bind只能在 CREATED 状态调用listen只能在 BOUND 状态调用connect可以在 BOUND 或 CREATED 状态调用send/recv只能在 CONNECTED 状态调用close可以在任何状态调用
AFD 通过 SocketAcquireStateLock 宏保护状态转换的原子性,防止并发调用导致的状态混乱。
TDI 通信机制详解
AFD 与 TCP/IP 协议栈通过 TDI(Transport Driver Interface)通信。TDI 使用标准的 Windows I/O 机制,通过 IRP_MJ_INTERNAL_DEVICE_CONTROL 传递请求。
TDI 请求的关键 IOCTL 代码:
| IOCTL | 功能 | 参数 |
|---|---|---|
IOCTL_TDI_ASSOCIATE_ADDRESS |
关联地址到连接 | 地址句柄 |
IOCTL_TDI_CONNECT |
建立连接 | 远程地址 |
IOCTL_TDI_DISCONNECT |
断开连接 | 超时、标志 |
IOCTL_TDI_SEND |
发送数据(TCP) | 缓冲、标志 |
IOCTL_TDI_RECEIVE |
接收数据(TCP) | 缓冲、标志 |
IOCTL_TDI_SEND_DATAGRAM |
发送数据报(UDP) | 目标地址、缓冲 |
IOCTL_TDI_RECEIVE_DATAGRAM |
接收数据报(UDP) | 缓冲、源地址 |
IOCTL_TDI_QUERY_INFORMATION |
查询 TDI 信息 | 信息类型 |
IOCTL_TDI_SET_EVENT_HANDLER |
设置事件回调 | 事件类型、回调 |
AFD 在发送 TDI 请求时,需要构造相应的 IRP 和 IO_STACK_LOCATION。例如,发送 TCP 数据的过程:
c
NTSTATUS AfdSend(PAFD_FCB Fcb, PIRP Irp) {
PIRP TdiIrp;
PMDL Mdl;
// 1. 锁定用户缓冲区
Mdl = IoAllocateMdl(UserBuffer, Length, FALSE, FALSE, NULL);
MmProbeAndLockPages(Mdl, UserMode, IoAccessMode);
// 2. 构造 TDI_SEND IRP
TdiIrp = TdiBuildInternalDeviceControlIrp(
TDI_SEND,
Fcb->TdiDeviceObject,
Fcb->TdiConnectionHandle,
NULL, NULL);
TdiBuildSend(TdiIrp, Fcb->TdiConnectionHandle, Mdl, 0, Length, NULL);
// 3. 发送并等待
Status = IoCallDriver(Fcb->TdiDeviceObject, TdiIrp);
return Status;
}
select 的实现机制
select 是 BSD socket API 中的多路复用机制,允许应用同时监控多个 socket 的状态变化。AFD 的 select 实现涉及复杂的同步机制:
-
请求收集 :应用调用
select时,AFD 收集所有关心的 socket 和事件(可读、可写、异常)。 -
立即检查:AFD 首先立即检查每个 socket 的状态,如果有就绪的 socket,立即返回。
-
等待注册:如果没有就绪的 socket,AFD 将请求挂起,将 IRP 放入每个 socket 的等待队列。
-
事件触发:当数据到达或连接建立时,TCP/IP 通过 TDI 事件通知 AFD。AFD 检查等待队列,如果有匹配的等待请求,完成对应的 IRP。
-
超时处理:如果指定了超时时间,AFD 使用内核定时器在超时后完成 IRP。
c
NTSTATUS AfdSelect(PAFD_FCB Fcb, PAFD_POLL_INFO PollInfo) {
// 1. 立即检查
if (CheckSocketReady(Fcb, PollInfo->Events)) {
PollInfo->ReadyEvents = GetReadyEvents(Fcb);
return STATUS_SUCCESS;
}
// 2. 注册等待
if (PollInfo->Timeout == 0) {
return STATUS_TIMEOUT; // 非阻塞模式
}
// 3. 挂起 IRP
InsertTailList(&Fcb->PollList, &PollInfo->ListEntry);
return STATUS_PENDING;
}
WSAEventSelect 与 WSAAsyncSelect
Windows 提供了两种异步通知机制:
-
WSAEventSelect :将 socket 事件映射到 Windows 事件对象。当指定事件发生时,AFD 设置对应的事件对象,应用通过
WaitForSingleObject等待。 -
WSAAsyncSelect:将 socket 事件映射到窗口消息。当指定事件发生时,AFD 向指定窗口投递消息。应用通过窗口过程处理消息。
这两种机制都依赖于 AFD 的事件通知系统。AFD 在端点结构中维护事件标志(EventFlags),当底层协议栈触发事件时,AFD 检查这些标志并触发相应的通知。
Winsock 分层架构的深层分析
Winsock 的分层架构是 Windows 网络编程的核心设计。这个架构包括四个主要层次:
-
应用层:使用 Winsock API 的网络应用程序。
-
ws2_32.dll:Winsock 2 的用户态 API 层。它不直接处理 socket 操作,而是通过 SPI(Service Provider Interface)将调用转发给服务提供者。
-
msafd.dll:Microsoft 的默认服务提供者。它将 Winsock 调用翻译为对 AFD 驱动的 IOCTL 调用。
-
afd.sys:内核态的 socket 实现。它维护 socket 状态,处理异步 I/O,通过 TDI 与协议栈通信。
这种分层设计的好处是:
- 可扩展性:可以插入第三方服务提供者(LSP)实现特殊功能
- 兼容性:应用层 API 保持稳定,底层实现可以变化
- 灵活性:可以为不同协议栈使用不同的服务提供者
socket 句柄的本质
在 Winsock 中,SOCKET 类型实际上是一个句柄值。在 ReactOS 的实现中,这个句柄指向 AFD 驱动创建的文件对象。应用通过 socket() 创建 socket 时,实际发生的是:
ws2_32.dll调用msafd.dll的WSPSocketWSPSocket调用NtCreateFile打开\Device\Afd- AFD 驱动创建
AFD_FCB结构,关联到文件对象 - 返回文件句柄作为
SOCKET值
后续的 bind、connect、send、recv 等调用都通过这个文件句柄进行,AFD 通过文件对象的 FsContext 找到对应的 FCB。
异步 I/O 的实现细节
Windows 支持多种异步 I/O 模式,AFD 需要支持所有这些模式:
-
阻塞模式 :默认模式,
send/recv调用阻塞直到操作完成。 -
非阻塞模式 :通过
ioctlsocket(FIONBIO)设置,send/recv立即返回,如果没有数据则返回WSAEWOULDBLOCK。 -
重叠 I/O :通过
WSA_FLAG_OVERLAPPED标志创建 socket,使用WSARecv/WSASend的重叠版本,通过事件或完成端口通知。 -
事件选择 :通过
WSAEventSelect将 socket 事件映射到事件对象。 -
异步选择 :通过
WSAAsyncSelect将 socket 事件映射到窗口消息。
AFD 通过检查文件对象的标志和 IRP 的参数来决定使用哪种模式。对于重叠 I/O,AFD 将 IRP 挂起,在操作完成时通过 IoCompleteRequest 通知 I/O 管理器。
与 Windows AFD 的对比
ReactOS 的 AFD 实现与 Windows 存在以下差异:
-
功能完整性:Windows 的 AFD 支持更多高级特性,如传输级别选项、条件接受、断开重用等。ReactOS 实现了核心功能,但部分高级特性尚未实现。
-
性能优化:Windows 的 AFD 包含大量性能优化,如零拷贝发送、接收缓冲合并等。ReactOS 的实现更注重功能正确性。
-
并发处理:Windows 的 AFD 使用更细粒度的锁机制,支持更高的并发连接数。ReactOS 使用全局锁,在高并发场景下可能成为瓶颈。
-
错误处理:Windows 的 AFD 对错误情况的处理更加完善,包括连接重置、超时、资源不足等。ReactOS 的错误处理相对简单。
AFD 的调试与诊断
ReactOS 的 AFD 包含调试支持,通过 AFD_DbgPrint 宏输出调试信息。调试级别包括:
MIN_TRACE:基本跟踪信息MID_TRACE:中等详细程度的跟踪MAX_TRACE:完整的跟踪信息DEBUG_ULTRA:超详细调试信息
调试信息可以通过 DebugTraceLevel 变量控制,便于定位网络通信问题。
本章代码索引
| 文件 | 内容 |
|---|---|
| afd/main.c(file:///d:/reactos/drivers/network/afd/afd/main.c) | DriverEntry |
| afd/bind.c(file:///d:/reactos/drivers/network/afd/afd/bind.c) | AfdBind |
| afd/connect.c(file:///d:/reactos/drivers/network/afd/afd/connect.c) | AfdConnect |
| afd/listen.c(file:///d:/reactos/drivers/network/afd/afd/listen.c) | AfdAccept |
| afd/read.c(file:///d:/reactos/drivers/network/afd/afd/read.c) | AfdReceive |
| afd/write.c(file:///d:/reactos/drivers/network/afd/afd/write.c) | AfdSend |
| afd/select.c(file:///d:/reactos/drivers/network/afd/afd/select.c) | AfdSelect |
| afd/event.c(file:///d:/reactos/drivers/network/afd/afd/event.c) | 异步事件 |
| afd.h(file:///d:/reactos/drivers/network/afd/afd/afd.h) | 数据结构 |
| ws2_32/(file:///d:/reactos/dll/win32/ws2_32/) | Winsock DLL |
| msafd/(file:///d:/reactos/dll/win32/msafd/) | Service Provider |
| tcpip/(file:///d:/reactos/drivers/network/tcpip/tcpip/) | TCP/IP 协议栈 |