Reactos 第 10 章 网络操作 — 10.5 Socket的有连接通信

第 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 通信的关键特性:

  1. 面向连接:通信前需建立连接(三次握手)
  2. 可靠传输:超时重传、确认应答、流量控制
  3. 字节流:无消息边界,发送和接收可分片
  4. 全双工:双向独立数据传输
  5. 有序:保证数据按发送顺序到达

本节内容概览

  • 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));

路径

  1. ws2_32.dll::connectIOCTL_AFD_CONNECT
  2. AFD AfdConnect 打开 \Device\Tcp 创建设备对象
  3. AFD 构造 TDI_CONNECT 请求
  4. 调 TCP/IP 的 TdiDispatch
  5. TCP/IP 调用 lwIP tcp_connect
  6. 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);

路径

  1. ws2_32.dll::listenIOCTL_AFD_LISTEN
  2. AFD AfdListen 通知 TCP/IP 开始监听
  3. ws2_32.dll::acceptIOCTL_AFD_ACCEPT
  4. AFD AfdAccept 等待新连接
  5. TCP/IP 收到 SYN 完成三次握手
  6. 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 AfdSendwrite.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 AfdReceiveread.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);

路径

  1. ws2_32.dll::closesocketIOCTL_AFD_CLOSE
  2. AFD AfdCloseTdiDisconnect
  3. TCP/IP 调用 lwIP tcp_close
  4. lwIP 发送 FIN,状态 -> FIN_WAIT_1
  5. 收到 ACK -> FIN_WAIT_2
  6. 收到 FIN -> 发送 ACK -> TIME_WAIT
  7. 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 总结

关键要点

  1. TCP 面向连接:三次握手建立连接
  2. socket 状态机:SYN_SENT、ESTABLISHED、FIN_WAIT_*、TIME_WAIT 等
  3. connect 调用 :通过 IOCTL_AFD_CONNECTTDI_CONNECTtcp_connect
  4. accept 调用 :通过 IOCTL_AFD_ACCEPTTDI_ACCEPT
  5. send/recv 调用 :通过 TDI_SEND/TDI_RECEIVE
  6. 四次挥手关闭:FIN_WAIT、CLOSE_WAIT、LAST_ACK、TIME_WAIT
  7. 滑动窗口:流量控制
  8. lwIP TCP 实现tcp_intcp_out 模块

TCP 有连接通信的深度技术分析

TCP(Transmission Control Protocol)是互联网上最重要的传输层协议,为绝大多数应用(HTTP、FTP、SSH、SMTP 等)提供可靠的字节流传输服务。本节深入分析 TCP 在 ReactOS 中的完整实现,从连接建立到数据传输,再到连接关闭的每个环节。

TCP 协议的核心机制

TCP 的设计目标是提供可靠的、有序的、无差错的字节流传输。为实现这一目标,TCP 引入了以下核心机制:

  1. 三次握手:建立连接前,双方交换 SYN 和 ACK 包,同步序列号并协商参数。
  2. 确认应答(ACK):接收方确认收到的数据,发送方根据 ACK 判断数据是否成功送达。
  3. 超时重传:发送方在超时未收到 ACK 时重传数据,确保可靠性。
  4. 滑动窗口:接收方通告可接收的字节数,控制发送方的发送速率,实现流量控制。
  5. 拥塞控制:发送方根据网络状况动态调整发送窗口,避免网络拥塞。
  6. 序列号:每个字节都有唯一序列号,用于重组和去重。

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:监听中的 socket
  • tcp_tw_pcbs:TIME_WAIT 状态的连接

三次握手的详细实现

TCP 三次握手在 lwIP 中的实现分为客户端和服务端两侧:

