/* * 模块名称:Network Socket API * 模块功能:BSD Socket API 兼容接口,提供 TCP/UDP 网络通信功能, * 底层基于 CH395F 以太网协议栈芯片 * 适用平台:STM32F4 系列(CH395F 以太网芯片) * 作者:王建锋 * 创建日期:2026-07-18 * 修改记录: */ #ifndef __NET_SOCKET_H #define __NET_SOCKET_H #ifdef __cplusplus extern "C" { #endif #include "net_types.h" #include "FreeRTOS.h" #include "task.h" /* * 消息队列类型定义 */ typedef enum { NET_MSG_SEND, NET_MSG_RECV, NET_MSG_CLOSE, NET_MSG_CONNECT, NET_MSG_LISTEN, NET_MSG_ACCEPT, } net_msg_type_t; typedef struct { net_msg_type_t type; /* 操作类型 */ int sockfd; /* Socket 描述符 */ void *buf; /* 数据缓冲区(send/recv) */ int len; /* 数据长度/缓冲区大小 */ int flags; /* 接收标志 */ TaskHandle_t caller; /* 调用方任务句柄 */ int result; /* 操作结果 */ /* 连接参数 */ struct net_sockaddr_in addr; /* 连接地址 */ int addrlen; /* 地址长度 */ } net_msg_t; /* * 网络初始化接口 */ /* * 函数功能:网络子系统初始化(配置 CH395F + 启用多连接模式) * 入口参数:ip - 本地 IP 地址字符串 "192.168.1.100",NULL 使用 DHCP * mask - 子网掩码字符串 "255.255.255.0",NULL 使用默认 * gateway - 网关地址字符串 "192.168.1.1",NULL 使用默认 * 返回值:0 成功,-1 失败 * 限定条件:SPI2 已正确初始化 * 函数说明:必须在所有网络操作之前调用 */ int net_init(const char *ip, const char *mask, const char *gateway); /* * 函数功能:轮询所有 Socket 状态(必须在主循环中调用) * 返回值:有事件发生的 socket 数量 * 限定条件:net_init() 已调用 * 函数说明:此函数处理所有 Socket 的中断事件,更新状态, * 并触发事件回调。在非阻塞模式下必须定期调用。 */ int net_poll(void); /* * 核心 Socket API */ /* * 函数功能:创建 socket * 入口参数:domain - 地址族,仅支持 AF_INET * type - SOCK_STREAM(TCP) 或 SOCK_DGRAM(UDP) * protocol - 通常为 0 * 返回值:socket 描述符 (0~7),失败返回 -1 * 限定条件:net_init() 已调用 * 函数说明:自动分配空闲 Socket 控制块 */ int net_socket(int domain, int type, int protocol); /* * 函数功能:绑定本地地址和端口 * 入口参数:sockfd - socket 描述符 * addr - 本地地址结构体指针 * addrlen - 地址结构体长度 * 返回值:0 成功,-1 失败 * 限定条件:socket 已创建且未绑定 * 函数说明:设置 CH395F 源端口 */ int net_bind(int sockfd, const struct net_sockaddr *addr, int addrlen); /* * 函数功能:TCP Server 监听 * 入口参数:sockfd - socket 描述符 * backlog - 最大等待连接数(多连接模式下为数据 Socket 数量) * 返回值:0 成功,-1 失败 * 限定条件:socket 已绑定 * 函数说明:内部调用 ch395f_tcp_listen,多连接模式自动配置数据 Socket */ int net_listen(int sockfd, int backlog); /* * 函数功能:TCP Server 接受连接 * 入口参数:sockfd - 监听 socket 描述符 * addr - 输出:客户端地址 * addrlen - 输入输出:地址长度 * 返回值:新 socket 描述符,失败返回 -1 * 限定条件:socket 正在监听 * 函数说明:在非阻塞模式下,如果没有新连接,返回 -1 并设置 * net_errno 为 NET_ERR_WOULDBLOCK */ int net_accept(int sockfd, struct net_sockaddr *addr, int *addrlen); /* * 函数功能:TCP Client 发起连接 * 入口参数:sockfd - socket 描述符 * addr - 服务器地址 * addrlen - 地址长度 * 返回值:0 成功,-1 失败 * 限定条件:socket 已创建 * 函数说明:连接过程是异步的,需要调用 net_poll() 等待连接完成, * 或使用 select() 等待可写事件 */ int net_connect(int sockfd, const struct net_sockaddr *addr, int addrlen); /* * 函数功能:发送数据(TCP) * 入口参数:sockfd - socket 描述符 * buf - 数据缓冲区 * len - 数据长度 * flags - 通常为 0 * 返回值:实际发送字节数,失败返回 -1 * 限定条件:TCP 连接已建立,指针非空 * 函数说明:阻塞等待发送缓冲区空闲,拷贝数据后触发发送 */ int net_send(int sockfd, const void *buf, int len, int flags); /* * 函数功能:接收数据(TCP) * 入口参数:sockfd - socket 描述符 * buf - 接收缓冲区 * len - 缓冲区大小 * flags - 通常为 0,可设置 NET_MSG_DONTWAIT 非阻塞 * 返回值:实际接收字节数,0=对端关闭,-1=错误 * 限定条件:TCP 连接已建立 * 函数说明:在阻塞模式下,如果没有数据,函数会等待; * 在非阻塞模式下,如果没有数据,返回 -1 并设置 * net_errno 为 NET_ERR_WOULDBLOCK */ int net_recv(int sockfd, void *buf, int len, int flags); /* * 函数功能:发送 UDP 数据 * 入口参数:sockfd - socket 描述符 * buf - 数据缓冲区 * len - 数据长度 * flags - 通常为 0 * dest_addr - 目标地址 * addrlen - 地址长度 * 返回值:实际发送字节数,失败返回 -1 * 限定条件:socket 已创建,指针非空 * 函数说明:设置目标地址后调用 CH395F 发送 */ int net_sendto(int sockfd, const void *buf, int len, int flags, const struct net_sockaddr *dest_addr, int addrlen); /* * 函数功能:接收 UDP 数据 * 入口参数:sockfd - socket 描述符 * buf - 接收缓冲区 * len - 缓冲区大小 * flags - 通常为 0 * src_addr - 输出:发送方地址 * addrlen - 输入输出:地址长度 * 返回值:实际接收字节数,失败返回 -1 * 限定条件:socket 已创建,指针非空 * 函数说明:读取 CH395F 接收缓冲区,获取对端地址 */ int net_recvfrom(int sockfd, void *buf, int len, int flags, struct net_sockaddr *src_addr, int *addrlen); /* * 函数功能:关闭 socket * 入口参数:sockfd - socket 描述符 * 返回值:0 成功,-1 失败 * 限定条件:socket 已打开 * 函数说明:释放 Socket 控制块,TCP 先断开连接 */ int net_close(int sockfd); /* * 事件回调 API */ /* * 函数功能:注册事件回调 * 入口参数:sockfd - socket 描述符 * cb - 回调函数 * arg - 用户参数 * 返回值:0 成功,-1 失败 * 限定条件:socket 已创建 * 函数说明:回调在 net_poll 上下文中触发 */ int net_set_event_cb(int sockfd, net_event_cb_t cb, void *arg); /* * 辅助函数 */ /* * 函数功能:获取 socket 最后错误码 * 返回值:错误码(NET_ERR_xxx) */ int net_get_errno(void); /* * 函数功能:将 IP 地址字符串转为网络字节序 * 入口参数:cp - 点分十进制字符串 "192.168.1.100" * 返回值:网络字节序 IP,失败返回 0 * 限定条件:cp 指针非空 * 函数说明:不支持域名解析 */ uint32_t net_inet_addr(const char *cp); /* * 函数功能:将网络字节序 IP 转为字符串 * 入口参数:addr - 网络字节序 IP * buf - 输出缓冲区(至少 16 字节) * 返回值:buf 指针 * 限定条件:buf 指针非空 */ char *net_inet_ntoa(uint32_t addr, char *buf); /* * 函数功能:端口字节序转换(主机序 -> 网络序) * 入口参数:hostshort - 主机序端口 * 返回值:网络序端口 * 限定条件:无 * 函数说明:小端 → 大端 */ uint16_t net_htons(uint16_t hostshort); /* * 函数功能:端口字节序转换(网络序 -> 主机序) * 入口参数:netshort - 网络序端口 * 返回值:主机序端口 * 限定条件:无 * 函数说明:大端 → 小端 */ uint16_t net_ntohs(uint16_t netshort); /* * 函数功能:IP 地址字节序转换(主机序 -> 网络序) * 入口参数:hostlong - 主机序 IP * 返回值:网络序 IP * 限定条件:无 * 函数说明:小端 → 大端 */ uint32_t net_htonl(uint32_t hostlong); /* * 函数功能:IP 地址字节序转换(网络序 -> 主机序) * 入口参数:netlong - 网络序 IP * 返回值:主机序 IP * 限定条件:无 * 函数说明:大端 → 小端 */ uint32_t net_ntohl(uint32_t netlong); /* * 函数功能:处理消息队列中的请求(必须在 netTask 主循环中调用) * 限定条件:net_init() 已调用 * 函数说明:处理其他任务通过 net_send/net_recv 等接口发送的请求, * 在 netTask 上下文中串行化执行所有 CH395F 操作 */ void net_process_messages(void); /* * 函数功能:获取 Socket 控制块指针(内部使用) * 入口参数:sockfd - socket 描述符 * 返回值:Socket 控制块指针,失败返回 NULL */ net_sock_t *net_get_sock(int sockfd); /* * 内部 API(需在 netTask 上下文中调用,绕过消息队列) */ /* * 函数功能:发送数据(内部版本,直接操作,不经过消息队列) * 入口参数:p_sock - Socket 控制块指针 * buf - 数据缓冲区 * len - 数据长度 * 返回值:实际发送字节数,失败返回 -1 * 限定条件:必须在 netTask 上下文中调用 */ int net_send_sock(net_sock_t *p_sock, const void *buf, int len); /* * 函数功能:接收数据(内部版本,直接操作,不经过消息队列) * 入口参数:p_sock - Socket 控制块指针 * buf - 接收缓冲区 * len - 缓冲区大小 * flags - 通常为 0,可设置 NET_MSG_DONTWAIT * 返回值:实际接收字节数,0=对端关闭,-1=错误 * 限定条件:必须在 netTask 上下文中调用 */ int net_recv_sock(net_sock_t *p_sock, void *buf, int len, int flags); /* * 函数功能:关闭 socket(内部版本,直接操作,不经过消息队列) * 入口参数:p_sock - Socket 控制块指针 * 返回值:0 成功,-1 失败 * 限定条件:必须在 netTask 上下文中调用 */ int net_close_sock(net_sock_t *p_sock); /* * 函数功能:启动 TCP Server 监听(内部版本,直接操作,不经过消息队列) * 入口参数:sockfd - Socket 描述符 * backlog - 数据 Socket 数量(0=单连接模式) * 返回值:0 成功,-1 失败 * 限定条件:必须在 netTask 上下文中调用 */ int net_listen_locked(int sockfd, int backlog); #ifdef __cplusplus } #endif #endif /* __NET_SOCKET_H */