第 10 章 网络操作 --- 10.5 Socket的有连接通信
本节剖析 TCP 协议的 Socket 有连接通信实现。 TCP(Transmission Control Protocol)是面向连接、可靠的传输层协议,在 Winsock 中对应 SOCK_STREAM。ReactOS 的 TCP 实现在 AFD 的 connect/accept/send/recv 路径以及 TCP/IP(tcpip.sys)的 lwIP TCP 实现中。
概述
TCP 通信的关键特性:
- 面向连接:通信前需建立连接(三次握手)
- 可靠传输:超时重传、确认应答、流量控制
- 字节流:无消息边界,发送和接收可分片
- 全双工:双向独立数据传输
- 有序:保证数据按发送顺序到达
本节内容概览
- 10.5.0 框架图
- 10.5.1 TCP 协议概述
- 10.5.2 TCP socket 状态机
- 10.5.3
connect连接建立 - 10.5.4
accept接受连接 - 10.5.5
send/recv数据传输 - 10.5.6
close关闭连接(四次挥手) - 10.5.7 滑动窗口与流量控制
- 10.5.8 总结与代码索引
学习目标
- 理解 TCP 三次握手、四次挥手
- 掌握 socket 状态机
- 知道
connect/accept在 AFD 的路径 - 跟踪 TCP 数据流
涉及的内核子系统
| 子系统 | 头文件/源文件 | 核心作用 |
|---|---|---|
| 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 |
| TCP/IP | drivers/network/tcpip/tcpip/(file:///d:/reactos/drivers/network/tcpip/tcpip/) | TCP/IP 协议栈 |
| lwIP TCP | drivers/network/tcpip/ip/src/core/tcp_in.c(file:///d:/reactos/drivers/network/tcpip/ip/src/core/tcp_in.c) | TCP 输入 |
| lwIP TCP | drivers/network/tcpip/ip/src/core/tcp_out.c(file:///d:/reactos/drivers/network/tcpip/ip/src/core/tcp_out.c) | TCP 输出 |
| Winsock | dll/win32/ws2_32/(file:///d:/reactos/dll/win32/ws2_32/) | 用户态 Winsock |
10.5.0 框架图
客户端 服务端
+--------+ +--------+
| socket | ----SYN---> | listen |
| | <---SYN+ACK--- | |
| | ----ACK---> | |
| ESTABLISHED ESTABLISHED
| | ----DATA---> | |
| | <---ACK--- | |
| | ----FIN---> | |
| FIN_WAIT1 CLOSE_WAIT
| | <---ACK--- | |
| FIN_WAIT2 | |
| | <---FIN--- | |
| TIME_WAIT LAST_ACK
| | ----ACK---> | |
| CLOSED CLOSED
+--------+ +--------+
10.5.1 TCP 协议概述
TCP 头(20 字节)
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 | |U|A|P|R|S|F| |
| Offset| Reserved |R|C|S|S|Y|I| Window |
| | |G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options (if Data Offset > 5) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
关键字段
- Sequence Number (SEQ):数据字节序号
- Acknowledgment Number (ACK):下一个期望的字节序号
- Flags:SYN、ACK、FIN、RST、PSH、URG
- Window:接收方滑动窗口大小
状态机
CLOSED -> LISTEN (服务器 listen)
-> SYN_SENT (客户端 connect)
LISTEN -> SYN_RCVD (收到 SYN, 发送 SYN+ACK)
SYN_SENT -> ESTABLISHED (收到 SYN+ACK, 发送 ACK)
SYN_RCVD -> ESTABLISHED (收到 ACK)
ESTABLISHED -> FIN_WAIT_1 (close, 发送 FIN)
ESTABLISHED -> CLOSE_WAIT (收到 FIN, 发送 ACK)
FIN_WAIT_1 -> FIN_WAIT_2 (收到 ACK)
FIN_WAIT_2 -> TIME_WAIT (收到 FIN, 发送 ACK)
CLOSE_WAIT -> LAST_ACK (close, 发送 FIN)
LAST_ACK -> CLOSED (收到 ACK)
TIME_WAIT -> CLOSED (2*MSL 后)
10.5.2 TCP socket 状态机
AFD 端点状态
c
typedef enum {
SOCKET_STATE_CREATED, // 已创建
SOCKET_STATE_BOUND, // 已 bind
SOCKET_STATE_LISTENING, // listen 中
SOCKET_STATE_CONNECTING, // connect 中
SOCKET_STATE_CONNECTED, // 已连接
SOCKET_STATE_DISCONNECTING, // 关闭中
SOCKET_STATE_CLOSED, // 已关闭
} AFD_SOCKET_STATE;
10.5.3 connect 连接建立
应用层
c
SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
connect(s, (struct sockaddr*)&addr, sizeof(addr));
路径
ws2_32.dll::connect→IOCTL_AFD_CONNECT- AFD
AfdConnect打开\Device\Tcp创建设备对象 - AFD 构造
TDI_CONNECT请求 - 调 TCP/IP 的
TdiDispatch - TCP/IP 调用 lwIP
tcp_connect - lwIP 发送 SYN 包,开始三次握手
AFD AfdConnect
connect.c(file:///d:/reactos/drivers/network/afd/afd/connect.c):
c
NTSTATUS AfdConnect(PAFD_ENDPOINT Endpoint, PAFD_CONNECT_REQUEST ConnectReq)
{
NTSTATUS Status;
PIRP Irp;
IO_STATUS_BLOCK IoStatus;
// 1. 打开 Tcp 设备(每个 socket 一个)
RtlInitUnicodeString(&DeviceName, L"\\Device\\Tcp");
InitializeObjectAttributes(...);
ZwCreateFile(&Endpoint->TdiConnectionHandle, ...);
// 2. 关联地址
Status = TdiAssociateAddress(Endpoint->TdiConnectionHandle,
Endpoint->TdiAddressHandle);
// 3. 构造 TDI_CONNECT 请求
PTDI_CONNECTION_INFORMATION ConnInfo = ...;
// 填充 RemoteAddress 为 ConnectReq->Address
Irp = TdiBuildConnect(Endpoint->TdiConnectionHandle,
IoGetRelatedDeviceObject(Endpoint->TdiConnectionHandle),
ConnectComplete, // 完成例程
Endpoint,
ConnInfo, 0, NULL);
// 4. 发起连接
Status = IoCallDriver(Endpoint->TdiDeviceObject, Irp);
// 5. 等待连接完成(同步 connect)
if (Status == STATUS_PENDING) {
Endpoint->State = SOCKET_STATE_CONNECTING;
KeWaitForSingleObject(Endpoint->ConnectEvent, Executive, KernelMode, FALSE, NULL);
Status = Endpoint->ConnectStatus;
}
if (NT_SUCCESS(Status)) {
Endpoint->State = SOCKET_STATE_CONNECTED;
}
return Status;
}
lwIP tcp_connect
c
// lwIP 内部
err_t tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
tcp_connected_fn connected)
{
// 1. 状态 -> SYN_SENT
pcb->state = SYN_SENT;
// 2. 构造 SYN 包
tcp_output_control_segment(pcb, TCP_SYN);
// 3. 启动重传定时器
pcb->rtime = 0;
pcb->nrtx = 0;
return ERR_OK;
}
TCP 三次握手
lwIP 内部状态机处理:
客户端 lwIP: tcp_connect
- 状态: SYN_SENT
- 发送 SYN (SEQ = x)
|
v
服务端 lwIP: tcp_input
- 状态: LISTEN -> SYN_RCVD
- 发送 SYN+ACK (SEQ = y, ACK = x+1)
|
v
客户端 lwIP: tcp_input
- 状态: SYN_SENT -> ESTABLISHED
- 发送 ACK (ACK = y+1)
- 通知应用(通过 PCB 回调)
10.5.4 accept 接受连接
服务端
c
SOCKET listen_sock = socket(AF_INET, SOCK_STREAM, 0);
bind(listen_sock, ...);
listen(listen_sock, 5);
SOCKET client_sock = accept(listen_sock, NULL, NULL);
路径
ws2_32.dll::listen→IOCTL_AFD_LISTEN- AFD
AfdListen通知 TCP/IP 开始监听 ws2_32.dll::accept→IOCTL_AFD_ACCEPT- AFD
AfdAccept等待新连接 - TCP/IP 收到 SYN 完成三次握手
- AFD 接收通知,accept 返回
AFD AfdAccept
listen.c(file:///d:/reactos/drivers/network/afd/afd/listen.c):
c
NTSTATUS AfdAccept(PAFD_ENDPOINT ListenEndpoint, PAFD_ACCEPT_REQUEST AcceptReq)
{
// 1. 创建新端点(client socket)
PAFD_ENDPOINT NewEndpoint = CreateNewEndpoint();
// 2. 打开新的 \Device\Tcp 设备
ZwCreateFile(&NewEndpoint->TdiConnectionHandle, ...);
// 3. 构造 IRP 等待连接
PIRP Irp = TdiBuildAccept(
NewEndpoint->TdiConnectionHandle,
...,
NewEndpoint,
...);
// 4. 调用 TCP/IP 等待连接
IoCallDriver(NewEndpoint->TdiDeviceObject, Irp);
// 5. 等待完成
if (Irp->IoStatus.Status == STATUS_PENDING) {
KeWaitForSingleObject(NewEndpoint->AcceptEvent, ...);
}
// 6. 返回客户端 socket 句柄
*AcceptReq->AcceptHandle = NewEndpoint->Handle;
return STATUS_SUCCESS;
}
10.5.5 send/recv 数据传输
TCP 发送
c
send(s, buf, len, 0);
AFD AfdSend(write.c(file:///d:/reactos/drivers/network/afd/afd/write.c)):
c
NTSTATUS AfdSend(PAFD_ENDPOINT Endpoint, PAFD_SEND_INFO SendInfo, ...) {
// 1. 构造 TDI_SEND 请求
PIRP Irp = TdiBuildSend(
Endpoint->TdiConnectionHandle,
...,
Buffer, Length,
0, // SendFlags
NULL);
// 2. 调用 TCP/IP
IoCallDriver(Endpoint->TdiDeviceObject, Irp);
// 3. 等待或异步
// ...
}
TCP 接收
c
recv(s, buf, len, 0);
AFD AfdReceive(read.c(file:///d:/reactos/drivers/network/afd/afd/read.c)):
c
NTSTATUS AfdReceive(PAFD_ENDPOINT Endpoint, ...) {
// 1. 构造 MDL
PMDL Mdl = IoAllocateMdl(Buf, Length, ...);
MmBuildMdlForNonPagedPool(Mdl);
// 2. 构造 TDI_RECEIVE 请求
PIRP Irp = TdiBuildReceive(
Endpoint->TdiConnectionHandle,
...,
Mdl, 0);
// 3. 调用 TCP/IP
IoCallDriver(Endpoint->TdiDeviceObject, Irp);
// 4. 等待
// ...
}
lwIP TCP 发送
c
// lwIP 内部
err_t tcp_write(struct tcp_pcb *pcb, const void *data, u16_t len, u8_t apiflags)
{
// 1. 检查发送窗口
if (len > pcb->snd_buf) {
return ERR_MEM;
}
// 2. 把数据复制到 PCB 缓冲
p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
pbuf_take(p, data, len);
pcb->unsent = p; // 加入 unsent 队列
// 3. 启动发送
tcp_output(pcb);
return ERR_OK;
}
lwIP TCP 接收
c
// lwIP 内部
err_t tcp_input(struct pbuf *p, struct netif *inp)
{
// 1. 解析 TCP 头
struct tcp_hdr *tcphdr = p->payload;
// 2. 查找 PCB
pcb = tcp_lookup(...);
// 3. 处理数据
if (tcphdr->flags & TCP_SYN) {
// 处理 SYN
}
if (tcphdr->flags & TCP_ACK) {
// 处理 ACK
}
if (p->tot_len > hdr_len) {
// 收到数据
// 复制到 PCB 的 recv 队列
pbuf_cat(pcb->recved, p);
// 通知应用
recv_data(pcb, pcb->recved);
}
}
10.5.6 close 关闭连接(四次挥手)
主动关闭
c
closesocket(s);
路径
ws2_32.dll::closesocket→IOCTL_AFD_CLOSE- AFD
AfdClose调TdiDisconnect - TCP/IP 调用 lwIP
tcp_close - lwIP 发送 FIN,状态 -> FIN_WAIT_1
- 收到 ACK -> FIN_WAIT_2
- 收到 FIN -> 发送 ACK -> TIME_WAIT
- 2*MSL 后 -> CLOSED
lwIP TCP 关闭
c
err_t tcp_close(struct tcp_pcb *pcb)
{
if (pcb->state != ESTABLISHED) {
return ERR_OK;
}
// 1. 状态 -> FIN_WAIT_1
pcb->state = FIN_WAIT_1;
// 2. 发送 FIN
tcp_output_control_segment(pcb, TCP_FIN);
return ERR_OK;
}
主动 close
客户端 close:
- 发送 FIN
- 状态 -> FIN_WAIT_1
- 收到 ACK -> FIN_WAIT_2
- 收到 FIN (服务端也 close) -> 发送 ACK -> TIME_WAIT
- 2*MSL 后 -> CLOSED
服务端:
- 收到 FIN -> 状态 -> CLOSE_WAIT
- 应用 close -> 发送 FIN -> LAST_ACK
- 收到 ACK -> CLOSED
10.5.7 滑动窗口与流量控制
TCP 使用 滑动窗口协议 进行流量控制:
- 接收方 通告窗口大小(
Window字段) - 发送方 不会发送超过窗口的数据
- 接收方处理数据后,发送 ACK + 新窗口大小
关键参数
- RTT(Round-Trip Time):往返时间
- MSS(Maximum Segment Size):最大段大小(典型 1460 字节)
- cwnd(Congestion Window):拥塞窗口
- rwnd(Receiver Window):接收窗口
- ssthresh:慢启动阈值
拥塞控制
- 慢启动:cwnd 指数增长
- 拥塞避免:cwnd 线性增长
- 快速重传:收到 3 个重复 ACK 时重传
- 快速恢复:避免 cwnd 重置
10.5.8 总结
关键要点:
- TCP 面向连接:三次握手建立连接
- socket 状态机:SYN_SENT、ESTABLISHED、FIN_WAIT_*、TIME_WAIT 等
connect调用 :通过IOCTL_AFD_CONNECT→TDI_CONNECT→tcp_connectaccept调用 :通过IOCTL_AFD_ACCEPT→TDI_ACCEPTsend/recv调用 :通过TDI_SEND/TDI_RECEIVE- 四次挥手关闭:FIN_WAIT、CLOSE_WAIT、LAST_ACK、TIME_WAIT
- 滑动窗口:流量控制
- lwIP TCP 实现 :
tcp_in、tcp_out模块
TCP 有连接通信的深度技术分析
TCP(Transmission Control Protocol)是互联网上最重要的传输层协议,为绝大多数应用(HTTP、FTP、SSH、SMTP 等)提供可靠的字节流传输服务。本节深入分析 TCP 在 ReactOS 中的完整实现,从连接建立到数据传输,再到连接关闭的每个环节。
TCP 协议的核心机制
TCP 的设计目标是提供可靠的、有序的、无差错的字节流传输。为实现这一目标,TCP 引入了以下核心机制:
- 三次握手:建立连接前,双方交换 SYN 和 ACK 包,同步序列号并协商参数。
- 确认应答(ACK):接收方确认收到的数据,发送方根据 ACK 判断数据是否成功送达。
- 超时重传:发送方在超时未收到 ACK 时重传数据,确保可靠性。
- 滑动窗口:接收方通告可接收的字节数,控制发送方的发送速率,实现流量控制。
- 拥塞控制:发送方根据网络状况动态调整发送窗口,避免网络拥塞。
- 序列号:每个字节都有唯一序列号,用于重组和去重。
lwIP 中 TCP 的数据结构
ReactOS 的 TCP 实现基于 lwIP,核心数据结构是 tcp_pcb(Protocol Control Block):
c
struct tcp_pcb {
// 连接信息
ip_addr_t local_ip; // 本地 IP
ip_addr_t remote_ip; // 远程 IP
u16_t local_port; // 本地端口
u16_t remote_port; // 远程端口
// 状态
u8_t state; // TCP 状态(CLOSED/LISTEN/SYN_SENT/...)
// 序列号
u32_t snd_nxt; // 下一个发送序列号
u32_t rcv_nxt; // 下一个期望接收序列号
u32_t snd_wl1; // 窗口更新序列号
u32_t snd_wl2; // 窗口更新序列号
u32_t lastack; // 最后一个 ACK 序列号
// 窗口
u16_t snd_wnd; // 发送窗口
u16_t rcv_wnd; // 接收窗口
u16_t cwnd; // 拥塞窗口
u16_t ssthresh; // 慢启动阈值
// 定时器
u32_t rtt; // RTT 估计
u32_t rto; // 重传超时
u32_t tmr; // 定时器
// 发送队列
struct tcp_seg *unsent; // 未发送的段
struct tcp_seg *unacked; // 已发送未确认的段
// 接收队列
struct tcp_seg *ooseq; // 乱序段
// 回调
void (*recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err);
err_t (*sent)(void *arg, struct tcp_pcb *tpcb, u16_t len);
void (*err)(void *arg, err_t err);
err_t (*accept)(void *arg, struct tcp_pcb *newpcb, err_t err);
// 链表
struct tcp_pcb *next;
};
lwIP 维护三个 TCP PCB 链表:
tcp_active_pcbs:活跃连接tcp_listen_pcbs:监听中的 sockettcp_tw_pcbs:TIME_WAIT 状态的连接
三次握手的详细实现
TCP 三次握手在 lwIP 中的实现分为客户端和服务端两侧:
客户端侧(tcp_connect):
- 应用调用
connect()→ AFD → TDI → lwIPtcp_connect tcp_connect分配序列号(ISN),创建 SYN 段- 状态变为
SYN_SENT - 将 SYN 段加入发送队列
- 调用
tcp_output发送 SYN 包 - 启动重传定时器(RTO = 3 秒)
c
err_t tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port,
tcp_connected_fn connected)
{
u32_t iss;
pcb->remote_ip = *ipaddr;
pcb->remote_port = port;
pcb->state = SYN_SENT;
// 生成初始序列号
iss = tcp_next_iss();
pcb->snd_nxt = iss;
pcb->lastack = iss;
// 注册连接完成回调
pcb->connected = connected;
// 发送 SYN
tcp_enqueue(pcb, TCP_TCPLEN, NULL, 0, TCP_SYN, TCP_WRITE_FLAG_COPY);
tcp_output(pcb);
return ERR_OK;
}
服务端侧(tcp_listen + tcp_accept):
- 应用调用
listen()→ AFD → TDI → lwIPtcp_listen tcp_listen创建tcp_pcb_listen,状态变为LISTEN- 收到 SYN 包时,
tcp_input处理:- 创建新的
tcp_pcb - 分配序列号
- 发送 SYN+ACK 包
- 状态变为
SYN_RCVD
- 创建新的
- 收到 ACK 包时,
tcp_input处理:- 状态变为
ESTABLISHED - 调用
accept回调通知应用
- 状态变为
三次握手的关键参数协商:
- MSS(Maximum Segment Size):通过 TCP 选项协商,通常为 1460 字节
- 窗口缩放:通过 TCP 选项支持大于 64KB 的窗口
- 时间戳:通过 TCP 选项支持 RTT 精确测量
- SACK(Selective ACK):通过 TCP 选项支持选择性重传
数据传输的实现
TCP 数据传输涉及发送和接收两个方向,以及复杂的流控和拥塞控制机制。
发送路径:
- 应用调用
send()→ AFD → TDI → lwIPtcp_write tcp_write将数据复制到pbuf,加入unsent队列tcp_output检查发送条件:- 发送窗口(
snd_wnd)> 0 - 拥塞窗口(
cwnd)> 0 - Nagle 算法(合并小段)
- 发送窗口(
- 符合条件的段被发送,从
unsent移到unacked - 启动重传定时器
c
err_t tcp_write(struct tcp_pcb *pcb, const void *data, u16_t len, u8_t apiflags)
{
// 检查发送缓冲区空间
if (len > pcb->snd_buf) {
return ERR_MEM;
}
// 分配 pbuf,复制数据
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
pbuf_take(p, data, len);
// 加入 unsent 队列
tcp_seg *seg = tcp_create_segment(pcb, p, 0);
tcp_seg_append(&pcb->unsent, seg);
// 更新发送缓冲区
pcb->snd_buf -= len;
// 立即发送
return tcp_output(pcb);
}
接收路径:
- NIC 收到 TCP 段 → 中断 → NDIS → tcpip.sys → lwIP
tcp_input tcp_input解析 TCP 头,查找匹配的 PCB- 检查序列号是否在接收窗口内
- 如果序列号正确(
rcv_nxt),数据放入接收队列 - 如果有乱序数据,放入
ooseq队列 - 调用
recv回调通知应用 - 发送 ACK 确认收到的数据
- 更新接收窗口
拥塞控制算法
ReactOS 的 lwIP 实现了基本的 TCP 拥塞控制:
-
慢启动 :连接建立时,
cwnd从 1 MSS 开始,每收到一个 ACK 增加 1 MSS,指数增长直到达到ssthresh。 -
拥塞避免 :
cwnd超过ssthresh后,每个 RTT 增加 1 MSS,线性增长。 -
快速重传 :收到 3 个重复 ACK 时,立即重传丢失的段,将
ssthresh设为cwnd/2,cwnd设为ssthresh + 3。 -
快速恢复 :快速重传后,
cwnd从ssthresh开始线性增长,而不是回到慢启动。
四次挥手的详细实现
TCP 连接关闭使用四次挥手,允许双方独立关闭发送方向:
主动关闭方:
- 应用调用
closesocket()→ AFD → TDI → lwIPtcp_close tcp_close发送 FIN 包,状态变为FIN_WAIT_1- 收到 ACK 后,状态变为
FIN_WAIT_2 - 收到对方的 FIN 后,发送 ACK,状态变为
TIME_WAIT TIME_WAIT持续 2*MSL(通常 60 秒),确保最后的 ACK 到达对方- 超时后,状态变为
CLOSED,释放 PCB
被动关闭方:
- 收到 FIN 后,发送 ACK,状态变为
CLOSE_WAIT recv回调返回 0(表示对端关闭)- 应用调用
closesocket()→ lwIPtcp_close - 发送 FIN 包,状态变为
LAST_ACK - 收到 ACK 后,状态变为
CLOSED
TIME_WAIT 状态的重要性:
- 确保最后的 ACK 能到达对方(如果丢失,对方会重传 FIN)
- 等待网络中残留的旧段消失,防止新连接收到旧数据
- 2*MSL 通常为 60 秒(MSL = 30 秒)
TCP 定时器机制
lwIP 使用多个定时器管理 TCP 连接:
-
重传定时器:每个未确认的段都有独立的重传定时器。超时后重传该段,RTO 按指数退避(3s → 6s → 12s → ...)。
-
TIME_WAIT 定时器 :
TIME_WAIT状态的连接在 2*MSL 后自动关闭。 -
保活定时器:可选机制,定期发送空段检测对端是否存活。默认 2 小时无数据后开始发送保活段。
-
延迟 ACK 定时器:收到数据后不立即发送 ACK,等待 200ms 或收到更多数据后一起发送 ACK,减少 ACK 数量。
与 Windows TCP 实现的对比
| 特性 | Windows TCP | ReactOS TCP (lwIP) |
|---|---|---|
| 拥塞控制 | Cubic/NewReno | 基本 Reno |
| 窗口缩放 | 支持(最大 16MB) | 支持(最大 1GB) |
| 时间戳 | 支持 | 支持 |
| SACK | 支持 | 基本支持 |
| ECN | 支持 | 不支持 |
| TFO | 支持 | 不支持 |
| 快速打开 | 支持 | 不支持 |
| 多路径 | MPTCP | 不支持 |
| 接收端合并 | 支持 | 不支持 |
ReactOS 的 TCP 实现基于 lwIP,虽然功能上不如 Windows 完整,但已经实现了 TCP 的核心机制,能够支持大多数常见的网络应用。lwIP 的模块化设计使得未来可以逐步添加高级特性。
本章代码索引
| 文件 | 内容 |
|---|---|
| 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) | AfdListen/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 |
| tcpip/(file:///d:/reactos/drivers/network/tcpip/tcpip/) | TCP/IP 协议栈 |
| ip/src/core/tcp_in.c(file:///d:/reactos/drivers/network/tcpip/ip/src/core/tcp_in.c) | lwIP TCP 输入 |
| ip/src/core/tcp_out.c(file:///d:/reactos/drivers/network/tcpip/ip/src/core/tcp_out.c) | lwIP TCP 输出 |
| ws2_32/(file:///d:/reactos/dll/win32/ws2_32/) | Winsock DLL |