3.4 KiB
3.4 KiB
NET Socket FTP 支持改造方案
背景
在 net_socket API 上移植 FTP Server(lftpd),需要支持 PASV 模式数据通道。现有 API 仅支持"一个监听 Socket 独占全部数据 Socket"的单 TCP Server 模型,改造后需支持多监听者 + 动态 Socket 分配。
Socket 需求量
| 用途 | Socket | 说明 |
|---|---|---|
| 控制通道监听(端口 21) | Socket 0 | 多连接 TCP Server |
| 控制通道数据 | Socket 1 | backlog=1,只接受 1 个 FTP 客户端 |
| PASV 数据监听 + 传输 | Socket 2 | 动态分配,用后释放 |
| 空闲 | Socket 3~7 | 备胎 |
改造项(7 项)
A. net_sock_t 新增 standalone_accept 标志
- 位置:
net_types.h:net_sock_t - 用途:区分多连接数据 Socket 和独立监听者(如 PASV)
- 设 1:PASV 监听者
handle_connect_event→ 原地转为ESTABLISHED - 设 1:
handle_disconnect_event→ 释放(CLOSED),不恢复TCP_ACCEPT
B. net_listen() 按 backlog 分配 + 登记 data_socks[]
- 循环从
NET_TCP_SERVER_DATA_SOCK_START到backlog个 - 分配的数据 Socket 登记到
p_sock->data_socks[],设data_sock_count backlog == 0时:不分配数据 Socket,设standalone_accept=1
C. net_bind() 支持 port=0 自动分配
sin_port == 0时从 49152~65535 分配- 静态变量
s_dynamic_port递增
D. handle_connect_event() 支持独立监听
LISTENING + standalone_accept:拷贝远程 IP/Port,状态转ESTABLISHEDLISTENING + !standalone_accept:保持 LISTENING(现有行为)
E. handle_disconnect_event() 支持独立释放
ESTABLISHED + standalone_accept:设state = CLOSED, in_use = 0(释放)ESTABLISHED + !standalone_accept:恢复TCP_ACCEPT(现有行为)- 释放时不清零整个控制块(正在
net_recv中的任务仍需读取 state)
F. net_accept() 支持单连接 + 修复多连接
- 先查
data_socks[](修复现行 bug) - 再查
standalone_accept监听者是否ESTABLISHED→ 返回自身
G. 新增 net_getsockname()
- 返回
local_port+ 本机 IP - 本机 IP 在
net_init()时缓存(s_local_ip),避免 SPI 竞态
消息队列序列化
问题
net_listen()、net_accept() 直接调用 CH395F SPI,从非 netTask(如 FTP 任务)调用会与 net_poll() 冲突。
方案
新增消息类型通过现有消息队列串行化:
| 消息类型 | 用途 | 状态 |
|---|---|---|
NET_MSG_LISTEN |
net_listen() 委托 netTask 执行 |
本次实现 |
NET_MSG_ACCEPT |
net_accept() 委托 netTask 执行 |
本次实现 |
net_bind() 暂不消息化(TCP 部分不碰 SPI,UDP 暂无需跨任务调用)。
向后兼容
- 控制通道
net_listen(sockfd=0, backlog=7)行为不变(仍配满 Socket 1~7) backlog < 7时才释放多余 SocketNET_MSG_LISTEN/NET_MSG_ACCEPT仅新增,不影响现有NET_MSG_SEND/RECV/CLOSE/CONNECTnet_sock_t新增字段standalone_accept默认 0,不影响现有使用
实施顺序
- 消息队列加
NET_MSG_LISTEN、NET_MSG_ACCEPT net_listen()消息化 + 按 backlog 分配 + data_socks 登记net_accept()消息化 + 单连接支持net_bind()port=0 支持net_types.hstandalone_accept 字段handle_connect_event()/handle_disconnect_event()独立监听逻辑net_getsockname()