删除多连接内容,只支持单连接
This commit is contained in:
@@ -29,7 +29,7 @@ int lftpd_inet_listen(int port)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (net_listen(s, 0) >= 0) {
|
if (net_listen(s) >= 0) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,34 +43,6 @@ int lftpd_inet_listen(int port)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lftpd_inet_listen_multi(int port, int backlog)
|
|
||||||
{
|
|
||||||
int s = net_socket(NET_AF_INET, NET_SOCK_STREAM, 0);
|
|
||||||
if (s < 0) {
|
|
||||||
DBG_ERROR("error creating multi listener socket");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct net_sockaddr_in addr;
|
|
||||||
addr.sin_family = NET_AF_INET;
|
|
||||||
addr.sin_port = net_htons((uint16_t)port);
|
|
||||||
addr.sin_addr.s_addr = 0;
|
|
||||||
|
|
||||||
if (net_bind(s, (struct net_sockaddr *)&addr, sizeof(addr)) < 0) {
|
|
||||||
DBG_ERROR("error binding multi listener port %d", port);
|
|
||||||
net_close(s);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (net_listen(s, backlog) < 0) {
|
|
||||||
DBG_ERROR("error listening on multi socket");
|
|
||||||
net_close(s);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lftpd_inet_get_socket_port(int socket)
|
int lftpd_inet_get_socket_port(int socket)
|
||||||
{
|
{
|
||||||
struct net_sockaddr_in addr;
|
struct net_sockaddr_in addr;
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
int lftpd_inet_listen(int port);
|
int lftpd_inet_listen(int port);
|
||||||
int lftpd_inet_listen_multi(int port, int backlog);
|
|
||||||
int lftpd_inet_get_socket_port(int socket);
|
int lftpd_inet_get_socket_port(int socket);
|
||||||
int lftpd_inet_accept(int socket);
|
int lftpd_inet_accept(int socket);
|
||||||
int lftpd_inet_accept_timeout(int socket, int timeout_ms);
|
int lftpd_inet_accept_timeout(int socket, int timeout_ms);
|
||||||
|
|||||||
@@ -30,14 +30,6 @@ extern "C" {
|
|||||||
#define NET_TCP_SERVER_LISTEN_SOCK 0 /* 监听 Socket 索引 */
|
#define NET_TCP_SERVER_LISTEN_SOCK 0 /* 监听 Socket 索引 */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef NET_TCP_SERVER_DATA_SOCK_START
|
|
||||||
#define NET_TCP_SERVER_DATA_SOCK_START 1 /* 数据 Socket 起始索引 */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef NET_TCP_SERVER_MAX_CLIENTS
|
|
||||||
#define NET_TCP_SERVER_MAX_CLIENTS 7 /* 最大客户端数(1~7) */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 缓冲区大小配置
|
* 缓冲区大小配置
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -209,8 +209,7 @@ int net_poll_events(net_pollfd *fds, int nfds, int timeout) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 检查挂起(连接断开) */
|
/* 检查挂起(连接断开) */
|
||||||
if ((NET_SOCK_STATE_TCP_ACCEPT == p_sock->state) ||
|
if (NET_SOCK_STATE_CLOSED == p_sock->state) {
|
||||||
(NET_SOCK_STATE_CLOSED == p_sock->state)) {
|
|
||||||
fds[i].revents |= NET_POLLHUP;
|
fds[i].revents |= NET_POLLHUP;
|
||||||
ready++;
|
ready++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -313,7 +313,7 @@ void net_process_messages(void) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NET_MSG_LISTEN: {
|
case NET_MSG_LISTEN: {
|
||||||
msg.result = net_listen_locked(msg.sockfd, msg.flags);
|
msg.result = net_listen_locked(msg.sockfd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NET_MSG_ACCEPT: {
|
case NET_MSG_ACCEPT: {
|
||||||
@@ -453,11 +453,10 @@ int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen) {
|
|||||||
/*
|
/*
|
||||||
* 函数功能:启动 TCP Server 监听(内部版本,必须在 netTask 上下文调用)
|
* 函数功能:启动 TCP Server 监听(内部版本,必须在 netTask 上下文调用)
|
||||||
* 入口参数:sockfd - Socket 描述符 (0~7) int
|
* 入口参数:sockfd - Socket 描述符 (0~7) int
|
||||||
* backlog - 数据 Socket 数量(0=单连接模式) int
|
|
||||||
* 返回值:0 - 成功,-1 - 失败 int
|
* 返回值:0 - 成功,-1 - 失败 int
|
||||||
* 限定条件:sockfd 已绑定且为 TCP;netTask 上下文
|
* 限定条件:sockfd 已绑定且为 TCP;netTask 上下文
|
||||||
*/
|
*/
|
||||||
int net_listen_locked(int sockfd, int backlog) {
|
int net_listen_locked(int sockfd) {
|
||||||
/* 取监听 Socket 控制块(直接下标访问,sockfd 已在上层 net_listen 校验过范围) */
|
/* 取监听 Socket 控制块(直接下标访问,sockfd 已在上层 net_listen 校验过范围) */
|
||||||
net_sock_t *p_sock = &s_net_socks[sockfd];
|
net_sock_t *p_sock = &s_net_socks[sockfd];
|
||||||
/* CH395F 打开 Socket 的返回状态 */
|
/* CH395F 打开 Socket 的返回状态 */
|
||||||
@@ -476,46 +475,10 @@ int net_listen_locked(int sockfd, int backlog) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 多连接模式(backlog > 0):为数据 Socket 分配并初始化 CH395F 资源 */
|
|
||||||
if (backlog > 0) {
|
|
||||||
/* 数据 Socket 编号范围:[NET_TCP_SERVER_DATA_SOCK_START, max_ds) */
|
|
||||||
int max_ds = NET_TCP_SERVER_DATA_SOCK_START + backlog;
|
|
||||||
/* 越界保护:不超过 Socket 总数 */
|
|
||||||
if (max_ds > NET_MAX_SOCKETS) {
|
|
||||||
max_ds = NET_MAX_SOCKETS;
|
|
||||||
}
|
|
||||||
/* 逐个配置数据 Socket,供后续 accept 时承接新连接 */
|
|
||||||
for (int ds = NET_TCP_SERVER_DATA_SOCK_START; ds < max_ds; ds++) {
|
|
||||||
/* 以 4 块为单位划出该 Socket 的发送/接收缓冲(发送占前 2 块,接收占后 2 块) */
|
|
||||||
uint8_t base = (uint8_t)(ds * 4);
|
|
||||||
ch395f_set_send_buf((uint8_t)ds, base, 2);
|
|
||||||
ch395f_set_recv_buf((uint8_t)ds, base + 2, 2);
|
|
||||||
/* 数据 Socket 监听同一本地端口,协议类型为 TCP */
|
|
||||||
ch395f_set_sour_port((uint8_t)ds, p_sock->local_port);
|
|
||||||
ch395f_set_proto_type((uint8_t)ds, CH395F_PROTO_TYPE_TCP);
|
|
||||||
/* 登记数据 Socket 控制块:标记已用、等待连接态、流类型、绑定硬件 Socket 号 */
|
|
||||||
s_net_socks[ds].in_use = 1;
|
|
||||||
s_net_socks[ds].state = NET_SOCK_STATE_TCP_ACCEPT;
|
|
||||||
s_net_socks[ds].type = NET_SOCK_STREAM;
|
|
||||||
s_net_socks[ds].ch395_sock = (uint8_t)ds;
|
|
||||||
s_net_socks[ds].send_ready = 1;
|
|
||||||
|
|
||||||
/* 记录到监听 Socket 的数据 Socket 列表,供 net_accept_locked 查表 */
|
|
||||||
p_sock->data_socks[p_sock->data_sock_count++] = ds;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 配置监听 Socket 自身的缓冲:
|
* 本实现仅支持单连接:监听 Socket 自身即为数据通道,复用 CH395F 默认收发缓冲
|
||||||
* - 单连接模式(backlog==0,通常用 Socket 0~3):CH395F 默认缓冲已互不重叠,无需重设;
|
* (Socket 0~3 默认缓冲互不重叠),不再为数据 Socket 额外分配。
|
||||||
* - 多连接模式(Socket 4~7 默认无收发缓冲):显式按 4 块划分发送/接收缓冲。
|
|
||||||
*/
|
*/
|
||||||
if (backlog > 0) {
|
|
||||||
uint8_t base = (uint8_t)(sockfd * 4);
|
|
||||||
ch395f_set_send_buf((uint8_t)sockfd, base, 2);
|
|
||||||
ch395f_set_recv_buf((uint8_t)sockfd, base + 2, 2);
|
|
||||||
}
|
|
||||||
/* 监听 Socket 协议类型为 TCP,并绑定本地端口 */
|
|
||||||
ch395f_set_proto_type(sockfd, CH395F_PROTO_TYPE_TCP);
|
ch395f_set_proto_type(sockfd, CH395F_PROTO_TYPE_TCP);
|
||||||
ch395f_set_sour_port(sockfd, p_sock->local_port);
|
ch395f_set_sour_port(sockfd, p_sock->local_port);
|
||||||
|
|
||||||
@@ -533,16 +496,16 @@ int net_listen_locked(int sockfd, int backlog) {
|
|||||||
s_net_errno = NET_ERR_BUSY;
|
s_net_errno = NET_ERR_BUSY;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 下发 TCP LISTEN 命令,进入监听状态 */
|
/* 下发 TCP LISTEN 命令,进入监听状态 */
|
||||||
ch395f_tcp_listen(sockfd);
|
status = ch395f_tcp_listen(sockfd);
|
||||||
|
if (status != CH395F_ERR_SUCCESS) {
|
||||||
|
s_net_errno = NET_ERR_BUSY;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* 监听 Socket 进入 LISTENING 态 */
|
/* 监听 Socket 进入 LISTENING 态 */
|
||||||
p_sock->state = NET_SOCK_STATE_LISTENING;
|
p_sock->state = NET_SOCK_STATE_LISTENING;
|
||||||
/* 单连接模式标记为 standalone_accept:CONNECT 中断直接作用于本 Socket 自身 */
|
/* 单连接:CONNECT 中断直接作用于本 Socket 自身 */
|
||||||
if (backlog == 0) {
|
|
||||||
p_sock->standalone_accept = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 启动监听前清空各 Socket 及全局中断状态寄存器(读即清除),
|
* 启动监听前清空各 Socket 及全局中断状态寄存器(读即清除),
|
||||||
@@ -559,12 +522,11 @@ int net_listen_locked(int sockfd, int backlog) {
|
|||||||
/*
|
/*
|
||||||
* 函数功能:启动 TCP Server 监听(线程安全版本,通过消息队列委托给 netTask)
|
* 函数功能:启动 TCP Server 监听(线程安全版本,通过消息队列委托给 netTask)
|
||||||
* 入口参数:sockfd - Socket 描述符 int
|
* 入口参数:sockfd - Socket 描述符 int
|
||||||
* backlog - 数据 Socket 数量 int
|
|
||||||
* 返回值:0 - 成功,-1 - 失败 int
|
* 返回值:0 - 成功,-1 - 失败 int
|
||||||
* 限定条件:net_init() + MX_FREERTOS_Init() 已执行;必须在任务上下文中调用
|
* 限定条件:net_init() + MX_FREERTOS_Init() 已执行;必须在任务上下文中调用
|
||||||
* 函数说明:通过消息队列委托给 netTask,确保 SPI 串行化
|
* 函数说明:通过消息队列委托给 netTask,确保 SPI 串行化
|
||||||
*/
|
*/
|
||||||
int net_listen(int sockfd, int backlog) {
|
int net_listen(int sockfd) {
|
||||||
net_msg_t msg;
|
net_msg_t msg;
|
||||||
|
|
||||||
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) {
|
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS) {
|
||||||
@@ -579,7 +541,6 @@ int net_listen(int sockfd, int backlog) {
|
|||||||
|
|
||||||
msg.type = NET_MSG_LISTEN;
|
msg.type = NET_MSG_LISTEN;
|
||||||
msg.sockfd = sockfd;
|
msg.sockfd = sockfd;
|
||||||
msg.flags = backlog;
|
|
||||||
msg.caller = xTaskGetCurrentTaskHandle();
|
msg.caller = xTaskGetCurrentTaskHandle();
|
||||||
msg.result = -1;
|
msg.result = -1;
|
||||||
|
|
||||||
@@ -607,57 +568,37 @@ int net_listen(int sockfd, int backlog) {
|
|||||||
* addrlen - 输入输出:地址结构体长度 int *(可为 NULL)
|
* addrlen - 输入输出:地址结构体长度 int *(可为 NULL)
|
||||||
* 返回值:新连接的 Socket 描述符,失败返回 -1 int
|
* 返回值:新连接的 Socket 描述符,失败返回 -1 int
|
||||||
* 限定条件:Socket 处于 LISTENING 状态
|
* 限定条件:Socket 处于 LISTENING 状态
|
||||||
* 函数说明:先查 data_socks[] 多连接数据 Socket,再查 standalone_accept 单连接 Socket
|
* 函数说明:单连接:监听 Socket 自身在 CONNECT 后已转为 ESTABLISHED
|
||||||
*/
|
*/
|
||||||
static int net_accept_locked(int sockfd, struct net_sockaddr *addr, int *addrlen) {
|
static int net_accept_locked(int sockfd, struct net_sockaddr *addr, int *addrlen) {
|
||||||
net_sock_t *p_listen_sock;
|
net_sock_t *p_listen_sock;
|
||||||
int i;
|
|
||||||
|
|
||||||
p_listen_sock = &s_net_socks[sockfd];
|
p_listen_sock = &s_net_socks[sockfd];
|
||||||
if (!p_listen_sock->in_use) {
|
if (!p_listen_sock->in_use) {
|
||||||
s_net_errno = NET_ERR_INVAL;
|
s_net_errno = NET_ERR_INVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (p_listen_sock->state != NET_SOCK_STATE_LISTENING &&
|
|
||||||
!(p_listen_sock->standalone_accept && p_listen_sock->state == NET_SOCK_STATE_ESTABLISHED)) {
|
|
||||||
s_net_errno = NET_ERR_INVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
net_poll();
|
net_poll();
|
||||||
|
|
||||||
/* 多连接模式:查 data_socks */
|
/* 单连接:本 Socket 自身在 CONNECT 后已转为 ESTABLISHED,
|
||||||
for (i = 0; i < p_listen_sock->data_sock_count; i++) {
|
* 只有处于 ESTABLISHED 才表示有可接受的连接;否则尚无连接 */
|
||||||
int data_sock = p_listen_sock->data_socks[i];
|
if (p_listen_sock->state != NET_SOCK_STATE_ESTABLISHED) {
|
||||||
net_sock_t *p_data_cb = &s_net_socks[data_sock];
|
s_net_errno = NET_ERR_WOULDBLOCK;
|
||||||
|
return -1;
|
||||||
if (p_data_cb->state == NET_SOCK_STATE_ESTABLISHED) {
|
|
||||||
if (NULL != addr &&NULL != addrlen) {
|
|
||||||
struct net_sockaddr_in *p_addr_in = (struct net_sockaddr_in *)addr;
|
|
||||||
p_addr_in->sin_family = NET_AF_INET;
|
|
||||||
p_addr_in->sin_port = net_htons(p_data_cb->remote_port);
|
|
||||||
p_addr_in->sin_addr.s_addr = p_data_cb->remote_ip;
|
|
||||||
*addrlen = sizeof(struct net_sockaddr_in);
|
|
||||||
}
|
|
||||||
return data_sock;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 单连接模式(PASV):查 standalone 监听者是否已 ESTABLISHED */
|
/* 填充对端地址(若调用方需要) */
|
||||||
if (p_listen_sock->standalone_accept &&
|
if (NULL != addr && NULL != addrlen) {
|
||||||
p_listen_sock->state == NET_SOCK_STATE_ESTABLISHED) {
|
struct net_sockaddr_in *p_addr_in = (struct net_sockaddr_in *)addr;
|
||||||
if (NULL != addr &&NULL != addrlen) {
|
p_addr_in->sin_family = NET_AF_INET;
|
||||||
struct net_sockaddr_in *p_addr_in = (struct net_sockaddr_in *)addr;
|
p_addr_in->sin_port = net_htons(p_listen_sock->remote_port);
|
||||||
p_addr_in->sin_family = NET_AF_INET;
|
p_addr_in->sin_addr.s_addr = p_listen_sock->remote_ip;
|
||||||
p_addr_in->sin_port = net_htons(p_listen_sock->remote_port);
|
*addrlen = sizeof(struct net_sockaddr_in);
|
||||||
p_addr_in->sin_addr.s_addr = p_listen_sock->remote_ip;
|
|
||||||
*addrlen = sizeof(struct net_sockaddr_in);
|
|
||||||
}
|
|
||||||
return sockfd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s_net_errno = NET_ERR_WOULDBLOCK;
|
/* 单连接:返回的就是监听 Socket 自身(已转为数据通道) */
|
||||||
return -1;
|
return sockfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -897,9 +838,6 @@ static int net_recv_locked(net_sock_t *p_sock, void *buf, int len, int flags) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_sock->state == NET_SOCK_STATE_TCP_ACCEPT) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (p_sock->state == NET_SOCK_STATE_CLOSED) {
|
if (p_sock->state == NET_SOCK_STATE_CLOSED) {
|
||||||
/* 断开前尝试排空 CH395F 接收缓冲区(Trap 13:FIN 可能比数据先到) */
|
/* 断开前尝试排空 CH395F 接收缓冲区(Trap 13:FIN 可能比数据先到) */
|
||||||
uint16_t rem = ch395f_get_recv_len(sockfd);
|
uint16_t rem = ch395f_get_recv_len(sockfd);
|
||||||
@@ -1485,44 +1423,14 @@ static int alloc_socket(void) {
|
|||||||
* 出口参数:无
|
* 出口参数:无
|
||||||
* 返回值:无
|
* 返回值:无
|
||||||
* 限定条件:net_poll() 检测到 CONNECT 中断后调用;netTask 上下文
|
* 限定条件:net_poll() 检测到 CONNECT 中断后调用;netTask 上下文
|
||||||
* 函数说明:1. 独立监听模式(standalone_accept):自身转 ESTABLISHED 并读取对端地址
|
* 函数说明:1. 单连接:自身转 ESTABLISHED 并读取对端地址
|
||||||
* 2. 多连接监听模式:Socket 0 保持 LISTENING,由数据 Socket 承接连接
|
* 2. TCP Client(CONNECTING):连接成功,读取对端地址并置 ESTABLISHED
|
||||||
* 3. 多连接模式自动打开的数据 Socket:首次 CONNECT 时初始化并置 ESTABLISHED
|
* 3. 连接成功后使能 KeepAlive 并触发 NET_EVENT_CONNECTED 回调
|
||||||
* 4. TCP Client(CONNECTING):连接成功,读取对端地址并置 ESTABLISHED
|
|
||||||
* 5. 数据 Socket(TCP_ACCEPT):被分配连接,置 ESTABLISHED
|
|
||||||
* 6. 连接成功后使能 KeepAlive 并触发 NET_EVENT_CONNECTED 回调
|
|
||||||
*/
|
*/
|
||||||
static void handle_connect_event(net_sock_t *p_sock) {
|
static void handle_connect_event(net_sock_t *p_sock) {
|
||||||
if (p_sock->state == NET_SOCK_STATE_LISTENING) {
|
if (p_sock->state == NET_SOCK_STATE_LISTENING) {
|
||||||
if (p_sock->standalone_accept) {
|
/* 单连接:收到 CONNECT 中断 = 自身有连接到达,转为 ESTABLISHED */
|
||||||
/* 独立监听模式(PASV):收到 CONNECT 中断 = 自身有连接到达,转为 ESTABLISHED */
|
DBG_INFO("sock%d standalone accept", p_sock->ch395_sock);
|
||||||
DBG_INFO("sock%d standalone accept", p_sock->ch395_sock);
|
|
||||||
uint8_t remote[6];
|
|
||||||
ch395f_get_remot_ipp(p_sock->ch395_sock, remote);
|
|
||||||
memcpy(p_sock->remote_ip_arr, remote, 4);
|
|
||||||
p_sock->remote_ip = ((uint32_t)remote[0]) |
|
|
||||||
((uint32_t)remote[1] << 8) |
|
|
||||||
((uint32_t)remote[2] << 16) |
|
|
||||||
((uint32_t)remote[3] << 24);
|
|
||||||
p_sock->remote_port = (uint16_t)(remote[4] | (remote[5] << 8));
|
|
||||||
p_sock->state = NET_SOCK_STATE_ESTABLISHED;
|
|
||||||
p_sock->send_ready = 1;
|
|
||||||
|
|
||||||
/* 清除残留的 TIMEOUT 中断标志 */
|
|
||||||
(void)ch395f_get_sock_int_status(p_sock->ch395_sock);
|
|
||||||
|
|
||||||
fire_event(p_sock, NET_EVENT_CONNECTED);
|
|
||||||
} else {
|
|
||||||
/* 多连接模式:监听 Socket 收到 CONNECT 中断 = 有新连接被分配到数据 Socket
|
|
||||||
* Socket 0 自身保持 LISTENING,不需要改变状态 */
|
|
||||||
fire_event(p_sock, NET_EVENT_CONNECTED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!p_sock->in_use) {
|
|
||||||
/* CH395F 自动打开的数<E79A84>?Socket(多连接模式),首次收到 CONNECT 中断 */
|
|
||||||
int sock_idx = (int)(p_sock - s_net_socks);
|
|
||||||
p_sock->ch395_sock = (uint8_t)sock_idx;
|
|
||||||
DBG_INFO("sock%d AUTO-OPENED, CONNECTED", p_sock->ch395_sock);
|
|
||||||
uint8_t remote[6];
|
uint8_t remote[6];
|
||||||
ch395f_get_remot_ipp(p_sock->ch395_sock, remote);
|
ch395f_get_remot_ipp(p_sock->ch395_sock, remote);
|
||||||
memcpy(p_sock->remote_ip_arr, remote, 4);
|
memcpy(p_sock->remote_ip_arr, remote, 4);
|
||||||
@@ -1531,15 +1439,14 @@ static void handle_connect_event(net_sock_t *p_sock) {
|
|||||||
((uint32_t)remote[2] << 16) |
|
((uint32_t)remote[2] << 16) |
|
||||||
((uint32_t)remote[3] << 24);
|
((uint32_t)remote[3] << 24);
|
||||||
p_sock->remote_port = (uint16_t)(remote[4] | (remote[5] << 8));
|
p_sock->remote_port = (uint16_t)(remote[4] | (remote[5] << 8));
|
||||||
p_sock->in_use = 1;
|
|
||||||
p_sock->state = NET_SOCK_STATE_ESTABLISHED;
|
p_sock->state = NET_SOCK_STATE_ESTABLISHED;
|
||||||
p_sock->send_ready = 1;
|
p_sock->send_ready = 1;
|
||||||
|
|
||||||
ch395f_set_keepalive_enable(p_sock->ch395_sock, 1);
|
/* 清除残留的 TIMEOUT 中断标志 */
|
||||||
|
(void)ch395f_get_sock_int_status(p_sock->ch395_sock);
|
||||||
|
|
||||||
fire_event(p_sock, NET_EVENT_CONNECTED);
|
fire_event(p_sock, NET_EVENT_CONNECTED);
|
||||||
}
|
} else if (p_sock->state == NET_SOCK_STATE_CONNECTING) {
|
||||||
else if (p_sock->state == NET_SOCK_STATE_CONNECTING) {
|
|
||||||
/* TCP Client 连接成功 */
|
/* TCP Client 连接成功 */
|
||||||
uint8_t remote[6];
|
uint8_t remote[6];
|
||||||
ch395f_get_remot_ipp(p_sock->ch395_sock, remote);
|
ch395f_get_remot_ipp(p_sock->ch395_sock, remote);
|
||||||
@@ -1553,24 +1460,6 @@ static void handle_connect_event(net_sock_t *p_sock) {
|
|||||||
|
|
||||||
ch395f_set_keepalive_enable(p_sock->ch395_sock, 1);
|
ch395f_set_keepalive_enable(p_sock->ch395_sock, 1);
|
||||||
|
|
||||||
fire_event(p_sock, NET_EVENT_CONNECTED);
|
|
||||||
}
|
|
||||||
else if (p_sock->state == NET_SOCK_STATE_TCP_ACCEPT) {
|
|
||||||
/* 数据 Socket 被分配了连接 */
|
|
||||||
DBG_INFO("data sock%d TCP_ACCEPT -> CONNECTED", p_sock->ch395_sock);
|
|
||||||
uint8_t remote[6];
|
|
||||||
ch395f_get_remot_ipp(p_sock->ch395_sock, remote);
|
|
||||||
memcpy(p_sock->remote_ip_arr, remote, 4);
|
|
||||||
p_sock->remote_ip = ((uint32_t)remote[0]) |
|
|
||||||
((uint32_t)remote[1] << 8) |
|
|
||||||
((uint32_t)remote[2] << 16) |
|
|
||||||
((uint32_t)remote[3] << 24);
|
|
||||||
p_sock->remote_port = (uint16_t)(remote[4] | (remote[5] << 8));
|
|
||||||
p_sock->state = NET_SOCK_STATE_ESTABLISHED;
|
|
||||||
p_sock->send_ready = 1;
|
|
||||||
|
|
||||||
ch395f_set_keepalive_enable(p_sock->ch395_sock, 1);
|
|
||||||
|
|
||||||
fire_event(p_sock, NET_EVENT_CONNECTED);
|
fire_event(p_sock, NET_EVENT_CONNECTED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1582,33 +1471,18 @@ static void handle_connect_event(net_sock_t *p_sock) {
|
|||||||
* 返回值:无
|
* 返回值:无
|
||||||
* 限定条件:net_poll() 检测到 DISCONNECT 中断后调用;netTask 上下文
|
* 限定条件:net_poll() 检测到 DISCONNECT 中断后调用;netTask 上下文
|
||||||
* 函数说明:1. CH395F 在 DISCONNECT 后自动关闭 Socket(FUN_PARA 默认),需重新 OPEN + LISTEN
|
* 函数说明:1. CH395F 在 DISCONNECT 后自动关闭 Socket(FUN_PARA 默认),需重新 OPEN + LISTEN
|
||||||
* 2. 独立监听模式:置 CLOSED,交由 net_recv_locked 排空剩余数据后再关
|
* 2. 单连接:置 CLOSED,交由 net_recv_locked 排空剩余数据后再关
|
||||||
* 3. 多连接数据 Socket:回到 TCP_ACCEPT 状态等待新连接
|
* 3. 触发 NET_EVENT_DISCONNECTED 回调
|
||||||
* 4. 触发 NET_EVENT_DISCONNECTED 回调
|
|
||||||
*/
|
*/
|
||||||
static void handle_disconnect_event(net_sock_t *p_sock) {
|
static void handle_disconnect_event(net_sock_t *p_sock) {
|
||||||
if (p_sock->state == NET_SOCK_STATE_LISTENING) {
|
if (p_sock->state == NET_SOCK_STATE_LISTENING) {
|
||||||
DBG_ERROR("WARNING: listen sock%d got disconnect", p_sock->ch395_sock);
|
DBG_ERROR("WARNING: listen sock%d got disconnect", p_sock->ch395_sock);
|
||||||
}
|
} else if (p_sock->state == NET_SOCK_STATE_ESTABLISHED) {
|
||||||
else if (p_sock->state == NET_SOCK_STATE_ESTABLISHED) {
|
/* 单连接:先不关 CH395F Socket,
|
||||||
if (p_sock->standalone_accept) {
|
* 留给 net_recv_locked 把剩余数据读出来再关,置 CLOSED 等待应用重新监听 */
|
||||||
/* 独立监听模式:先不关 CH395F Socket,
|
DBG_INFO("sock%d DISCONNECTED, releasing", p_sock->ch395_sock);
|
||||||
* 留给 net_recv_locked 把剩余数据读出来再关 */
|
p_sock->state = NET_SOCK_STATE_CLOSED;
|
||||||
DBG_INFO("sock%d DISCONNECTED, releasing", p_sock->ch395_sock);
|
fire_event(p_sock, NET_EVENT_DISCONNECTED);
|
||||||
p_sock->state = NET_SOCK_STATE_CLOSED;
|
|
||||||
fire_event(p_sock, NET_EVENT_DISCONNECTED);
|
|
||||||
} else {
|
|
||||||
DBG_INFO("sock%d DISCONNECTED, back to idle", p_sock->ch395_sock);
|
|
||||||
memset(p_sock->remote_ip_arr, 0, 4);
|
|
||||||
p_sock->remote_port = 0;
|
|
||||||
p_sock->send_ready = 1;
|
|
||||||
p_sock->state = NET_SOCK_STATE_TCP_ACCEPT;
|
|
||||||
fire_event(p_sock, NET_EVENT_DISCONNECTED);
|
|
||||||
}
|
|
||||||
} else if (p_sock->state == NET_SOCK_STATE_TCP_ACCEPT) {
|
|
||||||
memset(p_sock->remote_ip_arr, 0, 4);
|
|
||||||
p_sock->remote_port = 0;
|
|
||||||
p_sock->send_ready = 1;
|
|
||||||
} else if (p_sock->state != NET_SOCK_STATE_CLOSED &&
|
} else if (p_sock->state != NET_SOCK_STATE_CLOSED &&
|
||||||
p_sock->state != NET_SOCK_STATE_BOUND &&
|
p_sock->state != NET_SOCK_STATE_BOUND &&
|
||||||
p_sock->state != NET_SOCK_STATE_CREATED) {
|
p_sock->state != NET_SOCK_STATE_CREATED) {
|
||||||
@@ -1653,7 +1527,7 @@ static void handle_send_event(net_sock_t *p_sock) {
|
|||||||
* 返回值:无
|
* 返回值:无
|
||||||
* 限定条件:net_poll() 检测到 SOCK_TIMEOUT 中断后调用;netTask 上下文
|
* 限定条件:net_poll() 检测到 SOCK_TIMEOUT 中断后调用;netTask 上下文
|
||||||
* 函数说明:1. TCP Client(CONNECTING):连接超时,回到 CREATED 状态
|
* 函数说明:1. TCP Client(CONNECTING):连接超时,回到 CREATED 状态
|
||||||
* 2. 已建立连接:回到 CLOSED(独立模式)或 TCP_ACCEPT(多连接模式)
|
* 2. 已建立连接:回到 CLOSED(单连接)
|
||||||
* 3. 监听态:异常超时,记录错误日志
|
* 3. 监听态:异常超时,记录错误日志
|
||||||
* 4. 触发 NET_EVENT_TIMEOUT 回调
|
* 4. 触发 NET_EVENT_TIMEOUT 回调
|
||||||
*/
|
*/
|
||||||
@@ -1662,12 +1536,10 @@ static void handle_timeout_event(net_sock_t *p_sock) {
|
|||||||
/* TCP Client 连接超时 */
|
/* TCP Client 连接超时 */
|
||||||
DBG_ERROR("sock%d CONNECT TIMEOUT", p_sock->ch395_sock);
|
DBG_ERROR("sock%d CONNECT TIMEOUT", p_sock->ch395_sock);
|
||||||
p_sock->state = NET_SOCK_STATE_CREATED;
|
p_sock->state = NET_SOCK_STATE_CREATED;
|
||||||
}
|
} else if (p_sock->state == NET_SOCK_STATE_ESTABLISHED) {
|
||||||
else if (p_sock->state == NET_SOCK_STATE_ESTABLISHED) {
|
|
||||||
DBG_ERROR("sock%d TIMEOUT", p_sock->ch395_sock);
|
DBG_ERROR("sock%d TIMEOUT", p_sock->ch395_sock);
|
||||||
p_sock->state = p_sock->standalone_accept ? NET_SOCK_STATE_CLOSED : NET_SOCK_STATE_TCP_ACCEPT;
|
p_sock->state = NET_SOCK_STATE_CLOSED;
|
||||||
}
|
} else if (p_sock->state == NET_SOCK_STATE_LISTENING) {
|
||||||
else if (p_sock->state == NET_SOCK_STATE_LISTENING) {
|
|
||||||
/* 监听超时(异常情况) */
|
/* 监听超时(异常情况) */
|
||||||
DBG_ERROR("sock%d LISTEN TIMEOUT", p_sock->ch395_sock);
|
DBG_ERROR("sock%d LISTEN TIMEOUT", p_sock->ch395_sock);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,12 +97,11 @@ int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen);
|
|||||||
/*
|
/*
|
||||||
* 函数功能:TCP Server 监听
|
* 函数功能:TCP Server 监听
|
||||||
* 入口参数:sockfd - socket 描述符
|
* 入口参数:sockfd - socket 描述符
|
||||||
* backlog - 最大等待连接数(多连接模式下为数据 Socket 数量)
|
|
||||||
* 返回值:0 成功,-1 失败
|
* 返回值:0 成功,-1 失败
|
||||||
* 限定条件:socket 已绑定
|
* 限定条件:socket 已绑定
|
||||||
* 函数说明:内部调用 ch395f_tcp_listen,多连接模式自动配置数据 Socket
|
* 函数说明:内部调用 ch395f_tcp_listen,监听 Socket 自身即为数据通道
|
||||||
*/
|
*/
|
||||||
int net_listen(int sockfd, int backlog);
|
int net_listen(int sockfd);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 函数功能:TCP Server 接受连接
|
* 函数功能:TCP Server 接受连接
|
||||||
@@ -333,11 +332,10 @@ int net_close_sock(net_sock_t *p_sock);
|
|||||||
/*
|
/*
|
||||||
* 函数功能:启动 TCP Server 监听(内部版本,直接操作,不经过消息队列)
|
* 函数功能:启动 TCP Server 监听(内部版本,直接操作,不经过消息队列)
|
||||||
* 入口参数:sockfd - Socket 描述符
|
* 入口参数:sockfd - Socket 描述符
|
||||||
* backlog - 数据 Socket 数量(0=单连接模式)
|
|
||||||
* 返回值:0 成功,-1 失败
|
* 返回值:0 成功,-1 失败
|
||||||
* 限定条件:必须在 netTask 上下文中调用
|
* 限定条件:必须在 netTask 上下文中调用
|
||||||
*/
|
*/
|
||||||
int net_listen_locked(int sockfd, int backlog);
|
int net_listen_locked(int sockfd);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,7 +114,6 @@ typedef enum {
|
|||||||
NET_SOCK_STATE_CONNECTING, /* TCP Client 连接中 */
|
NET_SOCK_STATE_CONNECTING, /* TCP Client 连接中 */
|
||||||
NET_SOCK_STATE_ESTABLISHED, /* TCP 已连接 */
|
NET_SOCK_STATE_ESTABLISHED, /* TCP 已连接 */
|
||||||
NET_SOCK_STATE_UDP_OPEN, /* UDP 已打开 */
|
NET_SOCK_STATE_UDP_OPEN, /* UDP 已打开 */
|
||||||
NET_SOCK_STATE_TCP_ACCEPT, /* TCP Server 数据 Socket,等待分配连接 */
|
|
||||||
NET_SOCK_STATE_TCP_CLIENT_RECONNECTING, /* TCP Client 重连中 */
|
NET_SOCK_STATE_TCP_CLIENT_RECONNECTING, /* TCP Client 重连中 */
|
||||||
} net_sock_state_t;
|
} net_sock_state_t;
|
||||||
|
|
||||||
@@ -156,16 +155,9 @@ typedef struct {
|
|||||||
net_event_cb_t event_cb;
|
net_event_cb_t event_cb;
|
||||||
void *event_arg;
|
void *event_arg;
|
||||||
|
|
||||||
/* TCP Server 多连接模式:监听 Socket 的数据 Socket 列表 */
|
|
||||||
int data_socks[NET_TCP_SERVER_MAX_CLIENTS];
|
|
||||||
int data_sock_count;
|
|
||||||
|
|
||||||
/* 发送就绪标志 */
|
/* 发送就绪标志 */
|
||||||
uint8_t send_ready;
|
uint8_t send_ready;
|
||||||
|
|
||||||
/* 独立监听标志(PASV 用):该 Socket 为独立监听者,收到 CONNECT 后转为 ESTABLISHED,断开后释放 */
|
|
||||||
uint8_t standalone_accept;
|
|
||||||
|
|
||||||
/* 统计信息 */
|
/* 统计信息 */
|
||||||
uint32_t recv_bytes; /* 累计接收字节数 */
|
uint32_t recv_bytes; /* 累计接收字节数 */
|
||||||
uint32_t send_bytes; /* 累计发送字节数 */
|
uint32_t send_bytes; /* 累计发送字节数 */
|
||||||
|
|||||||
@@ -1,71 +1,71 @@
|
|||||||
*** Using Compiler 'V5.06 update 7 (build 960)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
|
*** Using Compiler 'V5.06 update 7 (build 960)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
|
||||||
Rebuild target 'STM32F407-Demo'
|
Rebuild target 'STM32F407-Demo'
|
||||||
assembling startup_stm32f407xx.s...
|
assembling startup_stm32f407xx.s...
|
||||||
compiling crc.c...
|
|
||||||
compiling ringbuf.c...
|
compiling ringbuf.c...
|
||||||
|
compiling crc.c...
|
||||||
compiling stm32f4xx_hal_flash_ramfunc.c...
|
compiling stm32f4xx_hal_flash_ramfunc.c...
|
||||||
compiling stm32f4xx_hal_gpio.c...
|
compiling stm32f4xx_hal_gpio.c...
|
||||||
compiling stm32f4xx_hal_flash_ex.c...
|
|
||||||
compiling i2c.c...
|
compiling i2c.c...
|
||||||
compiling usart.c...
|
|
||||||
compiling gpio.c...
|
|
||||||
compiling app_main.c...
|
|
||||||
compiling stm32f4xx_hal_timebase_tim.c...
|
|
||||||
compiling spi.c...
|
|
||||||
compiling stm32f4xx_it.c...
|
|
||||||
compiling stm32f4xx_hal_msp.c...
|
|
||||||
compiling dma.c...
|
|
||||||
compiling stm32f4xx_hal_flash.c...
|
|
||||||
compiling sys_clock.c...
|
|
||||||
compiling stm32f4xx_hal_dma_ex.c...
|
compiling stm32f4xx_hal_dma_ex.c...
|
||||||
compiling stm32f4xx_hal_rcc_ex.c...
|
|
||||||
compiling stm32f4xx_hal_dma.c...
|
compiling stm32f4xx_hal_dma.c...
|
||||||
|
compiling stm32f4xx_hal_timebase_tim.c...
|
||||||
|
compiling stm32f4xx_hal_msp.c...
|
||||||
|
compiling stm32f4xx_it.c...
|
||||||
|
compiling app_main.c...
|
||||||
|
compiling spi.c...
|
||||||
|
compiling usart.c...
|
||||||
|
compiling dma.c...
|
||||||
|
compiling sys_clock.c...
|
||||||
|
compiling stm32f4xx_hal_rcc_ex.c...
|
||||||
|
compiling stm32f4xx_hal_flash.c...
|
||||||
|
compiling gpio.c...
|
||||||
|
compiling stm32f4xx_hal_flash_ex.c...
|
||||||
compiling rs485_task.c...
|
compiling rs485_task.c...
|
||||||
compiling adc_task.c...
|
compiling adc_task.c...
|
||||||
compiling stm32f4xx_hal_tim_ex.c...
|
|
||||||
compiling net_task.c...
|
|
||||||
compiling stm32f4xx_hal_rcc.c...
|
compiling stm32f4xx_hal_rcc.c...
|
||||||
compiling main.c...
|
compiling main.c...
|
||||||
|
compiling stm32f4xx_hal_tim_ex.c...
|
||||||
compiling freertos.c...
|
compiling freertos.c...
|
||||||
|
compiling net_task.c...
|
||||||
compiling lftpd_string.c...
|
compiling lftpd_string.c...
|
||||||
compiling stm32f4xx_hal_tim.c...
|
|
||||||
compiling croutine.c...
|
compiling croutine.c...
|
||||||
|
compiling stm32f4xx_hal_tim.c...
|
||||||
compiling event_groups.c...
|
compiling event_groups.c...
|
||||||
compiling list.c...
|
compiling list.c...
|
||||||
compiling stm32f4xx_hal_pwr.c...
|
|
||||||
compiling stream_buffer.c...
|
compiling stream_buffer.c...
|
||||||
compiling queue.c...
|
compiling queue.c...
|
||||||
compiling tasks.c...
|
|
||||||
compiling stm32f4xx_hal_pwr_ex.c...
|
|
||||||
compiling timers.c...
|
compiling timers.c...
|
||||||
|
compiling tasks.c...
|
||||||
compiling heap_4.c...
|
compiling heap_4.c...
|
||||||
compiling journal.c...
|
|
||||||
compiling port.c...
|
compiling port.c...
|
||||||
|
compiling journal.c...
|
||||||
|
compiling stm32f4xx_hal_pwr.c...
|
||||||
compiling map.c...
|
compiling map.c...
|
||||||
compiling stm32f4xx_hal_cortex.c...
|
|
||||||
compiling ff.c...
|
|
||||||
compiling stm32f4xx_hal_i2c_ex.c...
|
|
||||||
compiling stm32f4xx_hal.c...
|
|
||||||
compiling stm32f4xx_hal_exti.c...
|
|
||||||
compiling system_stm32f4xx.c...
|
compiling system_stm32f4xx.c...
|
||||||
|
compiling stm32f4xx_hal_i2c_ex.c...
|
||||||
|
compiling stm32f4xx_hal_cortex.c...
|
||||||
|
compiling stm32f4xx_hal_pwr_ex.c...
|
||||||
|
compiling stm32f4xx_hal_exti.c...
|
||||||
|
compiling lftpd_io.c...
|
||||||
|
compiling stm32f4xx_hal.c...
|
||||||
|
compiling ff.c...
|
||||||
|
compiling sd2506.c...
|
||||||
compiling rs485.c...
|
compiling rs485.c...
|
||||||
compiling stm32f4xx_hal_spi.c...
|
compiling stm32f4xx_hal_spi.c...
|
||||||
compiling sd2506.c...
|
|
||||||
compiling ch395f.c...
|
compiling ch395f.c...
|
||||||
compiling nand_ftl.c...
|
|
||||||
compiling lftpd_io.c...
|
|
||||||
compiling gd5f2gq5ue.c...
|
|
||||||
compiling tpafe5160.c...
|
|
||||||
compiling lftpd_inet.c...
|
|
||||||
compiling net_select.c...
|
|
||||||
compiling stm32f4xx_hal_uart.c...
|
|
||||||
compiling lftpd.c...
|
|
||||||
compiling cmsis_os2.c...
|
compiling cmsis_os2.c...
|
||||||
compiling stm32f4xx_hal_i2c.c...
|
compiling stm32f4xx_hal_i2c.c...
|
||||||
|
compiling tpafe5160.c...
|
||||||
|
compiling gd5f2gq5ue.c...
|
||||||
|
compiling net_select.c...
|
||||||
|
compiling lftpd_inet.c...
|
||||||
|
compiling nand_ftl.c...
|
||||||
|
compiling stm32f4xx_hal_uart.c...
|
||||||
|
compiling lftpd.c...
|
||||||
compiling net_socket.c...
|
compiling net_socket.c...
|
||||||
compiling ch395f_test_task.c...
|
compiling ch395f_test_task.c...
|
||||||
linking...
|
linking...
|
||||||
Program Size: Code=49060 RO-data=1760 RW-data=228 ZI-data=69764
|
Program Size: Code=49060 RO-data=1760 RW-data=228 ZI-data=69508
|
||||||
FromELF: creating hex file...
|
FromELF: creating hex file...
|
||||||
".\STM32F407-Demo\STM32F407-Demo.axf" - 0 Error(s), 0 Warning(s).
|
".\STM32F407-Demo\STM32F407-Demo.axf" - 0 Error(s), 0 Warning(s).
|
||||||
Build Time Elapsed: 00:00:14
|
Build Time Elapsed: 00:00:15
|
||||||
|
|||||||
@@ -27,7 +27,6 @@
|
|||||||
|------|------|
|
|------|------|
|
||||||
| TCP Client | 主动连接远程服务器 |
|
| TCP Client | 主动连接远程服务器 |
|
||||||
| TCP Server(单连接) | 支持 1 个客户端连接 |
|
| TCP Server(单连接) | 支持 1 个客户端连接 |
|
||||||
| TCP Server(多连接) | 支持最多 7 个并发连接 |
|
|
||||||
| UDP Client | 发送 UDP 数据报 |
|
| UDP Client | 发送 UDP 数据报 |
|
||||||
| UDP Server | 接收 UDP 数据报 |
|
| UDP Server | 接收 UDP 数据报 |
|
||||||
| select/poll | I/O 多路复用 |
|
| select/poll | I/O 多路复用 |
|
||||||
@@ -38,7 +37,6 @@
|
|||||||
| 特性 | Linux Socket | 本实现 |
|
| 特性 | Linux Socket | 本实现 |
|
||||||
|------|--------------|--------|
|
|------|--------------|--------|
|
||||||
| Socket 数量 | 无限制 | 最多 8 个 |
|
| Socket 数量 | 无限制 | 最多 8 个 |
|
||||||
| TCP Server 多连接 | 无限制 | 最多 7 个并发连接 |
|
|
||||||
| 非阻塞模式 | 支持 | 通过 `net_poll()` 实现 |
|
| 非阻塞模式 | 支持 | 通过 `net_poll()` 实现 |
|
||||||
| 错误码 | errno | `net_get_errno()` |
|
| 错误码 | errno | `net_get_errno()` |
|
||||||
| 头文件 | `<sys/socket.h>` | `"net_socket.h"` |
|
| 头文件 | `<sys/socket.h>` | `"net_socket.h"` |
|
||||||
@@ -82,19 +80,6 @@
|
|||||||
| `net_select.h` | select/poll API 头文件 |
|
| `net_select.h` | select/poll API 头文件 |
|
||||||
| `net_select.c` | select/poll 实现 |
|
| `net_select.c` | select/poll 实现 |
|
||||||
|
|
||||||
### 2.3 底层驱动改进(v2.1)
|
|
||||||
|
|
||||||
ch395f.c/h 已完成以下优化:
|
|
||||||
|
|
||||||
| 改进项 | 说明 |
|
|
||||||
|--------|------|
|
|
||||||
| 命令执行等待 | `open/close/listen/connect/disconnect` 所有长命令内部调用 `poll_cmd_status` 等待完成(20ms × 200 次 = 4s 超时) |
|
|
||||||
| 全局中断 | 使用 `GET_GLOB_INT_STATUS_ALL`(2字节版,命令码 0x19)支持全部 8 个 Socket |
|
|
||||||
| 错误码 | 与芯片手册完全对齐的 17 个状态码定义 |
|
|
||||||
| FUN_PARA 标志 | `CH395F_FUN_PARA_TCP_SERVER` / `SOCKET_CLOSE` / `DISABLE_SEND_OK` 宏 |
|
|
||||||
| 新增函数 | `ch395f_set_arp()` / `ch395f_set_ttl()` / `ch395f_get_unreach_info()` / `ch395f_poll_cmd_status()` |
|
|
||||||
| KeepAlive | 参数单位为毫秒(非秒),必须为 500 的倍数 |
|
|
||||||
|
|
||||||
### 2.4 Socket 状态机
|
### 2.4 Socket 状态机
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -116,12 +101,11 @@ ch395f.c/h 已完成以下优化:
|
|||||||
│ net_accept() │ (连接成功) │
|
│ net_accept() │ (连接成功) │
|
||||||
│ │ │ │
|
│ │ │ │
|
||||||
│ ▼ ▼ │
|
│ ▼ ▼ │
|
||||||
│ TCP_ACCEPT ESTABLISHED ◄──┤
|
│ ESTABLISHED ◄──────────────┘
|
||||||
│ │ │ │
|
│ │ │
|
||||||
│ (分配连接)│ net_send/recv() │
|
│ net_accept() 返回监听 Socket 自身 │
|
||||||
│ │ │ │
|
│ │ │
|
||||||
│ ▼ ▼ │
|
│ net_send/recv() │
|
||||||
│ ESTABLISHED │
|
|
||||||
│ │ │
|
│ │ │
|
||||||
│ net_close() │
|
│ net_close() │
|
||||||
│ │ │
|
│ │ │
|
||||||
@@ -317,8 +301,8 @@ void tcp_server_single(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 3. 开始监听(单连接模式 backlog=0) */
|
/* 3. 开始监听 */
|
||||||
if (net_listen(listen_sock, 0) != 0) {
|
if (net_listen(listen_sock) != 0) {
|
||||||
printf("监听失败\r\n");
|
printf("监听失败\r\n");
|
||||||
net_close(listen_sock);
|
net_close(listen_sock);
|
||||||
return;
|
return;
|
||||||
@@ -365,97 +349,7 @@ void tcp_server_single(void)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 5.2 TCP Server(多连接)
|
### 5.2 TCP Client
|
||||||
|
|
||||||
多连接模式使用 1 个监听 Socket + N 个数据 Socket,支持并发连接:
|
|
||||||
|
|
||||||
```c
|
|
||||||
#include "net_socket.h"
|
|
||||||
#include "net_select.h"
|
|
||||||
|
|
||||||
#define MAX_CLIENTS 4
|
|
||||||
|
|
||||||
void tcp_server_multi(void)
|
|
||||||
{
|
|
||||||
int listen_sock;
|
|
||||||
struct net_sockaddr_in addr;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* 1. 创建监听 Socket */
|
|
||||||
listen_sock = net_socket(AF_INET, SOCK_STREAM, 0);
|
|
||||||
if (listen_sock < 0) {
|
|
||||||
printf("创建 Socket 失败\r\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 2. 绑定 */
|
|
||||||
addr.sin_family = AF_INET;
|
|
||||||
addr.sin_port = net_htons(8080);
|
|
||||||
addr.sin_addr.s_addr = net_inet_addr("0.0.0.0");
|
|
||||||
|
|
||||||
if (net_bind(listen_sock, (struct net_sockaddr *)&addr, sizeof(addr)) != 0) {
|
|
||||||
printf("绑定失败\r\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 3. 启动监听(backlog 设为并发连接数) */
|
|
||||||
if (net_listen(listen_sock, MAX_CLIENTS) != 0) {
|
|
||||||
printf("监听失败\r\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("TCP Server 启动,支持 %d 个并发连接\r\n", MAX_CLIENTS);
|
|
||||||
|
|
||||||
/* 4. 使用 select 等待事件 */
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
net_fd_set readfds;
|
|
||||||
struct net_timeval timeout;
|
|
||||||
|
|
||||||
NET_FD_ZERO(&readfds);
|
|
||||||
|
|
||||||
/* 监听 Socket 加入读集合 */
|
|
||||||
NET_FD_SET(listen_sock, &readfds);
|
|
||||||
|
|
||||||
/* 数据 Socket(1~4)加入读集合 */
|
|
||||||
for (i = 1; i <= MAX_CLIENTS; i++) {
|
|
||||||
NET_FD_SET(i, &readfds);
|
|
||||||
}
|
|
||||||
|
|
||||||
timeout.tv_sec = 0;
|
|
||||||
timeout.tv_usec = 100000; /* 100ms 超时 */
|
|
||||||
|
|
||||||
int ret = net_select(listen_sock + MAX_CLIENTS + 1,
|
|
||||||
&readfds, NULL, NULL, &timeout);
|
|
||||||
|
|
||||||
if (ret > 0)
|
|
||||||
{
|
|
||||||
/* 检查数据 Socket */
|
|
||||||
for (i = 1; i <= MAX_CLIENTS; i++)
|
|
||||||
{
|
|
||||||
if (NET_FD_ISSET(i, &readfds))
|
|
||||||
{
|
|
||||||
net_sock_t *sock = net_get_sock(i);
|
|
||||||
if (sock != NULL && sock->state == NET_SOCK_STATE_ESTABLISHED)
|
|
||||||
{
|
|
||||||
char buf[256];
|
|
||||||
int len = net_recv(i, buf, sizeof(buf) - 1, 0);
|
|
||||||
if (len > 0) {
|
|
||||||
buf[len] = '\0';
|
|
||||||
printf("Socket %d: %s\r\n", i, buf);
|
|
||||||
net_send(i, buf, len, 0); /* 回显 */
|
|
||||||
} else {
|
|
||||||
printf("Socket %d 断开\r\n", i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5.3 TCP Client
|
|
||||||
|
|
||||||
```c
|
```c
|
||||||
#include "net_socket.h"
|
#include "net_socket.h"
|
||||||
@@ -922,13 +816,12 @@ int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen);
|
|||||||
#### net_listen - 开始监听
|
#### net_listen - 开始监听
|
||||||
|
|
||||||
```c
|
```c
|
||||||
int net_listen(int sockfd, int backlog);
|
int net_listen(int sockfd);
|
||||||
```
|
```
|
||||||
|
|
||||||
| 参数 | 说明 |
|
| 参数 | 说明 |
|
||||||
|------|------|
|
|------|------|
|
||||||
| `sockfd` | socket 描述符 |
|
| `sockfd` | socket 描述符 |
|
||||||
| `backlog` | 最大并发连接数(0=单连接) |
|
|
||||||
| 返回值 | 0 成功,-1 失败 |
|
| 返回值 | 0 成功,-1 失败 |
|
||||||
|
|
||||||
#### net_accept - 接受连接
|
#### net_accept - 接受连接
|
||||||
@@ -1092,103 +985,7 @@ NET_FD_ISSET(fd, fdset) /* 检查 fd 是否在集合中 */
|
|||||||
|
|
||||||
## 11. 完整示例
|
## 11. 完整示例
|
||||||
|
|
||||||
### 11.1 TCP Echo Server(多连接)
|
### 11.1 TCP Client 自动重连
|
||||||
|
|
||||||
```c
|
|
||||||
#include "net_socket.h"
|
|
||||||
#include "net_select.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define SERVER_PORT 8080
|
|
||||||
#define MAX_CLIENTS 4
|
|
||||||
|
|
||||||
void tcp_echo_server(void)
|
|
||||||
{
|
|
||||||
int listen_sock;
|
|
||||||
struct net_sockaddr_in addr;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* 初始化网络 */
|
|
||||||
net_init("192.168.1.100", "255.255.255.0", "192.168.1.1");
|
|
||||||
|
|
||||||
/* 创建监听 Socket */
|
|
||||||
listen_sock = net_socket(AF_INET, SOCK_STREAM, 0);
|
|
||||||
if (listen_sock < 0) {
|
|
||||||
printf("创建 Socket 失败\r\n");
|
|
||||||
while(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 绑定 */
|
|
||||||
memset(&addr, 0, sizeof(addr));
|
|
||||||
addr.sin_family = AF_INET;
|
|
||||||
addr.sin_port = net_htons(SERVER_PORT);
|
|
||||||
addr.sin_addr.s_addr = net_inet_addr("0.0.0.0");
|
|
||||||
|
|
||||||
if (net_bind(listen_sock, (struct net_sockaddr *)&addr, sizeof(addr)) != 0) {
|
|
||||||
printf("绑定失败\r\n");
|
|
||||||
while(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 监听 */
|
|
||||||
if (net_listen(listen_sock, MAX_CLIENTS) != 0) {
|
|
||||||
printf("监听失败\r\n");
|
|
||||||
while(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("TCP Echo Server 启动,端口 %d\r\n", SERVER_PORT);
|
|
||||||
|
|
||||||
/* 主循环 */
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
net_fd_set readfds;
|
|
||||||
struct net_timeval timeout;
|
|
||||||
|
|
||||||
NET_FD_ZERO(&readfds);
|
|
||||||
NET_FD_SET(listen_sock, &readfds);
|
|
||||||
|
|
||||||
for (i = 1; i <= MAX_CLIENTS; i++) {
|
|
||||||
NET_FD_SET(i, &readfds);
|
|
||||||
}
|
|
||||||
|
|
||||||
timeout.tv_sec = 0;
|
|
||||||
timeout.tv_usec = 100000;
|
|
||||||
|
|
||||||
int ret = net_select(listen_sock + MAX_CLIENTS + 1,
|
|
||||||
&readfds, NULL, NULL, &timeout);
|
|
||||||
|
|
||||||
if (ret > 0)
|
|
||||||
{
|
|
||||||
for (i = 1; i <= MAX_CLIENTS; i++)
|
|
||||||
{
|
|
||||||
if (NET_FD_ISSET(i, &readfds))
|
|
||||||
{
|
|
||||||
net_sock_t *sock = net_get_sock(i);
|
|
||||||
|
|
||||||
if (sock == NULL) continue;
|
|
||||||
|
|
||||||
if (sock->state == NET_SOCK_STATE_ESTABLISHED)
|
|
||||||
{
|
|
||||||
char buf[256];
|
|
||||||
int len = net_recv(i, buf, sizeof(buf) - 1, 0);
|
|
||||||
|
|
||||||
if (len > 0) {
|
|
||||||
buf[len] = '\0';
|
|
||||||
printf("客户端 %d: %s\r\n", i, buf);
|
|
||||||
net_send(i, buf, len, 0);
|
|
||||||
} else {
|
|
||||||
printf("客户端 %d 断开\r\n", i);
|
|
||||||
net_close(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 11.2 TCP Client 自动重连
|
|
||||||
|
|
||||||
```c
|
```c
|
||||||
#include "net_socket.h"
|
#include "net_socket.h"
|
||||||
@@ -1261,8 +1058,7 @@ void tcp_client_reconnect(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (sock_info != NULL &&
|
else if (sock_info != NULL &&
|
||||||
(sock_info->state == NET_SOCK_STATE_TCP_ACCEPT ||
|
(sock_info->state == NET_SOCK_STATE_CLOSED))
|
||||||
sock_info->state == NET_SOCK_STATE_CLOSED))
|
|
||||||
{
|
{
|
||||||
/* 连接失败或断开 */
|
/* 连接失败或断开 */
|
||||||
printf("连接失败,准备重连...\r\n");
|
printf("连接失败,准备重连...\r\n");
|
||||||
@@ -1287,27 +1083,17 @@ void tcp_client_reconnect(void)
|
|||||||
### 12.2 Socket 数量有限制吗?
|
### 12.2 Socket 数量有限制吗?
|
||||||
|
|
||||||
是的,CH395F 最多支持 8 个 Socket(索引 0~7)。其中:
|
是的,CH395F 最多支持 8 个 Socket(索引 0~7)。其中:
|
||||||
- TCP Server 多连接模式:1 个监听 Socket + 最多 7 个数据 Socket
|
- TCP Server(单连接):1 个监听 Socket 即数据通道
|
||||||
- TCP Client:最多 8 个
|
- TCP Client:最多 8 个
|
||||||
- UDP:最多 8 个
|
- UDP:最多 8 个
|
||||||
|
|
||||||
### 12.3 TCP Server 多连接模式有什么要求?
|
### 12.3 发送数据有什么限制?
|
||||||
|
|
||||||
**模式工作原理:**
|
|
||||||
- CH395F 多连接模式下,Socket 0 专职监听,Socket 1~7 由芯片自动分配
|
|
||||||
- 客户端连接时,CH395F 自动查找协议类型为 TCP、源端口与监听端口相同、处于关闭状态的 Socket
|
|
||||||
- 找到后自动打开该 Socket 并分配连接,触发 CONNECT 中断
|
|
||||||
|
|
||||||
**硬件要求:**
|
|
||||||
- CH395F 固件版本 >= 0x44(支持 Socket 4~7)
|
|
||||||
|
|
||||||
### 12.4 发送数据有什么限制?
|
|
||||||
|
|
||||||
- 每次发送的数据长度不能超过 `NET_SEND_BUF_SIZE`(默认 4096 字节)
|
- 每次发送的数据长度不能超过 `NET_SEND_BUF_SIZE`(默认 4096 字节)
|
||||||
- TCP 需要等待发送缓冲区空闲(`send_ready` 标志)
|
- TCP 需要等待发送缓冲区空闲(`send_ready` 标志)
|
||||||
- UDP 单次发送最大 1460 字节
|
- UDP 单包载荷最大 1472 字节(写入超过此值,CH395F 会自动分片为多个 UDP 包发送)
|
||||||
|
|
||||||
### 12.5 如何处理连接断开?
|
### 12.4 如何处理连接断开?
|
||||||
|
|
||||||
**方式一:阻塞接收**
|
**方式一:阻塞接收**
|
||||||
```c
|
```c
|
||||||
@@ -1338,7 +1124,7 @@ void callback(int sockfd, net_event_t event, void *arg)
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 12.6 select 和 poll 的区别?
|
### 12.5 select 和 poll 的区别?
|
||||||
|
|
||||||
| 特性 | select | poll |
|
| 特性 | select | poll |
|
||||||
|------|--------|------|
|
|------|--------|------|
|
||||||
@@ -1348,7 +1134,7 @@ void callback(int sockfd, net_event_t event, void *arg)
|
|||||||
|
|
||||||
两者功能相同,推荐使用 `net_select()`,更接近 Linux 编程习惯。
|
两者功能相同,推荐使用 `net_select()`,更接近 Linux 编程习惯。
|
||||||
|
|
||||||
### 12.7 错误码说明
|
### 12.6 错误码说明
|
||||||
|
|
||||||
| 错误码 | 宏定义 | 说明 |
|
| 错误码 | 宏定义 | 说明 |
|
||||||
|--------|--------|------|
|
|--------|--------|------|
|
||||||
@@ -1365,7 +1151,7 @@ void callback(int sockfd, net_event_t event, void *arg)
|
|||||||
| -10 | NET_ERR_NOSPACE | 发送缓冲区无空间 |
|
| -10 | NET_ERR_NOSPACE | 发送缓冲区无空间 |
|
||||||
| -11 | NET_ERR_BUSY | 操作未完成(BUSY) |
|
| -11 | NET_ERR_BUSY | 操作未完成(BUSY) |
|
||||||
|
|
||||||
### 12.8 CH395F 命令执行状态码
|
### 12.7 CH395F 命令执行状态码
|
||||||
|
|
||||||
CH395F 底层驱动返回的状态码(`ch395f_get_cmd_status()` 或 `ch395f_poll_cmd_status()`):
|
CH395F 底层驱动返回的状态码(`ch395f_get_cmd_status()` 或 `ch395f_poll_cmd_status()`):
|
||||||
|
|
||||||
@@ -1390,15 +1176,7 @@ CH395F 底层驱动返回的状态码(`ch395f_get_cmd_status()` 或 `ch395f_po
|
|||||||
| 0x5F | CH395F_CMD_RET_ABORT | 命令中止 |
|
| 0x5F | CH395F_CMD_RET_ABORT | 命令中止 |
|
||||||
| 0xFA | CH395F_ERR_UNKNOW | 未知错误 |
|
| 0xFA | CH395F_ERR_UNKNOW | 未知错误 |
|
||||||
|
|
||||||
### 12.9 故障排查
|
### 12.8 故障排查
|
||||||
|
|
||||||
**问题:TCP Client 连接超时,无 CONNECT 中断**
|
|
||||||
- 检查多连接模式下数据 Socket(1~7)是否设置了 `SET_PROTO_TCP` + `SET_SOUR_PORT`(与监听端口相同)
|
|
||||||
- 如果不设置,CH395F 不知道哪些 Socket 可用于自动分配,TCP SYN 被静默丢弃
|
|
||||||
|
|
||||||
**问题:数据 Socket OPEN 返回 0x1B(已被使用)**
|
|
||||||
- CH395F 多连接模式下,数据 Socket 由芯片自动管理,软件不应手动 `OPEN_SOCKET`
|
|
||||||
- 只需 `SET_PROTO_TCP` + `SET_SOUR_PORT`,CH395F 在有连接时自动打开
|
|
||||||
|
|
||||||
**问题:Socket 4~7 的 CONNECT/RECV 中断不触发**
|
**问题:Socket 4~7 的 CONNECT/RECV 中断不触发**
|
||||||
- 需使用 `GET_GLOB_INT_STATUS_ALL`(命令码 0x19,返回 2 字节)才能检测 Socket 4~7 的中断
|
- 需使用 `GET_GLOB_INT_STATUS_ALL`(命令码 0x19,返回 2 字节)才能检测 Socket 4~7 的中断
|
||||||
@@ -1408,7 +1186,7 @@ CH395F 底层驱动返回的状态码(`ch395f_get_cmd_status()` 或 `ch395f_po
|
|||||||
- 芯片 INIT 需要约 200ms,轮询间隔应为 20ms(过短的查询可能干扰内部处理)
|
- 芯片 INIT 需要约 200ms,轮询间隔应为 20ms(过短的查询可能干扰内部处理)
|
||||||
- 超时值建议设为 4 秒以上
|
- 超时值建议设为 4 秒以上
|
||||||
|
|
||||||
### 12.10 线程安全问题
|
### 12.9 线程安全问题
|
||||||
|
|
||||||
**问题:`net_send()` / `net_recv()` / `net_close()` 可以在任意任务中调用吗?**
|
**问题:`net_send()` / `net_recv()` / `net_close()` 可以在任意任务中调用吗?**
|
||||||
|
|
||||||
|
|||||||
@@ -1790,7 +1790,7 @@ void StartCh395fTestTask(void *argument)
|
|||||||
DBG_INFO("Test task: bound to port 8080");
|
DBG_INFO("Test task: bound to port 8080");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (net_listen(sockfd, 0) < 0) {
|
if (net_listen(sockfd) < 0) {
|
||||||
DBG_ERROR("Test task: net_listen failed");
|
DBG_ERROR("Test task: net_listen failed");
|
||||||
goto task_end;
|
goto task_end;
|
||||||
}
|
}
|
||||||
@@ -1854,7 +1854,7 @@ void StartCh395fTestTask(void *argument)
|
|||||||
DBG_INFO("Test task: connection closed, re-listen...");
|
DBG_INFO("Test task: connection closed, re-listen...");
|
||||||
net_close(sockfd);
|
net_close(sockfd);
|
||||||
osDelay(500);
|
osDelay(500);
|
||||||
net_listen(sockfd, 0);
|
net_listen(sockfd);
|
||||||
phase_active = 0;
|
phase_active = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user