320 lines
6.8 KiB
C
320 lines
6.8 KiB
C
/*
|
||
* 模块名称:Network Select Implementation
|
||
* 模块功能:I/O 多路复用实现,包括 select 和 poll 模式,
|
||
* 用于同时监控多个 Socket 的读写事件
|
||
* 适用平台:STM32F4 系列(CH395F 以太网芯片)
|
||
* 作者:王建锋
|
||
* 创建日期:2026-07-18
|
||
* 修改记录:
|
||
*/
|
||
|
||
#include "net_select.h"
|
||
#include "net_socket.h"
|
||
#include "ch395f.h"
|
||
|
||
/*
|
||
* 私有函数声明区
|
||
*/
|
||
static int check_socket_readable(int sockfd);
|
||
static int check_socket_writable(int sockfd);
|
||
static int check_socket_error(int sockfd);
|
||
|
||
/*
|
||
* 公共函数实现区
|
||
*/
|
||
|
||
/*
|
||
* 函数功能:I/O 多路复用(select 模式)
|
||
*/
|
||
int net_select(int nfds, net_fd_set *readfds, net_fd_set *writefds,
|
||
net_fd_set *exceptfds, net_timeval *timeout)
|
||
{
|
||
uint32_t start_tick;
|
||
uint32_t timeout_ms = 0;
|
||
net_fd_set result_read = {0};
|
||
net_fd_set result_write = {0};
|
||
net_fd_set result_except = {0};
|
||
int ready_count = 0;
|
||
int i;
|
||
|
||
/* 计算超时时间 */
|
||
if (timeout != NULL)
|
||
{
|
||
timeout_ms = (uint32_t)(timeout->tv_sec * 1000) +
|
||
(uint32_t)(timeout->tv_usec / 1000);
|
||
}
|
||
|
||
start_tick = HAL_GetTick();
|
||
|
||
while (1)
|
||
{
|
||
/* 轮询所有 Socket */
|
||
net_poll();
|
||
|
||
ready_count = 0;
|
||
|
||
/* 检查哪些 Socket 有事件 */
|
||
for (i = 0; i < nfds && i < NET_MAX_SOCKETS; i++)
|
||
{
|
||
net_sock_t *sock = net_get_sock(i);
|
||
|
||
if (sock == NULL)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
/* 检查可读事件 */
|
||
if (readfds != NULL && NET_FD_ISSET(i, readfds))
|
||
{
|
||
if (check_socket_readable(i))
|
||
{
|
||
NET_FD_SET(i, &result_read);
|
||
ready_count++;
|
||
}
|
||
}
|
||
|
||
/* 检查可写事件 */
|
||
if (writefds != NULL && NET_FD_ISSET(i, writefds))
|
||
{
|
||
if (check_socket_writable(i))
|
||
{
|
||
NET_FD_SET(i, &result_write);
|
||
ready_count++;
|
||
}
|
||
}
|
||
|
||
/* 检查异常事件 */
|
||
if (exceptfds != NULL && NET_FD_ISSET(i, exceptfds))
|
||
{
|
||
if (check_socket_error(i))
|
||
{
|
||
NET_FD_SET(i, &result_except);
|
||
ready_count++;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 有事件就绪,返回 */
|
||
if (ready_count > 0)
|
||
{
|
||
break;
|
||
}
|
||
|
||
/* 超时检查 */
|
||
if (timeout != NULL)
|
||
{
|
||
if (timeout_ms > 0 &&
|
||
(HAL_GetTick() - start_tick) >= timeout_ms)
|
||
{
|
||
break; /* 超时返回 0 */
|
||
}
|
||
}
|
||
|
||
/* 短暂延时避免忙等 */
|
||
HAL_Delay(NET_POLL_DELAY_MS);
|
||
}
|
||
|
||
/* 复制结果 */
|
||
if (readfds != NULL)
|
||
{
|
||
readfds->fd_bits = result_read.fd_bits;
|
||
}
|
||
if (writefds != NULL)
|
||
{
|
||
writefds->fd_bits = result_write.fd_bits;
|
||
}
|
||
if (exceptfds != NULL)
|
||
{
|
||
exceptfds->fd_bits = result_except.fd_bits;
|
||
}
|
||
|
||
return ready_count;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:I/O 多路复用(poll 模式)
|
||
*/
|
||
int net_poll_events(net_pollfd *fds, int nfds, int timeout)
|
||
{
|
||
uint32_t start_tick;
|
||
int ready = 0;
|
||
int i;
|
||
|
||
if (fds == NULL || nfds <= 0)
|
||
{
|
||
return -1;
|
||
}
|
||
|
||
start_tick = HAL_GetTick();
|
||
|
||
while (1)
|
||
{
|
||
/* 轮询 */
|
||
net_poll();
|
||
|
||
ready = 0;
|
||
|
||
for (i = 0; i < nfds; i++)
|
||
{
|
||
fds[i].revents = 0;
|
||
|
||
/* 检查 fd 有效性 */
|
||
if (fds[i].fd < 0 || fds[i].fd >= NET_MAX_SOCKETS)
|
||
{
|
||
fds[i].revents |= NET_POLLNVAL;
|
||
ready++;
|
||
continue;
|
||
}
|
||
|
||
net_sock_t *sock = net_get_sock(fds[i].fd);
|
||
|
||
if (sock == NULL)
|
||
{
|
||
fds[i].revents |= NET_POLLNVAL;
|
||
ready++;
|
||
continue;
|
||
}
|
||
|
||
/* 检查可读 */
|
||
if (fds[i].events & NET_POLLIN)
|
||
{
|
||
if (check_socket_readable(fds[i].fd))
|
||
{
|
||
fds[i].revents |= NET_POLLIN;
|
||
ready++;
|
||
}
|
||
}
|
||
|
||
/* 检查可写 */
|
||
if (fds[i].events & NET_POLLOUT)
|
||
{
|
||
if (check_socket_writable(fds[i].fd))
|
||
{
|
||
fds[i].revents |= NET_POLLOUT;
|
||
ready++;
|
||
}
|
||
}
|
||
|
||
/* 检查错误 */
|
||
if (check_socket_error(fds[i].fd))
|
||
{
|
||
fds[i].revents |= NET_POLLERR;
|
||
ready++;
|
||
}
|
||
|
||
/* 检查挂起(连接断开) */
|
||
if (sock->state == NET_SOCK_STATE_TCP_ACCEPT ||
|
||
sock->state == NET_SOCK_STATE_CLOSED)
|
||
{
|
||
fds[i].revents |= NET_POLLHUP;
|
||
ready++;
|
||
}
|
||
}
|
||
|
||
if (ready > 0)
|
||
{
|
||
break;
|
||
}
|
||
|
||
/* 超时检查 */
|
||
if (timeout >= 0)
|
||
{
|
||
if ((HAL_GetTick() - start_tick) >= (uint32_t)timeout)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
|
||
HAL_Delay(NET_POLL_DELAY_MS);
|
||
}
|
||
|
||
return ready;
|
||
}
|
||
|
||
/*
|
||
* 私有函数实现区
|
||
*/
|
||
|
||
/*
|
||
* 函数功能:检查 Socket 是否可读
|
||
* 返回值:1 可读,0 不可读
|
||
*/
|
||
static int check_socket_readable(int sockfd)
|
||
{
|
||
net_sock_t *sock;
|
||
uint16_t recv_len;
|
||
|
||
sock = net_get_sock(sockfd);
|
||
if (sock == NULL)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
/* 监听 Socket 有新连接时可读 */
|
||
if (sock->state == NET_SOCK_STATE_LISTENING)
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
/* 已建立连接的 Socket 有数据可读 */
|
||
if (sock->state == NET_SOCK_STATE_ESTABLISHED)
|
||
{
|
||
recv_len = ch395f_get_recv_len(sockfd);
|
||
if (recv_len > 0)
|
||
{
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:检查 Socket 是否可写
|
||
* 返回值:1 可写,0 不可写
|
||
*/
|
||
static int check_socket_writable(int sockfd)
|
||
{
|
||
net_sock_t *sock;
|
||
|
||
sock = net_get_sock(sockfd);
|
||
if (sock == NULL)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
/* 已建立连接的 Socket 发送缓冲区空闲时可写 */
|
||
if (sock->state == NET_SOCK_STATE_ESTABLISHED)
|
||
{
|
||
if (sock->send_ready)
|
||
{
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:检查 Socket 是否有错误
|
||
* 返回值:1 有错误,0 无错误
|
||
*/
|
||
static int check_socket_error(int sockfd)
|
||
{
|
||
net_sock_t *sock;
|
||
|
||
/* 无效 fd 视为错误 */
|
||
if (sockfd < 0 || sockfd >= NET_MAX_SOCKETS)
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
sock = net_get_sock(sockfd);
|
||
if (sock == NULL)
|
||
{
|
||
return 1; /* 未使用的 Socket 视为错误 */
|
||
}
|
||
|
||
return 0;
|
||
}
|