Files
STM32F4-Base/Drivers/BSP/NET/net_select.c
2026-07-19 00:59:56 +08:00

320 lines
6.8 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 模块名称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;
}