tcpip.sys 传输层 (TCP) 详细分析
目录
1. 概述
TCP (Transmission Control Protocol,传输控制协议) 是 TCP/IP 协议栈中面向连接的可靠传输协议,提供有序、可靠、全双工的字节流服务。在 ReactOS tcpip.sys 中,TCP 层位于 TDI 接口与 IP 层之间。
1.1 架构特点
ReactOS 的 TCP 实现采用分层结构:
1.2 TCP 特性
| 面向连接 | 三次握手建立连接,四次挥手断开 |
| 可靠传输 | 确认 (ACK) + 超时重传 |
| 有序交付 | 序号机制保证字节流有序 |
| 流量控制 | 滑动窗口 + 窗口通告 |
| 拥塞控制 | 慢启动 + 拥塞避免 + 快速重传/恢复 |
| 全双工 | 双方可同时收发 |
| 字节流 | 无报文边界,面向字节流 |
2. TCP 层整体架构
2.1 三层结构
┌─────────────────────────────────────────────────────────┐
│ TDI 接口层 (上层: AFD.sys / TDI 客户端) │
│ TDI_CONNECT / TDI_LISTEN / TDI_ACCEPT │
│ TDI_SEND / TDI_RECEIVE / TDI_DISCONNECT │
└──────────────────────┬──────────────────────────────────┘
│
┌──────────────────────▼──────────────────────────────────┐
│ TCP 包装层 (ip/transport/tcp/) ←★ │
│ │
│ tcp.c : TCPSocket/TCPConnect/TCPSendData/TCPReceiveData
│ accept.c : TCPListen/TCPAccept/TCPAbortListenForSocket │
│ event.c : TCP*EventHandlers / Flush*Queue │
│ if.c : 接口更新 (TCPUpdateInterface*) │
│ │
│ 核心对象: CONNECTION_ENDPOINT + TDI_BUCKET 队列 │
└──────────────────────┬──────────────────────────────────┘
│ LibTCP* 调用
┌──────────────────────▼──────────────────────────────────┐
│ lwIP 粘合层 (ip/lwip_glue/tcp.c) │
│ LibTCPSocket/LibTCPConnect/LibTCPSend/LibTCPListen… │
│ 通过 tcpip_callback 排队到 tcpip 线程 │
└──────────────────────┬──────────────────────────────────┘
│ lwIP raw API
┌──────────────────────▼──────────────────────────────────┐
│ lwIP TCP 核心 (lwip/src/core/tcp.c/tcp_in.c/tcp_out.c) │
│ struct tcp_pcb (协议控制块) │
│ 状态机 / 重传 / 拥塞控制 / 滑动窗口 │
└──────────────────────┬──────────────────────────────────┘
│ LibIPInsertPacket / tcp_output
┌──────────────────────▼──────────────────────────────────┐
│ IP 网络层 │
└─────────────────────────────────────────────────────────┘
2.2 源码文件
| ip/transport/tcp/tcp.c | 核心:TCPSocket/TCPConnect/TCPSendData/TCPReceiveData/TCPDisconnect |
| ip/transport/tcp/accept.c | 监听/接受:TCPListen/TCPAccept/TCPCheckPeerForAccept |
| ip/transport/tcp/event.c | 事件处理:TCPEventHandlers、FlushQueue |
| ip/transport/tcp/if.c | 接口绑定:TCPUpdateInterfaceIPInformation/LinkStatus |
| ip/lwip_glue/tcp.c | lwIP 桥接:LibTCP* 系列函数 |
| include/tcpcore.h | 保留的 Linux 2.4.20 移植结构 (sk_buff/tcp_opt) |
| include/tcp.h | TCP 头、CONNECTION_ENDPOINT 声明 |
2.3 历史:Linux 移植 vs lwIP
注意: ReactOS 早期将 Linux 内核 2.4.20 的 TCP 实现移植到 include/tcpcore.h
(含 struct sk_buff / struct tcp_opt / struct sock 完整结构)。
当前实际使用的 TCP 协议实现是 lwIP 2.x (通过 LibTCP* 粘合层),
tcpcore.h 仍保留在头文件树中但不再是活动实现。
3. TCP 报文格式
定义在 [tcp.h](file:///d:/reactos/drivers/network/tcpip/include/tcp.h#L15-L25):
typedef struct TCPv4_HEADER {
USHORT SourcePort; // 源端口 (2B)
USHORT DestinationPort; // 目的端口 (2B)
ULONG SequenceNumber; // 序号 (4B)
ULONG AckNumber; // 确认号 (4B)
UCHAR DataOffset; // 数据偏移 (高 4 位, 单位 32 位字)
UCHAR Flags; // 标志位 (低 6 位)
USHORT Window; // 接收窗口 (2B)
USHORT Checksum; // 校验和 (2B)
USHORT Urgent; // 紧急指针 (2B)
} TCPv4_HEADER, *PTCPv4_HEADER;
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |C|E|U|A|P|R|S|F| |
| Offset| Rsvd |W|C|R|C|S|S|Y|I| Window |
| | |R|E|G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3.1 标志位
/* tcpdef.h 中的 TCP 标志 */
#define TCP_FIN 0x01 // 结束连接
#define TCP_SYN 0x02 // 同步序号 (连接建立)
#define TCP_RST 0x04 // 重置连接
#define TCP_PSH 0x08 // 推送数据
#define TCP_ACK 0x10 // 确认
#define TCP_URG 0x20 // 紧急
3.2 伪头 (TCPv4_PSEUDO_HEADER)
定义在 [tcp.h](file:///d:/reactos/drivers/network/tcpip/include/tcp.h#L38-L44):
typedef struct TCPv4_PSEUDO_HEADER {
ULONG SourceAddress; // 源 IP
ULONG DestinationAddress; // 目的 IP
UCHAR Zero; // 保留
UCHAR Protocol; // 6 (TCP)
USHORT TCPLength; // TCP 段长度
} TCPv4_PSEUDO_HEADER, *PTCPv4_PSEUDO_HEADER;
3.3 TCP 选项
#define TCPOPT_END_OF_LIST 0x0 // 选项结束
#define TCPOPT_NO_OPERATION 0x1 // 无操作
#define TCPOPT_MAX_SEG_SIZE 0x2 // 最大段大小 (MSS)
#define TCPOPTLEN_MAX_SEG_SIZE 0x4
4. TCP 状态机
TCP 共有 11 种状态(lwIP tcp_state_str):
+———+
| CLOSED |
+—-+—-+
|
主动打开/被动打开
|
+—-v—-+
| LISTEN |
+—-+—-+
| 收到 SYN
+—-v—-+
| SYN_RCVD |
+—-+—-+
| 发送 SYN+ACK
|
主动打开 | 同时打开
+—-v—-+ +—-v—-+
| SYN_SENT+——–> SYN_RCVD |
+—-+—-+ +—-+—-+
| |
| 收到 SYN+ACK | 收到 ACK
+——–+——–+
|
+——v——+
| ESTABLISHED |
+——+——+
|
+————+————+
| 主动关闭 | 被动关闭 |
▼ ▼
+———+ +———–+
|FIN_WAIT_1| | CLOSE_WAIT|
+—-+—-+ +—–+—–+
| | 关闭
+—-v—-+ +—-v—-+
|FIN_WAIT_2| | LAST_ACK|
+—-+—-+ +—-+—-+
| |
+—-v—-+ |
|TIME_WAIT| |
+—-+—-+ |
| |
+—-v—-+ |
| CLOSED |<——–+
+———+
4.1 关键状态
| LISTEN | 监听,等待 SYN |
| SYN_SENT | 已发送 SYN,等待 SYN+ACK |
| SYN_RCVD | 已收到 SYN,已发送 SYN+ACK |
| ESTABLISHED | 连接建立,数据传输 |
| FIN_WAIT_1/2 | 主动关闭等待 |
| CLOSE_WAIT | 被动关闭等待应用关闭 |
| TIME_WAIT | 2MSL 等待 (60 秒) |
5. 连接端点结构 (CONNECTION_ENDPOINT)
CONNECTION_ENDPOINT 是 TCP 层的核心对象,定义在 [titypes.h](file:///d:/reactos/drivers/network/tcpip/include/titypes.h)。
5.1 结构概览
CONNECTION_ENDPOINT
│
├── 对象管理
│ ├── LONG RefCount // 引用计数
│ ├── OBJECT_FREE_ROUTINE Free // 释放函数 (ConnectionFree)
│ └── ERESOURCE Resource // 对象锁
│
├── 地址绑定
│ ├── PADDRESS_FILE AddressFile // 关联的地址文件
│ ├── PVOID SocketContext // lwIP tcp_pcb 指针
│ └── PCONNECTION_ENDPOINT Next // 地址文件的连接链表
│
├── 请求队列 (TDI_BUCKET 链表)
│ ├── LIST_ENTRY ConnectRequest // 连接请求
│ ├── LIST_ENTRY ListenRequest // 监听请求
│ ├── LIST_ENTRY AcceptRequest // 接受请求
│ ├── LIST_ENTRY ReceiveRequest // 接收请求
│ ├── LIST_ENTRY SendRequest // 发送请求
│ └── LIST_ENTRY ShutdownRequest // 断开请求
│
├── 数据队列
│ ├── LIST_ENTRY PacketQueue // 收到的 pbuf 队列 (lwIP)
│ ├── PLIST_ENTRY SendDataQueue // 待发送数据
│ └── PLIST_ENTRY FastSendDataQueue
│
└── 状态
├── KEVENT DisconnectEvent
├── KTIMER DisconnectTimer
└── KSPIN_LOCK DisconnectLock
5.2 TDI_BUCKET — 请求桶
TDI_BUCKET 封装了一个挂起的 TDI 请求:
typedef struct _TDI_BUCKET {
LIST_ENTRY Entry; // 队列链接
TDI_REQUEST Request; // TDI 请求 (句柄+完成回调+上下文)
PCONNECTION_ENDPOINT AssociatedEndpoint; // 关联的连接端点
NTSTATUS Status; // 完成状态
ULONG_PTR Information; // 传输的字节数/信息
} TDI_BUCKET, *PTDI_BUCKET;
使用 TdiBucketLookasideList 后备列表分配:
ExInitializeNPagedLookasideList(&TdiBucketLookasideList,
NULL, NULL, 0,
sizeof(TDI_BUCKET), TDI_BUCKET_TAG, 0);
5.3 收发窗口 (AFD 中定义)
AFD 层维护 FCB->Send/Recv 窗口,TCP 层通过 TDI 接口与之交互。
6. TDI_BUCKET 与 IRP 队列模型
6.1 请求挂起模型
用户态 IRP (TDI_SEND)
│
▼
TCP 层:
├─ 分配 TDI_BUCKET
├─ 保存完成回调 (Complete) 和上下文 (Context)
├─ InsertTailList(&Connection->SendRequest, &Bucket->Entry)
└─ 返回 STATUS_PENDING
│
▼ (lwIP 事件触发时)
事件处理器:
├─ RemoveHeadList(&Connection->SendRequest)
├─ 执行操作 (LibTCPSend)
├─ Bucket->Status = 结果
├─ Bucket->Information = 字节数
└─ CompleteBucket → BucketCompletionWorker
└─ 调用 TDI 完成回调 → 完成用户 IRP
6.2 CompleteBucket — 完成请求
在 [event.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/event.c#L37-L50):
CompleteBucket(Connection, Bucket, Synchronous)
├─ ReferenceObject(Connection)
├─ Bucket->AssociatedEndpoint = Connection
├─ Synchronous → BucketCompletionWorker 直接执行
└─ 异步 → ChewCreate(BucketCompletionWorker, Bucket) 排队
6.3 BucketCompletionWorker — 完成工作项
在 [event.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/event.c#L21-L35):
BucketCompletionWorker(Context)
├─ Bucket = Context
├─ Complete = Bucket->Request.RequestNotifyObject
├─ Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information)
│ └─ 通常为 DispDataRequestComplete → IoCompleteRequest
├─ DereferenceObject(Bucket->AssociatedEndpoint)
└─ ExFreeToNPagedLookasideList(&TdiBucketLookasideList, Bucket)
6.4 Flush*Queue 系列
| FlushReceiveQueue | 以状态完成所有挂起接收 |
| FlushSendQueue | 完成所有挂起发送 |
| FlushShutdownQueue | 完成所有挂起断开 |
| FlushConnectQueue | 完成所有挂起连接 |
| FlushListenQueue | 完成所有挂起监听 |
| FlushAllQueues | 全部完成 (连接终止时) |
7. 连接管理
7.1 TCPSocket — 创建 socket
在 [tcp.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/tcp.c#L153):
TCPSocket(Connection, Family, Type, Proto)
│
├─ LockObject(Connection)
├─ 调用 LibTCPSocket(Connection) → 创建 lwIP tcp_pcb
├─ 设置回调:
│ tcp_arg(pcb, Connection)
│ tcp_err(pcb, InternalErrorEventHandler)
│ (连接建立后设置 tcp_recv/tcp_sent/tcp_accept)
├─ Connection->SocketContext = pcb
└─ 返回
7.2 TCPConnect — 发起连接
在 [tcp.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/tcp.c#L301-L424):
TCPConnect(Connection, ConnInfo, ReturnInfo, Complete, Context)
│
├─ LockObject(Connection)
├─ 解析远端地址 (TA_IP_ADDRESS → ip_addr_t)
│
├─ 分配本地端口:
│ LocalAddress = 地址文件地址
│ 端口未指定 → TCPAllocatePort(动态)
│
├─ 创建 TDI_BUCKET 挂入 ConnectRequest
│
├─ LibTCPConnect(Connection, &ipaddr, port)
│ └─ lwIP: tcp_connect(pcb, ipaddr, port, InternalConnectEventHandler)
│
├─ 返回 STATUS_PENDING
│
└─ 连接完成 → TCPConnectEventHandler
7.3 LibTCPConnect — lwIP 桥接
在 [tcp.c 粘合层](file:///d:/reactos/drivers/network/tcpip/ip/lwip_glue/tcp.c#L621-L635):
LibTCPConnect(Connection, ipaddr, port)
│
├─ 分配 lwip_callback_msg
├─ 填充 Input.Connect { Connection, IpAddress, Port }
├─ tcpip_callback_with_block(LibTCPConnectCallback, msg, 1)
│ └─ 在 tcpip 线程中执行:
│ tcp_arg(pcb, Connection)
│ tcp_recv(pcb, InternalRecvEventHandler)
│ tcp_sent(pcb, InternalSendEventHandler)
│ tcp_connect(pcb, ipaddr, port, InternalConnectEventHandler)
│ msg->Output.Connect.Error = …
├─ KeWaitForSingleObject(&msg->Event) // 等待 tcpip 线程完成
└─ 返回错误码
7.4 TCPConnectEventHandler — 连接完成
在 [event.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/event.c#L419-L441):
TCPConnectEventHandler(arg, err)
├─ Connection = arg
├─ 遍历 ConnectRequest 队列:
│ Bucket->Status = TCPTranslateError(err)
│ CompleteBucket(Connection, Bucket, FALSE)
└─ 完成所有挂起的连接请求
8. 监听与接受
8.1 TCPListen — 监听
在 [accept.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/accept.c#L47-L105):
TCPListen(Connection, Backlog)
│
├─ 解析本地绑定地址:
│ AddressToBind = AddressFile->Address
│ Port = AddressFile->Port
│
├─ LibTCPBind(Connection, &AddressToBind, Port)
│ └─ tcp_bind(pcb, ipaddr, port)
│
├─ 端口未指定 (0):
│ ├─ TCPGetSockAddress 获取实际端口
│ ├─ TCPAllocatePort 分配端口
│ └─ AddressFile->Port = AllocatedPort
│
├─ Connection->SocketContext = LibTCPListen(Connection, Backlog)
│ └─ tcp_listen(pcb) + tcp_accept(pcb, InternalAcceptEventHandler)
│
└─ 返回
8.2 TCPAccept — 接受连接
在 [accept.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/accept.c#L139):
TCPAccept(Request, Listener, Connection, Complete, Context)
│
├─ 分配 TDI_BUCKET
├─ Bucket->AssociatedEndpoint = Connection (接受新连接的 socket)
├─ 挂入 Listener->ListenRequest
│
└─ 返回 STATUS_PENDING
└─ 新连接到达 → TCPAcceptEventHandler
8.3 TCPAcceptEventHandler — 接受完成
在 [event.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/event.c#L230-L291):
TCPAcceptEventHandler(arg, newpcb)
│
├─ Connection = arg (Listener)
├─ 遍历 ListenRequest 队列:
│ ├─ TCPCheckPeerForAccept(newpcb, Request):
│ │ └─ LibTCPGetPeerName → 填充远端地址
│ │
│ ├─ 成功:
│ │ ├─ 释放原 socket 上下文 (LibTCPClose 旧的 pcb)
│ │ ├─ Bucket->AssociatedEndpoint->SocketContext = newpcb
│ │ └─ LibTCPAccept(newpcb, listen_pcb, AssociatedEndpoint)
│ │ └─ tcp_recv/tcp_sent/tcp_err/tcp_poll 设置
│ │ └─ 通知 AFD 完成 accept
│ │
│ └─ CompleteBucket(Connection, Bucket, FALSE)
│ └─ 完成用户 IRP
└─ 只接受一个连接 (break)
8.4 TCPAbortListenForSocket — 中止监听
在 [accept.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/accept.c#L107-L137):
TCPAbortListenForSocket(Listener, Connection)
├─ 遍历 Listener->ListenRequest
├─ 找到关联 Connection 的 Bucket:
│ ├─ 移除 + 释放
│ └─ 返回 TRUE
└─ 返回 FALSE
9. 数据发送路径
9.1 TCPSendData — 发送入口
在 [tcp.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/tcp.c#L579-L630):
TCPSendData(Connection, Buffer, DataSize, DataUsed, Flags, Complete, Context)
│
├─ 分配 TDI_BUCKET
├─ Bucket->Request.RequestNotifyObject = Complete
├─ Bucket->Request.RequestContext = Context
│
├─ 挂入 Connection->SendRequest
│
├─ 尝试立即发送:
│ LibTCPSend(Connection, Buffer, DataSize, &sent, TRUE)
│ ├─ 成功 → 完成 Bucket (返回已发送字节数)
│ └─ 失败 (STATUS_PENDING) → 保持挂起
│
└─ 返回 STATUS_PENDING / 立即完成
9.2 LibTCPSend — lwIP 发送
在 [tcp.c 粘合层](file:///d:/reactos/drivers/network/tcpip/ip/lwip_glue/tcp.c#L556-L590):
LibTCPSend(Connection, dataptr, len, sent, safe)
│
├─ 分配 lwip_callback_msg
├─ tcpip_callback_with_block(LibTCPSendCallback, msg, 1)
│ └─ tcpip 线程中:
│ Error = tcp_write(pcb, dataptr, len, TCP_WRITE_FLAG_COPY)
│ 成功 → tcp_output(pcb)
│ msg->Output.Send.Error = Error
│ msg->Output.Send.Information = len
├─ 等待事件
├─ *sent = Information
└─ 返回错误码
9.3 TCPSendEventHandler — 发送事件
在 [event.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/event.c#L293-L377),由 lwIP tcp_sent 回调触发(发送窗口有空间时):
TCPSendEventHandler(arg, space)
│
├─ Connection = arg
├─ 遍历 SendRequest 队列:
│ ├─ NdisQueryBuffer(Irp->MdlAddress) → 用户发送缓冲
│ ├─ LibTCPSend(Connection, SendBuffer, SendLen, &BytesSent, TRUE)
│ ├─ STATUS_PENDING → 放回队列头部, 停止
│ ├─ 成功 → Bucket->Information = BytesSent
│ └─ CompleteBucket (完成用户 IRP)
│
├─ 全部完成后:
│ ├─ FlushShutdownQueue(STATUS_SUCCESS) // 完成待处理的断开
│ └─ KeCancelTimer(DisconnectTimer)
│
└─ DereferenceObject
10. 数据接收路径
10.1 TCPReceive — IP 层入口
在 [tcp.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/tcp.c#L192-L206),作为 IPRegisterProtocol(IPPROTO_TCP, TCPReceive) 注册:
TCPReceive(Interface, IPPacket)
│
└─ LibIPInsertPacket(Interface->TCPContext, IPPacket->Header, TotalSize)
└─ 将 IP 数据包送入 lwIP 的 netif 输入 (tcpip 线程)
10.2 LibIPInsertPacket — 注入 lwIP
在 [ip.c 粘合层](file:///d:/reactos/drivers/network/tcpip/ip/lwip_glue/ip.c):
LibIPInsertPacket(ifarg, data, size)
│
├─ 创建 pbuf (PBUF_RAW, 引用数据)
├─ 排队到 tcpip 线程输入队列
│ └─ tcpip_thread 处理 → netif->input → tcp_input
│ └─ lwIP 处理 TCP 段 (校验/序号/状态机)
│ └─ 数据到达 → 调用 InternalRecvEventHandler
└─ 完成
10.3 InternalRecvEventHandler → TCPRecvEventHandler
lwIP 数据到达时调用注册的 tcp_recv 回调(粘合层中):
InternalRecvEventHandler(arg, pcb, p, err)
│
├─ Connection = arg
├─ 将 pbuf 挂入 Connection->PacketQueue:
│ LibTCPEnqueuePacket(Connection, p)
│ tcp_recved(pcb, p->tot_len) // 通知 lwIP 数据已取走
│
└─ 调用外部处理器:
TCPRecvEventHandler(Connection) // event.c
10.4 TCPRecvEventHandler — 接收事件
在 [event.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/event.c#L379-L417):
TCPRecvEventHandler(arg)
│
├─ Connection = arg
├─ 遍历 ReceiveRequest 队列:
│ ├─ NdisQueryBuffer(Irp->MdlAddress) → 用户接收缓冲
│ ├─ LibTCPGetDataFromConnectionQueue(Connection, RecvBuffer,
│ │ RecvLen, &Received)
│ │ └─ 从 PacketQueue 解包 pbuf, 复制数据到用户缓冲
│ ├─ STATUS_PENDING → 放回队列头部, 停止 (无数据)
│ ├─ 成功 → Bucket->Information = Received
│ └─ CompleteBucket (完成用户 IRP)
│
└─ 完成
10.5 TCPReceiveData — TDI 接收入口
在 [tcp.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/tcp.c#L528-L577):
TCPReceiveData(Connection, Buffer, ReceiveLength, BytesReceived,
ReceiveFlags, Complete, Context)
│
├─ 分配 TDI_BUCKET 挂入 ReceiveRequest
│
├─ 尝试立即取数据:
│ LibTCPGetDataFromConnectionQueue → 有数据则完成
│ STATUS_PENDING → 保持挂起等待 TCPRecvEventHandler
│
└─ 返回
11. 事件处理器
11.1 事件处理器总览
lwIP 通过回调驱动 TCP 层,粘合层将回调转发给 event.c 的处理器:
lwIP 回调 粘合层 事件处理器 (event.c)
───────── ────── ─────────────────
tcp_connect 完成 → InternalConnectEventHandler → TCPConnectEventHandler
tcp_accept 新连接 → InternalAcceptEventHandler → TCPAcceptEventHandler
tcp_recv 数据到达 → InternalRecvEventHandler → TCPRecvEventHandler
tcp_sent 可发送 → InternalSendEventHandler → TCPSendEventHandler
tcp_err 错误/关闭 → InternalErrorEventHandler → TCPFinEventHandler
tcp_poll 周期轮询 → InternalPollEventHandler → (keepalive/超时)
11.2 TCPFinEventHandler — 连接终止
在 [event.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/event.c#L181-L228):
TCPFinEventHandler(arg, err)
│
├─ Status = TCPTranslateError(err)
├─ FlushAllQueues(Connection, Status) // 完成所有挂起请求
│
├─ 从地址文件连接链表移除:
│ ├─ 是首连接 → AddressFile->Connection = Next
│ ├─ 是监听器 → AddressFile->Listener = NULL
│ └─ 遍历查找 → 从链中移除
│
├─ DereferenceObject(AddressFile)
├─ Connection->AddressFile = NULL
└─ 完成
11.3 TCPTranslateError — 错误码转换
在 [tcp.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/tcp.c#L267-L299),将 lwIP err_t 转换为 NTSTATUS:
err_t → NTSTATUS
ERR_OK (0) → STATUS_SUCCESS
ERR_MEM (-1) → STATUS_INSUFFICIENT_RESOURCES
ERR_BUF (-2) → STATUS_BUFFER_TOO_SMALL
ERR_TIMEOUT(-3)→ STATUS_TIMEOUT
ERR_RTE (-4) → STATUS_NETWORK_UNREACHABLE
ERR_INPROGRESS→ STATUS_PENDING
ERR_VAL (-6) → STATUS_INVALID_PARAMETER
ERR_WOULDBLOCK→ STATUS_CANT_WAIT
ERR_USE (-8) → STATUS_ADDRESS_ALREADY_EXISTS
ERR_ABRT (-10) → STATUS_LOCAL_DISCONNECT
ERR_RST (-11) → STATUS_REMOTE_DISCONNECT
ERR_CLSD (-12) → STATUS_FILE_CLOSED
ERR_CONN (-13) → STATUS_INVALID_CONNECTION
ERR_IF (-15) → STATUS_UNEXPECTED_NETWORK_ERROR
12. lwIP 粘合层与 tcpip 线程模型
12.1 线程模型
lwIP 要求所有 raw API 调用在 tcpip 线程 中执行:
LibTCPXxx (调用线程)
│
│ 1. 分配 lwip_callback_msg { Event, Input, Output }
│ 2. 填充 Input 参数
│ 3. tcpip_callback_with_block(LibTCPXxxCallback, msg, 1)
│ │
│ ▼ (排队到 tcpip 线程)
│ tcpip 线程: LibTCPXxxCallback(msg)
│ ├─ 调用 lwIP raw API (tcp_connect/tcp_write/…)
│ ├─ 填充 msg->Output
│ └─ KeSetEvent(&msg->Event)
│
│ 4. KeWaitForSingleObject(&msg->Event) // 等待完成
│ 5. 读取 Output
│
└─ 返回结果
12.2 lwip_callback_msg
定义在 [lwip_glue.h](file:///d:/reactos/drivers/network/tcpip/ip/lwip_glue/lwip_glue.h#L24-L92):
struct lwip_callback_msg
{
KEVENT Event; // 同步事件
union { // 输入参数
struct { PVOID Arg; } Socket;
struct { struct tcp_pcb* pcb; } FreeSocket;
struct { PCONNECTION_ENDPOINT Connection; ip_addr_t *IpAddress; u16_t Port; } Bind;
struct { PCONNECTION_ENDPOINT Connection; u8_t Backlog; } Listen;
struct { PCONNECTION_ENDPOINT Connection; void *Data; u16_t DataLength; } Send;
struct { PCONNECTION_ENDPOINT Connection; ip_addr_t *IpAddress; u16_t Port; } Connect;
struct { PCONNECTION_ENDPOINT Connection; int shut_rx; int shut_tx; } Shutdown;
struct { PCONNECTION_ENDPOINT Connection; int Callback; } Close;
} Input;
union { // 输出结果
struct { struct tcp_pcb *NewPcb; } Socket;
struct { err_t Error; } Bind;
struct { struct tcp_pcb *NewPcb; } Listen;
struct { err_t Error; u32_t Information; } Send;
struct { err_t Error; } Connect;
struct { err_t Error; } Shutdown;
struct { err_t Error; } Close;
} Output;
};
12.3 LibTCP* 函数清单
| LibTCPSocket | tcp_new | 创建 PCB |
| LibTCPFreeSocket | tcp_close | 关闭 PCB |
| LibTCPBind | tcp_bind | 绑定本地地址端口 |
| LibTCPListen | tcp_listen + tcp_accept | 进入监听 |
| LibTCPSend | tcp_write + tcp_output | 发送数据 |
| LibTCPConnect | tcp_connect | 发起连接 |
| LibTCPShutdown | tcp_shutdown | 关闭读写 |
| LibTCPClose | tcp_close | 关闭 |
| LibTCPGetPeerName | 读 PCB 字段 | 获取远端地址 |
| LibTCPGetHostName | 读 PCB 字段 | 获取本地地址 |
| LibTCPAccept | 设置回调 | 设置新 PCB 回调 |
| LibTCPSetNoDelay | tcp_nagle_disable | 禁用 Nagle |
| LibTCPGetSocketStatus | 读 state | 获取状态 |
| LibTCPEnqueuePacket | pbuf 管理 | 入队接收数据 |
| LibTCPGetDataFromConnectionQueue | pbuf 读取 | 出队复制数据 |
| LibIPInsertPacket | netif input | 注入 IP 包 |
13. 断开与清理
13.1 TCPDisconnect — TDI 断开
在 [tcp.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/tcp.c#L426-L526):
TCPDisconnect(Connection, Flags, Timeout, ConnInfo, ReturnInfo, Complete, Context)
│
├─ 解析 Flags:
│ TDI_DISCONNECT_ABORT:
│ │ └─ LibTCPShutdown(Connection, 1, 1) // 立即中止 (RST)
│ │
│ TDI_DISCONNECT_RELEASE:
│ │ └─ LibTCPShutdown(Connection, 0, 1) // 只关发送 (FIN)
│ │
│ 其他 (正常):
│ └─ LibTCPShutdown(Connection, 0, 1)
│ └─ 挂起 ShutdownRequest 直到发送完成
│
├─ 设置 DisconnectTimer (超时强制完成)
│
└─ 完成或挂起
13.2 TCPClose — 关闭
在 [tcp.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/tcp.c#L177-L190):
TCPClose(Connection)
└─ LibTCPClose(Connection, FALSE, TRUE)
└─ tcp_close(pcb) → lwIP 发送 FIN/释放
13.3 连接资源释放 (ConnectionFree)
ConnectionFree(Object)
├─ Connection = Object
├─ 清理 PacketQueue (释放 pbuf)
├─ LibTCPFreeSocket(SocketContext) // 关闭 lwIP PCB
└─ ExFreePool(Connection)
14. 工作流程图
14.1 TCP 连接建立 (三次握手)
远端
lwIP tcpip线程
TCP层(tcpip.sys)
应用程序
远端
lwIP tcpip线程
TCP层(tcpip.sys)
应用程序
#mermaid-svg-rexOxnyITE46znnG{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-rexOxnyITE46znnG .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-rexOxnyITE46znnG .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-rexOxnyITE46znnG .error-icon{fill:#552222;}#mermaid-svg-rexOxnyITE46znnG .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-rexOxnyITE46znnG .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-rexOxnyITE46znnG .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-rexOxnyITE46znnG .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-rexOxnyITE46znnG .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-rexOxnyITE46znnG .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-rexOxnyITE46znnG .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-rexOxnyITE46znnG .marker{fill:#333333;stroke:#333333;}#mermaid-svg-rexOxnyITE46znnG .marker.cross{stroke:#333333;}#mermaid-svg-rexOxnyITE46znnG svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-rexOxnyITE46znnG p{margin:0;}#mermaid-svg-rexOxnyITE46znnG .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-rexOxnyITE46znnG text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-rexOxnyITE46znnG .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-rexOxnyITE46znnG .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-rexOxnyITE46znnG .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-rexOxnyITE46znnG .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-rexOxnyITE46znnG #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-rexOxnyITE46znnG .sequenceNumber{fill:white;}#mermaid-svg-rexOxnyITE46znnG #sequencenumber{fill:#333;}#mermaid-svg-rexOxnyITE46znnG #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-rexOxnyITE46znnG .messageText{fill:#333;stroke:none;}#mermaid-svg-rexOxnyITE46znnG .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-rexOxnyITE46znnG .labelText,#mermaid-svg-rexOxnyITE46znnG .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-rexOxnyITE46znnG .loopText,#mermaid-svg-rexOxnyITE46znnG .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-rexOxnyITE46znnG .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-rexOxnyITE46znnG .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-rexOxnyITE46znnG .noteText,#mermaid-svg-rexOxnyITE46znnG .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-rexOxnyITE46znnG .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-rexOxnyITE46znnG .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-rexOxnyITE46znnG .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-rexOxnyITE46znnG .actorPopupMenu{position:absolute;}#mermaid-svg-rexOxnyITE46znnG .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-rexOxnyITE46znnG .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-rexOxnyITE46znnG .actor-man circle,#mermaid-svg-rexOxnyITE46znnG line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-rexOxnyITE46znnG :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
第一次握手
connect() (TDI_CONNECT)
分配本地端口 + 创建 TDI_BUCKET
LibTCPConnect (排队到 tcpip 线程)
发送 SYN (tcp_connect)
收到 SYN+ACK
发送 ACK (第二次/第三次握手)
InternalConnectEventHandler (err=ERR_OK)
TCPConnectEventHandler 完成所有连接请求
连接成功 (IoCompleteRequest)
14.2 TCP 数据发送流程
#mermaid-svg-8ganwPQbVs6NqoPE{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-8ganwPQbVs6NqoPE .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-8ganwPQbVs6NqoPE .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-8ganwPQbVs6NqoPE .error-icon{fill:#552222;}#mermaid-svg-8ganwPQbVs6NqoPE .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-8ganwPQbVs6NqoPE .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-8ganwPQbVs6NqoPE .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-8ganwPQbVs6NqoPE .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-8ganwPQbVs6NqoPE .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-8ganwPQbVs6NqoPE .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-8ganwPQbVs6NqoPE .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-8ganwPQbVs6NqoPE .marker{fill:#333333;stroke:#333333;}#mermaid-svg-8ganwPQbVs6NqoPE .marker.cross{stroke:#333333;}#mermaid-svg-8ganwPQbVs6NqoPE svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-8ganwPQbVs6NqoPE p{margin:0;}#mermaid-svg-8ganwPQbVs6NqoPE .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-8ganwPQbVs6NqoPE .cluster-label text{fill:#333;}#mermaid-svg-8ganwPQbVs6NqoPE .cluster-label span{color:#333;}#mermaid-svg-8ganwPQbVs6NqoPE .cluster-label span p{background-color:transparent;}#mermaid-svg-8ganwPQbVs6NqoPE .label text,#mermaid-svg-8ganwPQbVs6NqoPE span{fill:#333;color:#333;}#mermaid-svg-8ganwPQbVs6NqoPE .node rect,#mermaid-svg-8ganwPQbVs6NqoPE .node circle,#mermaid-svg-8ganwPQbVs6NqoPE .node ellipse,#mermaid-svg-8ganwPQbVs6NqoPE .node polygon,#mermaid-svg-8ganwPQbVs6NqoPE .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-8ganwPQbVs6NqoPE .rough-node .label text,#mermaid-svg-8ganwPQbVs6NqoPE .node .label text,#mermaid-svg-8ganwPQbVs6NqoPE .image-shape .label,#mermaid-svg-8ganwPQbVs6NqoPE .icon-shape .label{text-anchor:middle;}#mermaid-svg-8ganwPQbVs6NqoPE .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-8ganwPQbVs6NqoPE .rough-node .label,#mermaid-svg-8ganwPQbVs6NqoPE .node .label,#mermaid-svg-8ganwPQbVs6NqoPE .image-shape .label,#mermaid-svg-8ganwPQbVs6NqoPE .icon-shape .label{text-align:center;}#mermaid-svg-8ganwPQbVs6NqoPE .node.clickable{cursor:pointer;}#mermaid-svg-8ganwPQbVs6NqoPE .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-8ganwPQbVs6NqoPE .arrowheadPath{fill:#333333;}#mermaid-svg-8ganwPQbVs6NqoPE .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-8ganwPQbVs6NqoPE .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-8ganwPQbVs6NqoPE .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8ganwPQbVs6NqoPE .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-8ganwPQbVs6NqoPE .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8ganwPQbVs6NqoPE .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-8ganwPQbVs6NqoPE .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-8ganwPQbVs6NqoPE .cluster text{fill:#333;}#mermaid-svg-8ganwPQbVs6NqoPE .cluster span{color:#333;}#mermaid-svg-8ganwPQbVs6NqoPE div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-8ganwPQbVs6NqoPE .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-8ganwPQbVs6NqoPE rect.text{fill:none;stroke-width:0;}#mermaid-svg-8ganwPQbVs6NqoPE .icon-shape,#mermaid-svg-8ganwPQbVs6NqoPE .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8ganwPQbVs6NqoPE .icon-shape p,#mermaid-svg-8ganwPQbVs6NqoPE .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-8ganwPQbVs6NqoPE .icon-shape .label rect,#mermaid-svg-8ganwPQbVs6NqoPE .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8ganwPQbVs6NqoPE .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-8ganwPQbVs6NqoPE .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-8ganwPQbVs6NqoPE :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
是
否
应用 send
TDI_SEND → TCPSendData
分配 TDI_BUCKET
挂入 SendRequest 队列
LibTCPSend
排队 tcpip_callback
tcpip 线程: tcp_write + tcp_output
发送窗口有空间?
构造 TCP 段 → IP 层发送
等待 tcp_sent 事件
tcp_sent 回调 → InternalSendEventHandler
TCPSendEventHandler
从 SendRequest 取 Bucket
LibTCPSend 发送下一批
CompleteBucket 完成用户 IRP
应用 send 返回
14.3 TCP 数据接收流程
#mermaid-svg-ptEeDvx6XZn7ApUY{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ptEeDvx6XZn7ApUY .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ptEeDvx6XZn7ApUY .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ptEeDvx6XZn7ApUY .error-icon{fill:#552222;}#mermaid-svg-ptEeDvx6XZn7ApUY .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ptEeDvx6XZn7ApUY .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ptEeDvx6XZn7ApUY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ptEeDvx6XZn7ApUY .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ptEeDvx6XZn7ApUY .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ptEeDvx6XZn7ApUY .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ptEeDvx6XZn7ApUY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ptEeDvx6XZn7ApUY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ptEeDvx6XZn7ApUY .marker.cross{stroke:#333333;}#mermaid-svg-ptEeDvx6XZn7ApUY svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ptEeDvx6XZn7ApUY p{margin:0;}#mermaid-svg-ptEeDvx6XZn7ApUY .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-ptEeDvx6XZn7ApUY .cluster-label text{fill:#333;}#mermaid-svg-ptEeDvx6XZn7ApUY .cluster-label span{color:#333;}#mermaid-svg-ptEeDvx6XZn7ApUY .cluster-label span p{background-color:transparent;}#mermaid-svg-ptEeDvx6XZn7ApUY .label text,#mermaid-svg-ptEeDvx6XZn7ApUY span{fill:#333;color:#333;}#mermaid-svg-ptEeDvx6XZn7ApUY .node rect,#mermaid-svg-ptEeDvx6XZn7ApUY .node circle,#mermaid-svg-ptEeDvx6XZn7ApUY .node ellipse,#mermaid-svg-ptEeDvx6XZn7ApUY .node polygon,#mermaid-svg-ptEeDvx6XZn7ApUY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ptEeDvx6XZn7ApUY .rough-node .label text,#mermaid-svg-ptEeDvx6XZn7ApUY .node .label text,#mermaid-svg-ptEeDvx6XZn7ApUY .image-shape .label,#mermaid-svg-ptEeDvx6XZn7ApUY .icon-shape .label{text-anchor:middle;}#mermaid-svg-ptEeDvx6XZn7ApUY .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ptEeDvx6XZn7ApUY .rough-node .label,#mermaid-svg-ptEeDvx6XZn7ApUY .node .label,#mermaid-svg-ptEeDvx6XZn7ApUY .image-shape .label,#mermaid-svg-ptEeDvx6XZn7ApUY .icon-shape .label{text-align:center;}#mermaid-svg-ptEeDvx6XZn7ApUY .node.clickable{cursor:pointer;}#mermaid-svg-ptEeDvx6XZn7ApUY .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ptEeDvx6XZn7ApUY .arrowheadPath{fill:#333333;}#mermaid-svg-ptEeDvx6XZn7ApUY .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ptEeDvx6XZn7ApUY .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ptEeDvx6XZn7ApUY .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ptEeDvx6XZn7ApUY .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ptEeDvx6XZn7ApUY .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ptEeDvx6XZn7ApUY .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ptEeDvx6XZn7ApUY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ptEeDvx6XZn7ApUY .cluster text{fill:#333;}#mermaid-svg-ptEeDvx6XZn7ApUY .cluster span{color:#333;}#mermaid-svg-ptEeDvx6XZn7ApUY div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ptEeDvx6XZn7ApUY .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ptEeDvx6XZn7ApUY rect.text{fill:none;stroke-width:0;}#mermaid-svg-ptEeDvx6XZn7ApUY .icon-shape,#mermaid-svg-ptEeDvx6XZn7ApUY .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ptEeDvx6XZn7ApUY .icon-shape p,#mermaid-svg-ptEeDvx6XZn7ApUY .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ptEeDvx6XZn7ApUY .icon-shape .label rect,#mermaid-svg-ptEeDvx6XZn7ApUY .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ptEeDvx6XZn7ApUY .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ptEeDvx6XZn7ApUY .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ptEeDvx6XZn7ApUY :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
是
否
IP 层 → TCPReceive
LibIPInsertPacket
创建 pbuf 注入 netif
tcpip 线程: tcp_input
lwIP 校验/序号处理
tcp_recv 回调
InternalRecvEventHandler
LibTCPEnqueuePacket 挂入 PacketQueue
tcp_recved 通知 lwIP
TCPRecvEventHandler
有挂起的 ReceiveRequest?
LibTCPGetDataFromConnectionQueue
复制数据到用户 MDL 缓冲
CompleteBucket 完成 IRP
应用 recv 返回
数据留在队列等待
14.4 监听与接受流程
#mermaid-svg-Pf82DBbYmNKxP41n{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Pf82DBbYmNKxP41n .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Pf82DBbYmNKxP41n .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Pf82DBbYmNKxP41n .error-icon{fill:#552222;}#mermaid-svg-Pf82DBbYmNKxP41n .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Pf82DBbYmNKxP41n .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Pf82DBbYmNKxP41n .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Pf82DBbYmNKxP41n .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Pf82DBbYmNKxP41n .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Pf82DBbYmNKxP41n .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Pf82DBbYmNKxP41n .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Pf82DBbYmNKxP41n .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Pf82DBbYmNKxP41n .marker.cross{stroke:#333333;}#mermaid-svg-Pf82DBbYmNKxP41n svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Pf82DBbYmNKxP41n p{margin:0;}#mermaid-svg-Pf82DBbYmNKxP41n .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-Pf82DBbYmNKxP41n .cluster-label text{fill:#333;}#mermaid-svg-Pf82DBbYmNKxP41n .cluster-label span{color:#333;}#mermaid-svg-Pf82DBbYmNKxP41n .cluster-label span p{background-color:transparent;}#mermaid-svg-Pf82DBbYmNKxP41n .label text,#mermaid-svg-Pf82DBbYmNKxP41n span{fill:#333;color:#333;}#mermaid-svg-Pf82DBbYmNKxP41n .node rect,#mermaid-svg-Pf82DBbYmNKxP41n .node circle,#mermaid-svg-Pf82DBbYmNKxP41n .node ellipse,#mermaid-svg-Pf82DBbYmNKxP41n .node polygon,#mermaid-svg-Pf82DBbYmNKxP41n .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Pf82DBbYmNKxP41n .rough-node .label text,#mermaid-svg-Pf82DBbYmNKxP41n .node .label text,#mermaid-svg-Pf82DBbYmNKxP41n .image-shape .label,#mermaid-svg-Pf82DBbYmNKxP41n .icon-shape .label{text-anchor:middle;}#mermaid-svg-Pf82DBbYmNKxP41n .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Pf82DBbYmNKxP41n .rough-node .label,#mermaid-svg-Pf82DBbYmNKxP41n .node .label,#mermaid-svg-Pf82DBbYmNKxP41n .image-shape .label,#mermaid-svg-Pf82DBbYmNKxP41n .icon-shape .label{text-align:center;}#mermaid-svg-Pf82DBbYmNKxP41n .node.clickable{cursor:pointer;}#mermaid-svg-Pf82DBbYmNKxP41n .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Pf82DBbYmNKxP41n .arrowheadPath{fill:#333333;}#mermaid-svg-Pf82DBbYmNKxP41n .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Pf82DBbYmNKxP41n .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Pf82DBbYmNKxP41n .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Pf82DBbYmNKxP41n .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Pf82DBbYmNKxP41n .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Pf82DBbYmNKxP41n .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Pf82DBbYmNKxP41n .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Pf82DBbYmNKxP41n .cluster text{fill:#333;}#mermaid-svg-Pf82DBbYmNKxP41n .cluster span{color:#333;}#mermaid-svg-Pf82DBbYmNKxP41n div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Pf82DBbYmNKxP41n .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Pf82DBbYmNKxP41n rect.text{fill:none;stroke-width:0;}#mermaid-svg-Pf82DBbYmNKxP41n .icon-shape,#mermaid-svg-Pf82DBbYmNKxP41n .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Pf82DBbYmNKxP41n .icon-shape p,#mermaid-svg-Pf82DBbYmNKxP41n .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Pf82DBbYmNKxP41n .icon-shape .label rect,#mermaid-svg-Pf82DBbYmNKxP41n .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Pf82DBbYmNKxP41n .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Pf82DBbYmNKxP41n .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Pf82DBbYmNKxP41n :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
是
否
应用 listen
TDI_LISTEN → TCPListen
LibTCPBind 绑定地址
LibTCPListen 进入监听
tcp_accept 注册回调
应用 accept → TCPAccept
挂入 ListenRequest 队列
远端 SYN 到达
lwIP 完成三次握手
tcp_accept 回调 → TCPAcceptEventHandler
TCPCheckPeerForAccept 获取远端地址
成功?
释放旧 socket 上下文
SocketContext = newpcb
LibTCPAccept 设置新 PCB 回调
CompleteBucket 完成 accept IRP
以错误完成
应用 accept 返回新 socket
15. 数据流图
15.1 完整的发送数据流
应用程序 send(buf)
│
▼
TDI_SEND IRP → DispTdiSend → TCPSendData
│
│ TDI_BUCKET { Complete, Context } 挂入 SendRequest
│
▼
LibTCPSend → tcpip 线程 → tcp_write(pcb, buf, len)
│
│ lwIP 将数据加入发送队列, 构造 TCP 段:
│ ┌──────────────────────────────────────┐
│ │ TCP 头 (20B) │
│ │ SourcePort / DestPort │
│ │ Seq = snd_nxt │
│ │ Ack = rcv_nxt │
│ │ Flags = ACK | PSH │
│ │ Window = rcv_wnd │
│ │ Checksum = TCP 伪头校验和 │
│ ├──────────────────────────────────────┤
│ │ 数据 (应用负载) │
│ └──────────────────────────────────────┘
│
▼
tcp_output → IP 层 (IPTransmitPacket)
│
▼
网络接口层 → LAN → NDIS → 网卡
│
▼ (远端 ACK 到达)
lwIP tcp_in → tcp_sent 回调
│
▼
TCPSendEventHandler → 完成用户 IRP
│
▼
send() 返回
15.2 完整的接收数据流
网卡 → NDIS → 网络接口层 → IP 层
│
▼
TCPReceive → LibIPInsertPacket → pbuf
│
▼
tcpip 线程: tcp_input
│
│ 校验和验证 → 序号检查 → 状态机处理
│
▼
数据到达 → tcp_recv 回调 (InternalRecvEventHandler)
│
├─ pbuf 挂入 Connection->PacketQueue
├─ tcp_recved (滑动窗口更新)
└─ TCPRecvEventHandler
│
▼
从 ReceiveRequest 取 Bucket
│
▼
LibTCPGetDataFromConnectionQueue
│ 从 pbuf 复制到用户缓冲 (MDL)
▼
CompleteBucket → 完成 TDI IRP
│
▼
DispDataRequestComplete → IoCompleteRequest
│
▼
recv() 返回数据
15.3 TDI_BUCKET 生命周期
创建 (TCPSendData/TCPReceiveData/TCPConnect…)
│ ExAllocateFromNPagedLookasideList(TdiBucketLookasideList)
▼
挂起 (InsertTailList → PendingIrpList)
│ 等待 lwIP 事件
▼
触发 (TCP*EventHandlers)
│ RemoveHeadList
▼
完成 (CompleteBucket)
│ BucketCompletionWorker
│ ├─ Complete(Context, Status, Information) → 完成用户 IRP
│ ├─ DereferenceObject(Connection)
│ └─ ExFreeToNPagedLookasideList(Bucket)
▼
释放
16. 关键函数索引
16.1 TCP 核心 (tcp.c)
| TCPStartup | [tcp.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/tcp.c#L208-L240) | 初始化:端口集/Bucket 池/LibIP/注册协议 |
| TCPShutdown | [tcp.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/tcp.c#L243-L265) | 清理 |
| TCPSocket | [tcp.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/tcp.c#L153) | 创建 socket (LibTCPSocket) |
| TCPConnect | [tcp.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/tcp.c#L301-L424) | 发起连接 |
| TCPDisconnect | [tcp.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/tcp.c#L426-L526) | 断开 (FIN/RST) |
| TCPSendData | [tcp.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/tcp.c#L579-L630) | 发送数据 |
| TCPReceiveData | [tcp.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/tcp.c#L528-L577) | 接收数据 |
| TCPReceive | [tcp.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/tcp.c#L192-L206) | IP 层接收入口 |
| TCPClose | [tcp.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/tcp.c#L177-L190) | 关闭连接 |
| TCPTranslateError | [tcp.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/tcp.c#L267-L299) | err_t → NTSTATUS |
| TCPAllocatePort / TCPFreePort | [tcp.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/tcp.c#L636-L655) | 端口管理 |
| TCPRemoveIRP | [tcp.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/tcp.c#L695) | 取消 IRP |
16.2 监听/接受 (accept.c)
| TCPListen | [accept.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/accept.c#L47-L105) | 监听 (LibTCPBind+Listen) |
| TCPAccept | [accept.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/accept.c#L139) | 接受连接 |
| TCPCheckPeerForAccept | [accept.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/accept.c#L17-L43) | 获取远端地址 |
| TCPAbortListenForSocket | [accept.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/accept.c#L107-L137) | 中止监听 |
16.3 事件处理 (event.c)
| TCPConnectEventHandler | [event.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/event.c#L419-L441) | 连接完成 |
| TCPAcceptEventHandler | [event.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/event.c#L230-L291) | 新连接接受 |
| TCPSendEventHandler | [event.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/event.c#L293-L377) | 可发送 |
| TCPRecvEventHandler | [event.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/event.c#L379-L417) | 数据到达 |
| TCPFinEventHandler | [event.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/event.c#L181-L228) | 连接终止 |
| CompleteBucket | [event.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/event.c#L37-L50) | 完成请求桶 |
| BucketCompletionWorker | [event.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/event.c#L21-L35) | 完成工作项 |
| FlushAllQueues | [event.c](file:///d:/reactos/drivers/network/tcpip/ip/transport/tcp/event.c#L156-L179) | 清空所有队列 |
16.4 lwIP 粘合层 (lwip_glue/tcp.c)
| LibTCPSocket | [tcp.c 粘合](file:///d:/reactos/drivers/network/tcpip/ip/lwip_glue/tcp.c#L336) | tcp_new |
| LibTCPConnect | [tcp.c 粘合](file:///d:/reactos/drivers/network/tcpip/ip/lwip_glue/tcp.c#L621-L635) | tcp_connect |
| LibTCPSend | [tcp.c 粘合](file:///d:/reactos/drivers/network/tcpip/ip/lwip_glue/tcp.c#L556-L590) | tcp_write+tcp_output |
| LibTCPBind | [tcp.c 粘合](file:///d:/reactos/drivers/network/tcpip/ip/lwip_glue/tcp.c#L414-L440) | tcp_bind |
| LibTCPListen | [tcp.c 粘合](file:///d:/reactos/drivers/network/tcpip/ip/lwip_glue/tcp.c#L469-L495) | tcp_listen |
| LibTCPShutdown | [tcp.c 粘合](file:///d:/reactos/drivers/network/tcpip/ip/lwip_glue/tcp.c) | tcp_shutdown |
| LibTCPClose | [tcp.c 粘合](file:///d:/reactos/drivers/network/tcpip/ip/lwip_glue/tcp.c) | tcp_close |
| LibTCPEnqueuePacket | [tcp.c 粘合](file:///d:/reactos/drivers/network/tcpip/ip/lwip_glue/tcp.c#L73-L84) | pbuf 入队 |
| LibTCPGetDataFromConnectionQueue | [tcp.c 粘合](file:///d:/reactos/drivers/network/tcpip/ip/lwip_glue/tcp.c#L100) | pbuf 出队复制 |
| LibIPInsertPacket | [ip.c 粘合](file:///d:/reactos/drivers/network/tcpip/ip/lwip_glue/ip.c) | 注入 IP 包 |
| LibTCPAccept | [tcp.c 粘合](file:///d:/reactos/drivers/network/tcpip/ip/lwip_glue/tcp.c) | 设置新 PCB 回调 |
附录 A:保留的 Linux 移植结构 (tcpcore.h)
include/tcpcore.h 保留了 Linux 内核 2.4.20 的完整移植:
| struct sk_buff | 套接字缓冲区 (head/data/tail/end 指针) |
| struct skb_shared_info | skb 共享信息 (分片) |
| struct sk_buff_head | skb 队列 |
| struct tcp_opt | TCP 选项/状态 (rcv_nxt/snd_nxt/snd_una/snd_wnd 等) |
| struct sock | socket 状态 |
这些结构保留但不再是活动实现(当前使用 lwIP 的 struct tcp_pcb)。
附录 B:参考文档
- [tcpip传输层UDP分析](file:///d:/reactos/doc/tcpip传输层UDP分析.md) — UDP 传输层
- [tcpip网络层IP分析](file:///d:/reactos/doc/tcpip网络层IP分析.md) — IP 网络层
- [TCPIP 驱动分析](file:///d:/reactos/doc/TCPIP_驱动分析.md) — tcpip.sys 整体
- [lwIP 源码](file:///d:/reactos/drivers/network/tcpip/lwip/) — lwIP 协议栈
- RFC 793 — Transmission Control Protocol
- RFC 1122 — Requirements for Internet Hosts
- RFC 2581 — TCP Congestion Control
网硕互联帮助中心



评论前必须登录!
注册