客户端侧(tcp_connect

  1. 应用调用 connect() → AFD → TDI → lwIP tcp_connect
  2. tcp_connect 分配序列号(ISN),创建 SYN 段
  3. 状态变为 SYN_SENT
  4. 将 SYN 段加入发送队列
  5. 调用 tcp_output 发送 SYN 包
  6. 启动重传定时器(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

  1. 应用调用 listen() → AFD → TDI → lwIP tcp_listen
  2. tcp_listen 创建 tcp_pcb_listen,状态变为 LISTEN
  3. 收到 SYN 包时,tcp_input 处理:
    • 创建新的 tcp_pcb
    • 分配序列号
    • 发送 SYN+ACK 包
    • 状态变为 SYN_RCVD
  4. 收到 ACK 包时,tcp_input 处理:
    • 状态变为 ESTABLISHED
    • 调用 accept 回调通知应用

三次握手的关键参数协商

  • MSS(Maximum Segment Size):通过 TCP 选项协商,通常为 1460 字节
  • 窗口缩放:通过 TCP 选项支持大于 64KB 的窗口
  • 时间戳:通过 TCP 选项支持 RTT 精确测量
  • SACK(Selective ACK):通过 TCP 选项支持选择性重传

数据传输的实现

TCP 数据传输涉及发送和接收两个方向,以及复杂的流控和拥塞控制机制。

发送路径

  1. 应用调用 send() → AFD → TDI → lwIP tcp_write
  2. tcp_write 将数据复制到 pbuf,加入 unsent 队列
  3. tcp_output 检查发送条件:
    • 发送窗口(snd_wnd)> 0
    • 拥塞窗口(cwnd)> 0
    • Nagle 算法(合并小段)
  4. 符合条件的段被发送,从 unsent 移到 unacked
  5. 启动重传定时器
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);
}

接收路径

  1. NIC 收到 TCP 段 → 中断 → NDIS → tcpip.sys → lwIP tcp_input
  2. tcp_input 解析 TCP 头,查找匹配的 PCB
  3. 检查序列号是否在接收窗口内
  4. 如果序列号正确(rcv_nxt),数据放入接收队列
  5. 如果有乱序数据,放入 ooseq 队列
  6. 调用 recv 回调通知应用
  7. 发送 ACK 确认收到的数据
  8. 更新接收窗口

拥塞控制算法

ReactOS 的 lwIP 实现了基本的 TCP 拥塞控制:

  1. 慢启动 :连接建立时,cwnd 从 1 MSS 开始,每收到一个 ACK 增加 1 MSS,指数增长直到达到 ssthresh

  2. 拥塞避免cwnd 超过 ssthresh 后,每个 RTT 增加 1 MSS,线性增长。

  3. 快速重传 :收到 3 个重复 ACK 时,立即重传丢失的段,将 ssthresh 设为 cwnd/2cwnd 设为 ssthresh + 3

  4. 快速恢复 :快速重传后,cwndssthresh 开始线性增长,而不是回到慢启动。

四次挥手的详细实现

TCP 连接关闭使用四次挥手,允许双方独立关闭发送方向:

主动关闭方

  1. 应用调用 closesocket() → AFD → TDI → lwIP tcp_close
  2. tcp_close 发送 FIN 包,状态变为 FIN_WAIT_1
  3. 收到 ACK 后,状态变为 FIN_WAIT_2
  4. 收到对方的 FIN 后,发送 ACK,状态变为 TIME_WAIT
  5. TIME_WAIT 持续 2*MSL(通常 60 秒),确保最后的 ACK 到达对方
  6. 超时后,状态变为 CLOSED,释放 PCB

被动关闭方

  1. 收到 FIN 后,发送 ACK,状态变为 CLOSE_WAIT
  2. recv 回调返回 0(表示对端关闭)
  3. 应用调用 closesocket() → lwIP tcp_close
  4. 发送 FIN 包,状态变为 LAST_ACK
  5. 收到 ACK 后,状态变为 CLOSED

TIME_WAIT 状态的重要性

  • 确保最后的 ACK 能到达对方(如果丢失,对方会重传 FIN)
  • 等待网络中残留的旧段消失,防止新连接收到旧数据
  • 2*MSL 通常为 60 秒(MSL = 30 秒)

TCP 定时器机制

lwIP 使用多个定时器管理 TCP 连接:

  1. 重传定时器:每个未确认的段都有独立的重传定时器。超时后重传该段,RTO 按指数退避(3s → 6s → 12s → ...)。

  2. TIME_WAIT 定时器TIME_WAIT 状态的连接在 2*MSL 后自动关闭。

  3. 保活定时器:可选机制,定期发送空段检测对端是否存活。默认 2 小时无数据后开始发送保活段。

  4. 延迟 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