asp.net空网站山东省建设管理局网站

张小明 2026/1/9 13:02:14
asp.net空网站,山东省建设管理局网站,做网站卖货,在线短视频网站开发费用第一阶段 设计架构Linux Socket模块第一部分#xff1a;规划 - 专注Linux Socket核心1.1 精简架构设计socket_lib/ ├── include/ # 对外头文件#xff08;只有1个#xff01;#xff09; │ └── socket.h # 统一对外接口 ├── …第一阶段 设计架构Linux Socket模块第一部分规划 - 专注Linux Socket核心1.1 精简架构设计socket_lib/ ├── include/ # 对外头文件只有1个 │ └── socket.h # 统一对外接口 ├── src/ # 内部实现 │ ├── socket_core.c # 核心创建、绑定、连接、关闭 │ ├── socket_io.c # 核心发送、接收 │ ├── socket_opt.c # 核心选项设置 │ └── socket_util.c # 辅助地址转换、错误处理 └── examples/ ├── echo_server.c └── echo_client.c1.2 核心功能树只做最必要的Socket核心功能 ├── 1. 基础操作 │ ├── socket_create() # 创建Socket │ ├── socket_close() # 关闭Socket │ └── socket_dup() # 复制Socket ├── 2. 连接管理 │ ├── socket_bind() # 绑定地址 │ ├── socket_connect() # 连接远程 │ ├── socket_listen() # 开始监听 │ └── socket_accept() # 接受连接 ├── 3. 数据IO │ ├── socket_send() # 发送数据TCP │ ├── socket_recv() # 接收数据TCP │ ├── socket_sendto() # 发送到地址UDP │ └── socket_recvfrom() # 从地址接收UDP ├── 4. 选项设置 │ ├── socket_setopt() # 设置选项 │ ├── socket_getopt() # 获取选项 │ ├── socket_set_nonblock() # 非阻塞模式 │ └── socket_set_timeout() # 超时设置 └── 5. 工具函数 ├── socket_addr_create() # 创建地址 ├── socket_addr_str() # 地址转字符串 └── socket_error_str() # 错误描述第二部分简洁头文件设计2.1 统一对外头文件 (socket.h)/** * file socket.h * brief Linux Socket通信库 - 简洁版 * * 基于Linux系统调用的Socket封装提供简单、直接、高效的接口。 * 使用基础库的common.h进行错误处理和线程安全。 * * version 1.0 * date 2024-01-01 */ ​ #ifndef SOCKET_H #define SOCKET_H ​ #include stdbool.h #include stddef.h #include stdint.h ​ #ifdef __cplusplus extern C { #endif ​ /* 基本类型 */ ​ /** * brief Socket句柄直接使用文件描述符 */ typedef int socket_t; ​ /** * brief 无效Socket定义 */ #define SOCKET_INVALID (-1) ​ /** * brief 地址族类型 */ typedef enum { SOCK_AF_INET 0, /** IPv4地址族 */ SOCK_AF_INET6, /** IPv6地址族 */ SOCK_AF_UNIX /** Unix域Socket */ } sock_family_t; ​ /** * brief Socket类型 */ typedef enum { SOCK_TYPE_STREAM 0, /** 流式Socket (TCP) */ SOCK_TYPE_DGRAM /** 数据报Socket (UDP) */ } sock_type_t; ​ /** * brief 地址结构足够简单 */ typedef struct { sock_family_t family; /** 地址族 */ union { struct { uint32_t addr; /** IPv4地址网络字节序 */ uint16_t port; /** 端口网络字节序 */ } ipv4; struct { uint8_t addr[16]; /** IPv6地址 */ uint16_t port; /** 端口网络字节序 */ } ipv6; struct { char path[108]; /** Unix域路径 */ } unix; } u; } sock_addr_t; ​ /* 错误码 */ ​ /** * brief 错误码直接使用errno简化 */ typedef int sock_error_t; ​ /** * brief 成功码 */ #define SOCK_SUCCESS 0 ​ /* 初始化 */ ​ /** * brief 初始化Socket库可选 * * return int 0成功-1失败 */ int sock_init(void); ​ /** * brief 清理Socket库 */ void sock_cleanup(void); ​ /* Socket生命周期 */ ​ /** * brief 创建Socket * * param family 地址族SOCK_AF_INET/SOCK_AF_INET6/SOCK_AF_UNIX * param type Socket类型SOCK_TYPE_STREAM/SOCK_TYPE_DGRAM * return socket_t Socket句柄失败返回SOCKET_INVALID */ socket_t sock_create(sock_family_t family, sock_type_t type); ​ /** * brief 关闭Socket * * param sock Socket句柄 * return int 0成功-1失败 */ int sock_close(socket_t sock); ​ /** * brief 复制Socket * * param sock 源Socket * return socket_t 新Socket失败返回SOCKET_INVALID */ socket_t sock_dup(socket_t sock); ​ /* 连接管理 */ ​ /** * brief 绑定地址 * * param sock Socket句柄 * param addr 地址 * return int 0成功-1失败 */ int sock_bind(socket_t sock, const sock_addr_t* addr); ​ /** * brief 连接到远程 * * param sock Socket句柄 * param addr 远程地址 * param timeout_ms 超时时间毫秒0表示阻塞 * return int 0成功-1失败 */ int sock_connect(socket_t sock, const sock_addr_t* addr, int timeout_ms); ​ /** * brief 开始监听 * * param sock Socket句柄 * param backlog 等待连接队列长度 * return int 0成功-1失败 */ int sock_listen(socket_t sock, int backlog); ​ /** * brief 接受连接 * * param sock 监听Socket * param client_addr 输出客户端地址可为NULL * param timeout_ms 超时时间毫秒0表示阻塞 * return socket_t 客户端Socket失败返回SOCKET_INVALID */ socket_t sock_accept(socket_t sock, sock_addr_t* client_addr, int timeout_ms); ​ /* 数据IO */ ​ /** * brief 发送数据TCP * * param sock Socket句柄 * param buf 数据缓冲区 * param len 数据长度 * param timeout_ms 超时时间毫秒0表示阻塞 * return ssize_t 发送的字节数-1失败 */ ssize_t sock_send(socket_t sock, const void* buf, size_t len, int timeout_ms); ​ /** * brief 接收数据TCP * * param sock Socket句柄 * param buf 接收缓冲区 * param len 缓冲区长度 * param timeout_ms 超时时间毫秒0表示阻塞 * return ssize_t 接收的字节数-1失败0连接关闭 */ ssize_t sock_recv(socket_t sock, void* buf, size_t len, int timeout_ms); ​ /** * brief 发送数据到地址UDP * * param sock Socket句柄 * param buf 数据缓冲区 * param len 数据长度 * param addr 目标地址 * return ssize_t 发送的字节数-1失败 */ ssize_t sock_sendto(socket_t sock, const void* buf, size_t len, const sock_addr_t* addr); ​ /** * brief 从地址接收数据UDP * * param sock Socket句柄 * param buf 接收缓冲区 * param len 缓冲区长度 * param src_addr 输出源地址可为NULL * param timeout_ms 超时时间毫秒0表示阻塞 * return ssize_t 接收的字节数-1失败 */ ssize_t sock_recvfrom(socket_t sock, void* buf, size_t len, sock_addr_t* src_addr, int timeout_ms); ​ /* 选项设置 */ ​ /** * brief 设置Socket选项 * * param sock Socket句柄 * param level 选项级别 * param optname 选项名 * param optval 选项值 * param optlen 选项值长度 * return int 0成功-1失败 */ int sock_setopt(socket_t sock, int level, int optname, const void* optval, socklen_t optlen); ​ /** * brief 获取Socket选项 * * param sock Socket句柄 * param level 选项级别 * param optname 选项名 * param optval 输出选项值 * param optlen 输入输出选项值长度 * return int 0成功-1失败 */ int sock_getopt(socket_t sock, int level, int optname, void* optval, socklen_t* optlen); ​ /** * brief 设置非阻塞模式 * * param sock Socket句柄 * param nonblock true非阻塞false阻塞 * return int 0成功-1失败 */ int sock_set_nonblock(socket_t sock, bool nonblock); ​ /** * brief 设置超时 * * param sock Socket句柄 * param send_timeout_ms 发送超时毫秒 * param recv_timeout_ms 接收超时毫秒 * return int 0成功-1失败 */ int sock_set_timeout(socket_t sock, int send_timeout_ms, int recv_timeout_ms); ​ /* 地址处理 */ ​ /** * brief 创建IPv4地址 * * param ip IPv4地址字符串 * param port 端口 * param addr 输出地址 * return int 0成功-1失败 */ int sock_addr_ipv4(const char* ip, uint16_t port, sock_addr_t* addr); ​ /** * brief 创建IPv6地址 * * param ip IPv6地址字符串 * param port 端口 * param addr 输出地址 * return int 0成功-1失败 */ int sock_addr_ipv6(const char* ip, uint16_t port, sock_addr_t* addr); ​ /** * brief 创建Unix域地址 * * param path 文件路径 * param addr 输出地址 * return int 0成功-1失败 */ int sock_addr_unix(const char* path, sock_addr_t* addr); ​ /** * brief 地址转字符串 * * param addr 地址 * param buf 输出缓冲区 * param len 缓冲区长度 * return int 0成功-1失败 */ int sock_addr_str(const sock_addr_t* addr, char* buf, size_t len); ​ /* 工具函数 */ ​ /** * brief 获取错误描述 * * param err 错误码 * return const char* 错误描述 */ const char* sock_strerror(int err); ​ /** * brief 检查Socket是否有效 * * param sock Socket句柄 * return true 有效 * return false 无效 */ bool sock_valid(socket_t sock); ​ /** * brief 获取Socket文件描述符直接返回 * * param sock Socket句柄 * return int 文件描述符 */ static inline int sock_fd(socket_t sock) { return sock; } ​ #ifdef __cplusplus } #endif ​ #endif /* SOCKET_H */第三部分实现文件规划3.1 socket_core.c - 核心功能实现主要函数sock_create()- 创建Socketsock_close()- 关闭Socketsock_bind()- 绑定地址sock_connect()- 连接远程sock_listen()- 开始监听sock_accept()- 接受连接3.2 socket_io.c - 数据IO实现主要函数sock_send()- TCP发送sock_recv()- TCP接收sock_sendto()- UDP发送sock_recvfrom()- UDP接收3.3 socket_opt.c - 选项设置实现主要函数sock_setopt()- 设置选项sock_getopt()- 获取选项sock_set_nonblock()- 设置非阻塞sock_set_timeout()- 设置超时3.4 socket_util.c - 工具函数实现主要函数sock_addr_ipv4()- 创建IPv4地址sock_addr_ipv6()- 创建IPv6地址sock_addr_unix()- 创建Unix地址sock_addr_str()- 地址转字符串sock_strerror()- 错误描述第四部分设计原则总结极简主义只做最必要的功能直接映射Socket句柄就是文件描述符零封装不隐藏系统调用只是简化使用无状态不需要全局初始化可选线程安全依赖基础库的线程安全错误透明直接传递errno这样的设计学习成本低调试容易性能接近原生兼容性好维护简单第二阶段 代码实现第一部分socket_core.c 实现/** * file socket_core.c * brief Socket核心功能实现 * * 实现Socket的创建、绑定、连接、监听和接受连接等核心功能。 * 基于Linux系统调用使用基础库进行错误处理和线程安全。 * * version 1.0 * date 2024-01-01 * copyright Copyright (c) 2024 */ ​ #include socket.h #include stdlib.h #include string.h #include unistd.h #include sys/socket.h #include sys/un.h #include netinet/in.h #include arpa/inet.h #include fcntl.h #include errno.h #include poll.h ​ /* 内部辅助函数 */ ​ /** * brief 将地址族转换为系统AF值 * * param family 地址族 * return int 系统AF值失败返回-1 */ static int family_to_af(sock_family_t family) { switch (family) { case SOCK_AF_INET: return AF_INET; case SOCK_AF_INET6: return AF_INET6; case SOCK_AF_UNIX: return AF_UNIX; default: return -1; } } ​ /** * brief 将Socket类型转换为系统SOCK值 * * param type Socket类型 * return int 系统SOCK值失败返回-1 */ static int type_to_sock(sock_type_t type) { switch (type) { case SOCK_TYPE_STREAM: return SOCK_STREAM; case SOCK_TYPE_DGRAM: return SOCK_DGRAM; default: return -1; } } ​ /** * brief 获取协议号 * * param type Socket类型 * return int 协议号0表示默认 */ static int get_protocol(sock_type_t type) { switch (type) { case SOCK_TYPE_STREAM: return IPPROTO_TCP; case SOCK_TYPE_DGRAM: return IPPROTO_UDP; default: return 0; } } ​ /** * brief 将地址结构转换为系统地址结构 * * param addr 地址结构 * param sys_addr 输出系统地址结构 * param addrlen 输出地址长度 * return int 0成功-1失败 */ static int addr_to_sys(const sock_addr_t* addr, struct sockaddr* sys_addr, socklen_t* addrlen) { if (!addr || !sys_addr || !addrlen) { errno EINVAL; return -1; } switch (addr-family) { case SOCK_AF_INET: { struct sockaddr_in* in_addr (struct sockaddr_in*)sys_addr; memset(in_addr, 0, sizeof(*in_addr)); in_addr-sin_family AF_INET; in_addr-sin_addr.s_addr addr-u.ipv4.addr; in_addr-sin_port addr-u.ipv4.port; *addrlen sizeof(*in_addr); return 0; } case SOCK_AF_INET6: { struct sockaddr_in6* in6_addr (struct sockaddr_in6*)sys_addr; memset(in6_addr, 0, sizeof(*in6_addr)); in6_addr-sin6_family AF_INET6; memcpy(in6_addr-sin6_addr, addr-u.ipv6.addr, 16); in6_addr-sin6_port addr-u.ipv6.port; *addrlen sizeof(*in6_addr); return 0; } case SOCK_AF_UNIX: { struct sockaddr_un* un_addr (struct sockaddr_un*)sys_addr; memset(un_addr, 0, sizeof(*un_addr)); un_addr-sun_family AF_UNIX; strncpy(un_addr-sun_path, addr-u.unix.path, sizeof(un_addr-sun_path) - 1); *addrlen sizeof(*un_addr); return 0; } default: errno EAFNOSUPPORT; return -1; } } ​ /** * brief 将系统地址结构转换为地址结构 * * param sys_addr 系统地址结构 * param addrlen 地址长度 * param addr 输出地址结构 * return int 0成功-1失败 */ static int addr_from_sys(const struct sockaddr* sys_addr, socklen_t addrlen, sock_addr_t* addr) { if (!sys_addr || !addr) { errno EINVAL; return -1; } memset(addr, 0, sizeof(*addr)); switch (sys_addr-sa_family) { case AF_INET: { const struct sockaddr_in* in_addr (const struct sockaddr_in*)sys_addr; addr-family SOCK_AF_INET; addr-u.ipv4.addr in_addr-sin_addr.s_addr; addr-u.ipv4.port in_addr-sin_port; return 0; } case AF_INET6: { const struct sockaddr_in6* in6_addr (const struct sockaddr_in6*)sys_addr; addr-family SOCK_AF_INET6; memcpy(addr-u.ipv6.addr, in6_addr-sin6_addr, 16); addr-u.ipv6.port in6_addr-sin6_port; return 0; } case AF_UNIX: { const struct sockaddr_un* un_addr (const struct sockaddr_un*)sys_addr; addr-family SOCK_AF_UNIX; strncpy(addr-u.unix.path, un_addr-sun_path, sizeof(addr-u.unix.path) - 1); return 0; } default: errno EAFNOSUPPORT; return -1; } } ​ /** * brief 检查Socket有效性 * * param sock Socket句柄 * return int 0有效-1无效 */ static int check_socket(socket_t sock) { if (sock SOCKET_INVALID) { errno EBADF; return -1; } int error 0; socklen_t len sizeof(error); if (getsockopt(sock, SOL_SOCKET, SO_ERROR, error, len) 0) { return -1; } if (error ! 0) { errno error; return -1; } return 0; } ​ /** * brief 轮询等待事件 * * param fd 文件描述符 * param events 等待的事件POLLIN/POLLOUT * param timeout_ms 超时时间毫秒 * return int 0有事件0超时-1错误 */ static int poll_wait(int fd, short events, int timeout_ms) { struct pollfd pfd; pfd.fd fd; pfd.events events; pfd.revents 0; int ret poll(pfd, 1, timeout_ms); if (ret 0) { return -1; } else if (ret 0) { errno ETIMEDOUT; return 0; } if (pfd.revents (POLLERR | POLLHUP | POLLNVAL)) { errno ECONNREFUSED; return -1; } return ret; } ​ /* 公开API实现 */ ​ /** * brief 创建Socket * * param family 地址族SOCK_AF_INET/SOCK_AF_INET6/SOCK_AF_UNIX * param type Socket类型SOCK_TYPE_STREAM/SOCK_TYPE_DGRAM * return socket_t Socket句柄失败返回SOCKET_INVALID */ socket_t sock_create(sock_family_t family, sock_type_t type) { int af family_to_af(family); int sock_type type_to_sock(type); int protocol get_protocol(type); if (af -1 || sock_type -1) { errno EINVAL; return SOCKET_INVALID; } int fd socket(af, sock_type, protocol); if (fd 0) { return SOCKET_INVALID; } /* 设置一些默认选项 */ int reuse 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, reuse, sizeof(reuse)); /* 对于TCP设置NODELAY减少延迟 */ if (type SOCK_TYPE_STREAM) { int nodelay 1; setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, nodelay, sizeof(nodelay)); } LOG_DEBUG(SOCKET, Created socket fd%d, family%d, type%d, fd, family, type); return fd; } ​ /** * brief 关闭Socket * * param sock Socket句柄 * return int 0成功-1失败 */ int sock_close(socket_t sock) { if (sock SOCKET_INVALID) { errno EBADF; return -1; } /* 先尝试正常关闭 */ if (shutdown(sock, SHUT_RDWR) 0) { if (errno ! ENOTCONN errno ! EINVAL) { LOG_WARN(SOCKET, shutdown failed on fd%d: %s, sock, strerror(errno)); } } /* 关闭文件描述符 */ if (close(sock) 0) { LOG_ERROR(SOCKET, close failed on fd%d: %s, sock, strerror(errno)); return -1; } LOG_DEBUG(SOCKET, Closed socket fd%d, sock); return 0; } ​ /** * brief 复制Socket * * param sock 源Socket * return socket_t 新Socket失败返回SOCKET_INVALID */ socket_t sock_dup(socket_t sock) { if (sock SOCKET_INVALID) { errno EBADF; return SOCKET_INVALID; } int new_fd dup(sock); if (new_fd 0) { return SOCKET_INVALID; } LOG_DEBUG(SOCKET, Duplicated socket fd%d - fd%d, sock, new_fd); return new_fd; } ​ /** * brief 绑定地址 * * param sock Socket句柄 * param addr 地址 * return int 0成功-1失败 */ int sock_bind(socket_t sock, const sock_addr_t* addr) { if (sock SOCKET_INVALID || !addr) { errno EINVAL; return -1; } struct sockaddr_storage sys_addr; socklen_t addrlen; if (addr_to_sys(addr, (struct sockaddr*)sys_addr, addrlen) 0) { return -1; } /* Unix域Socket需要删除已存在的文件 */ if (addr-family SOCK_AF_UNIX) { unlink(addr-u.unix.path); } if (bind(sock, (struct sockaddr*)sys_addr, addrlen) 0) { LOG_ERROR(SOCKET, bind failed on fd%d: %s, sock, strerror(errno)); return -1; } LOG_DEBUG(SOCKET, Bound socket fd%d to address, sock); return 0; } ​ /** * brief 连接到远程 * * param sock Socket句柄 * param addr 远程地址 * param timeout_ms 超时时间毫秒0表示阻塞 * return int 0成功-1失败 */ int sock_connect(socket_t sock, const sock_addr_t* addr, int timeout_ms) { if (sock SOCKET_INVALID || !addr) { errno EINVAL; return -1; } /* 检查Socket状态 */ if (check_socket(sock) 0) { return -1; } struct sockaddr_storage sys_addr; socklen_t addrlen; if (addr_to_sys(addr, (struct sockaddr*)sys_addr, addrlen) 0) { return -1; } /* 如果需要超时先设置为非阻塞 */ int flags 0; int need_restore 0; if (timeout_ms 0) { flags fcntl(sock, F_GETFL, 0); if (flags 0) { return -1; } if (!(flags O_NONBLOCK)) { if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) 0) { return -1; } need_restore 1; } } /* 尝试连接 */ int ret connect(sock, (struct sockaddr*)sys_addr, addrlen); if (ret 0) { if (errno EINPROGRESS) { /* 非阻塞连接等待完成 */ if (timeout_ms 0) { ret poll_wait(sock, POLLOUT, timeout_ms); if (ret 0) { if (need_restore) { fcntl(sock, F_SETFL, flags); } return ret; } /* 检查连接是否成功 */ int error 0; socklen_t len sizeof(error); if (getsockopt(sock, SOL_SOCKET, SO_ERROR, error, len) 0) { if (need_restore) { fcntl(sock, F_SETFL, flags); } return -1; } if (error ! 0) { errno error; if (need_restore) { fcntl(sock, F_SETFL, flags); } return -1; } } else { /* 没有超时连接会阻塞直到完成 */ if (need_restore) { fcntl(sock, F_SETFL, flags); } errno EINPROGRESS; return -1; } } else { /* 其他连接错误 */ if (need_restore) { fcntl(sock, F_SETFL, flags); } LOG_ERROR(SOCKET, connect failed on fd%d: %s, sock, strerror(errno)); return -1; } } /* 恢复原来的标志 */ if (need_restore) { fcntl(sock, F_SETFL, flags); } LOG_DEBUG(SOCKET, Connected socket fd%d, sock); return 0; } ​ /** * brief 开始监听 * * param sock Socket句柄 * param backlog 等待连接队列长度 * return int 0成功-1失败 */ int sock_listen(socket_t sock, int backlog) { if (sock SOCKET_INVALID) { errno EINVAL; return -1; } if (backlog 0) { backlog 128; /* 默认值 */ } if (listen(sock, backlog) 0) { LOG_ERROR(SOCKET, listen failed on fd%d: %s, sock, strerror(errno)); return -1; } LOG_DEBUG(SOCKET, Listening on socket fd%d, backlog%d, sock, backlog); return 0; } ​ /** * brief 接受连接 * * param sock 监听Socket * param client_addr 输出客户端地址可为NULL * param timeout_ms 超时时间毫秒0表示阻塞 * return socket_t 客户端Socket失败返回SOCKET_INVALID */ socket_t sock_accept(socket_t sock, sock_addr_t* client_addr, int timeout_ms) { if (sock SOCKET_INVALID) { errno EINVAL; return SOCKET_INVALID; } /* 如果需要超时先轮询等待 */ if (timeout_ms 0) { int ret poll_wait(sock, POLLIN, timeout_ms); if (ret 0) { return SOCKET_INVALID; } } struct sockaddr_storage addr; socklen_t addrlen sizeof(addr); int client_fd accept(sock, (struct sockaddr*)addr, addrlen); if (client_fd 0) { LOG_ERROR(SOCKET, accept failed on fd%d: %s, sock, strerror(errno)); return SOCKET_INVALID; } /* 转换客户端地址 */ if (client_addr) { if (addr_from_sys((struct sockaddr*)addr, addrlen, client_addr) 0) { LOG_WARN(SOCKET, Failed to convert client address); } } /* 设置一些选项 */ int reuse 1; setsockopt(client_fd, SOL_SOCKET, SO_REUSEADDR, reuse, sizeof(reuse)); LOG_DEBUG(SOCKET, Accepted connection fd%d from listening fd%d, client_fd, sock); return client_fd; } ​ /** * brief 初始化Socket库可选 * * return int 0成功-1失败 */ int sock_init(void) { /* Linux下不需要特殊的初始化 */ LOG_INFO(SOCKET, Socket library initialized); return 0; } ​ /** * brief 清理Socket库 */ void sock_cleanup(void) { /* Linux下不需要特殊的清理 */ LOG_INFO(SOCKET, Socket library cleaned up); } ​ /** * brief 检查Socket是否有效 * * param sock Socket句柄 * return true 有效 * return false 无效 */ bool sock_valid(socket_t sock) { return (sock ! SOCKET_INVALID check_socket(sock) 0); }第二部分socket_io.c 实现/** * file socket_io.c * brief Socket数据IO实现 * * 实现Socket的数据发送和接收功能支持TCP和UDP。 * 提供超时控制和错误处理。 * * version 1.0 * date 2024-01-01 * copyright Copyright (c) 2024 */ ​ #include socket.h #include stdlib.h #include string.h #include unistd.h #include sys/socket.h #include sys/time.h #include errno.h #include poll.h ​ /* 内部辅助函数 */ ​ /** * brief 设置Socket超时 * * param sock Socket句柄 * param send_timeout_ms 发送超时毫秒 * param recv_timeout_ms 接收超时毫秒 * return int 0成功-1失败 */ static int set_socket_timeout(socket_t sock, int send_timeout_ms, int recv_timeout_ms) { struct timeval tv; /* 设置发送超时 */ if (send_timeout_ms 0) { tv.tv_sec send_timeout_ms / 1000; tv.tv_usec (send_timeout_ms % 1000) * 1000; if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, tv, sizeof(tv)) 0) { return -1; } } /* 设置接收超时 */ if (recv_timeout_ms 0) { tv.tv_sec recv_timeout_ms / 1000; tv.tv_usec (recv_timeout_ms % 1000) * 1000; if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, tv, sizeof(tv)) 0) { return -1; } } return 0; } ​ /** * brief 等待Socket可读或可写 * * param sock Socket句柄 * param for_read true等待可读false等待可写 * param timeout_ms 超时时间毫秒 * return int 0可操作0超时-1错误 */ static int wait_socket(socket_t sock, bool for_read, int timeout_ms) { short events for_read ? POLLIN : POLLOUT; return poll_wait(sock, events, timeout_ms); } ​ /** * brief 安全的发送数据处理EINTR * * param sock Socket句柄 * param buf 数据缓冲区 * param len 数据长度 * param flags 发送标志 * return ssize_t 发送的字节数-1失败 */ static ssize_t safe_send(socket_t sock, const void* buf, size_t len, int flags) { ssize_t sent; do { sent send(sock, buf, len, flags); } while (sent 0 errno EINTR); return sent; } ​ /** * brief 安全的接收数据处理EINTR * * param sock Socket句柄 * param buf 接收缓冲区 * param len 缓冲区长度 * param flags 接收标志 * return ssize_t 接收的字节数-1失败0连接关闭 */ static ssize_t safe_recv(socket_t sock, void* buf, size_t len, int flags) { ssize_t received; do { received recv(sock, buf, len, flags); } while (received 0 errno EINTR); return received; } ​ /** * brief 安全的发送到地址处理EINTR * * param sock Socket句柄 * param buf 数据缓冲区 * param len 数据长度 * param flags 发送标志 * param addr 目标地址 * param addrlen 地址长度 * return ssize_t 发送的字节数-1失败 */ static ssize_t safe_sendto(socket_t sock, const void* buf, size_t len, int flags, const struct sockaddr* addr, socklen_t addrlen) { ssize_t sent; do { sent sendto(sock, buf, len, flags, addr, addrlen); } while (sent 0 errno EINTR); return sent; } ​ /** * brief 安全的从地址接收处理EINTR * * param sock Socket句柄 * param buf 接收缓冲区 * param len 缓冲区长度 * param flags 接收标志 * param addr 输出源地址 * param addrlen 输入输出地址长度 * return ssize_t 接收的字节数-1失败 */ static ssize_t safe_recvfrom(socket_t sock, void* buf, size_t len, int flags, struct sockaddr* addr, socklen_t* addrlen) { ssize_t received; do { received recvfrom(sock, buf, len, flags, addr, addrlen); } while (received 0 errno EINTR); return received; } ​ /* 公开API实现 */ ​ /** * brief 发送数据TCP * * param sock Socket句柄 * param buf 数据缓冲区 * param len 数据长度 * param timeout_ms 超时时间毫秒0表示阻塞 * return ssize_t 发送的字节数-1失败 */ ssize_t sock_send(socket_t sock, const void* buf, size_t len, int timeout_ms) { if (sock SOCKET_INVALID || !buf || len 0) { errno EINVAL; return -1; } /* 检查Socket状态 */ if (check_socket(sock) 0) { return -1; } /* 设置临时超时 */ int saved_send_timeout -1; socklen_t optlen sizeof(saved_send_timeout); if (timeout_ms 0) { /* 保存原来的发送超时 */ getsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, saved_send_timeout, optlen); /* 设置新的发送超时 */ if (set_socket_timeout(sock, timeout_ms, -1) 0) { return -1; } } /* 发送数据 */ ssize_t sent safe_send(sock, buf, len, 0); /* 恢复原来的超时设置 */ if (timeout_ms 0 saved_send_timeout 0) { struct timeval tv; tv.tv_sec saved_send_timeout / 1000000; tv.tv_usec saved_send_timeout % 1000000; setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, tv, sizeof(tv)); } if (sent 0) { if (errno EAGAIN || errno EWOULDBLOCK) { errno ETIMEDOUT; } LOG_DEBUG(SOCKET, send failed on fd%d: %s, sock, strerror(errno)); return -1; } LOG_DEBUG(SOCKET, Sent %zd bytes on fd%d, sent, sock); return sent; } ​ /** * brief 接收数据TCP * * param sock Socket句柄 * param buf 接收缓冲区 * param len 缓冲区长度 * param timeout_ms 超时时间毫秒0表示阻塞 * return ssize_t 接收的字节数-1失败0连接关闭 */ ssize_t sock_recv(socket_t sock, void* buf, size_t len, int timeout_ms) { if (sock SOCKET_INVALID || !buf || len 0) { errno EINVAL; return -1; } /* 检查Socket状态 */ if (check_socket(sock) 0) { return -1; } /* 如果需要超时先等待数据可读 */ if (timeout_ms 0) { int ret wait_socket(sock, true, timeout_ms); if (ret 0) { return ret; /* 0表示超时-1表示错误 */ } } /* 接收数据 */ ssize_t received safe_recv(sock, buf, len, 0); if (received 0) { if (errno EAGAIN || errno EWOULDBLOCK) { errno ETIMEDOUT; } LOG_DEBUG(SOCKET, recv failed on fd%d: %s, sock, strerror(errno)); return -1; } else if (received 0) { LOG_DEBUG(SOCKET, Connection closed on fd%d, sock); return 0; } LOG_DEBUG(SOCKET, Received %zd bytes on fd%d, received, sock); return received; } ​ /** * brief 发送数据到地址UDP * * param sock Socket句柄 * param buf 数据缓冲区 * param len 数据长度 * param addr 目标地址 * return ssize_t 发送的字节数-1失败 */ ssize_t sock_sendto(socket_t sock, const void* buf, size_t len, const sock_addr_t* addr) { if (sock SOCKET_INVALID || !buf || len 0 || !addr) { errno EINVAL; return -1; } struct sockaddr_storage sys_addr; socklen_t addrlen; if (addr_to_sys(addr, (struct sockaddr*)sys_addr, addrlen) 0) { return -1; } /* 发送数据 */ ssize_t sent safe_sendto(sock, buf, len, 0, (struct sockaddr*)sys_addr, addrlen); if (sent 0) { if (errno EMSGSIZE) { LOG_WARN(SOCKET, Message too large on fd%d, sock); } else { LOG_DEBUG(SOCKET, sendto failed on fd%d: %s, sock, strerror(errno)); } return -1; } LOG_DEBUG(SOCKET, Sent %zd bytes via UDP on fd%d, sent, sock); return sent; } ​ /** * brief 从地址接收数据UDP * * param sock Socket句柄 * param buf 接收缓冲区 * param len 缓冲区长度 * param src_addr 输出源地址可为NULL * param timeout_ms 超时时间毫秒0表示阻塞 * return ssize_t 接收的字节数-1失败 */ ssize_t sock_recvfrom(socket_t sock, void* buf, size_t len, sock_addr_t* src_addr, int timeout_ms) { if (sock SOCKET_INVALID || !buf || len 0) { errno EINVAL; return -1; } /* 如果需要超时先等待数据可读 */ if (timeout_ms 0) { int ret wait_socket(sock, true, timeout_ms); if (ret 0) { return ret; /* 0表示超时-1表示错误 */ } } struct sockaddr_storage addr; socklen_t addrlen sizeof(addr); /* 接收数据 */ ssize_t received safe_recvfrom(sock, buf, len, 0, (struct sockaddr*)addr, addrlen); if (received 0) { if (errno EAGAIN || errno EWOULDBLOCK) { errno ETIMEDOUT; } LOG_DEBUG(SOCKET, recvfrom failed on fd%d: %s, sock, strerror(errno)); return -1; } /* 转换源地址 */ if (src_addr received 0) { if (addr_from_sys((struct sockaddr*)addr, addrlen, src_addr) 0) { LOG_WARN(SOCKET, Failed to convert source address); } } LOG_DEBUG(SOCKET, Received %zd bytes via UDP on fd%d, received, sock); return received; }第三部分socket_opt.c 实现/** * file socket_opt.c * brief Socket选项设置实现 * * 实现Socket选项的设置和获取功能包括非阻塞模式、超时设置等。 * 提供常用选项的便捷接口。 * * version 1.0 * date 2024-01-01 * copyright Copyright (c) 2024 */ ​ #include socket.h #include stdlib.h #include string.h #include unistd.h #include sys/socket.h #include netinet/in.h #include netinet/tcp.h #include fcntl.h #include errno.h ​ /* 内部辅助函数 */ ​ /** * brief 检查Socket句柄有效性 * * param sock Socket句柄 * return int 0有效-1无效 */ static int validate_socket(socket_t sock) { if (sock SOCKET_INVALID) { errno EBADF; return -1; } /* 使用fstat检查文件描述符是否有效 */ struct stat st; if (fstat(sock, st) 0) { return -1; } return 0; } ​ /** * brief 获取当前Socket标志 * * param sock Socket句柄 * param flags 输出标志 * return int 0成功-1失败 */ static int get_socket_flags(socket_t sock, int* flags) { if (!flags) { errno EINVAL; return -1; } *flags fcntl(sock, F_GETFL, 0); if (*flags 0) { return -1; } return 0; } ​ /** * brief 设置Socket标志 * * param sock Socket句柄 * param flags 新标志 * return int 0成功-1失败 */ static int set_socket_flags(socket_t sock, int flags) { if (fcntl(sock, F_SETFL, flags) 0) { return -1; } return 0; } ​ /** * brief 设置超时值 * * param sock Socket句柄 * param level 选项级别 * param optname 选项名称 * param timeout_ms 超时时间毫秒 * return int 0成功-1失败 */ static int set_timeout_option(socket_t sock, int level, int optname, int timeout_ms) { struct timeval tv; if (timeout_ms 0) { /* 不修改超时设置 */ return 0; } tv.tv_sec timeout_ms / 1000; tv.tv_usec (timeout_ms % 1000) * 1000; if (setsockopt(sock, level, optname, tv, sizeof(tv)) 0) { return -1; } return 0; } ​ /** * brief 获取超时值 * * param sock Socket句柄 * param level 选项级别 * param optname 选项名称 * param timeout_ms 输出超时时间毫秒 * return int 0成功-1失败 */ static int get_timeout_option(socket_t sock, int level, int optname, int* timeout_ms) { struct timeval tv; socklen_t len sizeof(tv); if (!timeout_ms) { errno EINVAL; return -1; } if (getsockopt(sock, level, optname, tv, len) 0) { return -1; } *timeout_ms (int)(tv.tv_sec * 1000 tv.tv_usec / 1000); return 0; } ​ /* 公开API实现 */ ​ /** * brief 设置Socket选项 * * param sock Socket句柄 * param level 选项级别 * param optname 选项名 * param optval 选项值 * param optlen 选项值长度 * return int 0成功-1失败 */ int sock_setopt(socket_t sock, int level, int optname, const void* optval, socklen_t optlen) { if (sock SOCKET_INVALID || !optval || optlen 0) { errno EINVAL; return -1; } if (validate_socket(sock) 0) { return -1; } if (setsockopt(sock, level, optname, optval, optlen) 0) { LOG_DEBUG(SOCKET, setsockopt failed on fd%d: %s, sock, strerror(errno)); return -1; } LOG_DEBUG(SOCKET, Set option fd%d, level%d, optname%d, sock, level, optname); return 0; } ​ /** * brief 获取Socket选项 * * param sock Socket句柄 * param level 选项级别 * param optname 选项名 * param optval 输出选项值 * param optlen 输入输出选项值长度 * return int 0成功-1失败 */ int sock_getopt(socket_t sock, int level, int optname, void* optval, socklen_t* optlen) { if (sock SOCKET_INVALID || !optval || !optlen || *optlen 0) { errno EINVAL; return -1; } if (validate_socket(sock) 0) { return -1; } if (getsockopt(sock, level, optname, optval, optlen) 0) { LOG_DEBUG(SOCKET, getsockopt failed on fd%d: %s, sock, strerror(errno)); return -1; } LOG_DEBUG(SOCKET, Got option fd%d, level%d, optname%d, sock, level, optname); return 0; } ​ /** * brief 设置非阻塞模式 * * param sock Socket句柄 * param nonblock true非阻塞false阻塞 * return int 0成功-1失败 */ int sock_set_nonblock(socket_t sock, bool nonblock) { if (sock SOCKET_INVALID) { errno EINVAL; return -1; } if (validate_socket(sock) 0) { return -1; } int flags; if (get_socket_flags(sock, flags) 0) { return -1; } if (nonblock) { flags | O_NONBLOCK; } else { flags ~O_NONBLOCK; } if (set_socket_flags(sock, flags) 0) { return -1; } LOG_DEBUG(SOCKET, Set nonblock%s on fd%d, nonblock ? true : false, sock); return 0; } ​ /** * brief 设置超时 * * param sock Socket句柄 * param send_timeout_ms 发送超时毫秒 * param recv_timeout_ms 接收超时毫秒 * return int 0成功-1失败 */ int sock_set_timeout(socket_t sock, int send_timeout_ms, int recv_timeout_ms) { if (sock SOCKET_INVALID) { errno EINVAL; return -1; } if (validate_socket(sock) 0) { return -1; } /* 设置发送超时 */ if (set_timeout_option(sock, SOL_SOCKET, SO_SNDTIMEO, send_timeout_ms) 0) { LOG_WARN(SOCKET, Failed to set send timeout on fd%d: %s, sock, strerror(errno)); } /* 设置接收超时 */ if (set_timeout_option(sock, SOL_SOCKET, SO_RCVTIMEO, recv_timeout_ms) 0) { LOG_WARN(SOCKET, Failed to set recv timeout on fd%d: %s, sock, strerror(errno)); } LOG_DEBUG(SOCKET, Set timeout on fd%d: send%dms, recv%dms, sock, send_timeout_ms, recv_timeout_ms); return 0; } ​ /** * brief 获取发送超时 * * param sock Socket句柄 * param timeout_ms 输出发送超时毫秒 * return int 0成功-1失败 */ int sock_get_send_timeout(socket_t sock, int* timeout_ms) { if (sock SOCKET_INVALID || !timeout_ms) { errno EINVAL; return -1; } return get_timeout_option(sock, SOL_SOCKET, SO_SNDTIMEO, timeout_ms); } ​ /** * brief 获取接收超时 * * param sock Socket句柄 * param timeout_ms 输出接收超时毫秒 * return int 0成功-1失败 */ int sock_get_recv_timeout(socket_t sock, int* timeout_ms) { if (sock SOCKET_INVALID || !timeout_ms) { errno EINVAL; return -1; } return get_timeout_option(sock, SOL_SOCKET, SO_RCVTIMEO, timeout_ms); } ​ /** * brief 设置地址重用选项 * * param sock Socket句柄 * param reuse 是否启用地址重用 * return int 0成功-1失败 */ int sock_set_reuseaddr(socket_t sock, bool reuse) { if (sock SOCKET_INVALID) { errno EINVAL; return -1; } int optval reuse ? 1 : 0; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, optval, sizeof(optval)) 0) { LOG_DEBUG(SOCKET, Failed to set SO_REUSEADDR on fd%d: %s, sock, strerror(errno)); return -1; } LOG_DEBUG(SOCKET, Set SO_REUSEADDR%d on fd%d, optval, sock); return 0; } ​ /** * brief 设置端口重用选项 * * param sock Socket句柄 * param reuse 是否启用端口重用 * return int 0成功-1失败 */ int sock_set_reuseport(socket_t sock, bool reuse) { if (sock SOCKET_INVALID) { errno EINVAL; return -1; } int optval reuse ? 1 : 0; #ifdef SO_REUSEPORT if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, optval, sizeof(optval)) 0) { LOG_DEBUG(SOCKET, Failed to set SO_REUSEPORT on fd%d: %s, sock, strerror(errno)); return -1; } LOG_DEBUG(SOCKET, Set SO_REUSEPORT%d on fd%d, optval, sock); return 0; #else LOG_WARN(SOCKET, SO_REUSEPORT not supported on this system); errno ENOPROTOOPT; return -1; #endif } ​ /** * brief 设置TCP NODELAY选项 * * param sock Socket句柄 * param nodelay 是否禁用Nagle算法 * return int 0成功-1失败 */ int sock_set_tcp_nodelay(socket_t sock, bool nodelay) { if (sock SOCKET_INVALID) { errno EINVAL; return -1; } int optval nodelay ? 1 : 0; if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, optval, sizeof(optval)) 0) { LOG_DEBUG(SOCKET, Failed to set TCP_NODELAY on fd%d: %s, sock, strerror(errno)); return -1; } LOG_DEBUG(SOCKET, Set TCP_NODELAY%d on fd%d, optval, sock); return 0; } ​ /** * brief 设置保持连接选项 * * param sock Socket句柄 * param keepalive 是否启用保持连接 * return int 0成功-1失败 */ int sock_set_keepalive(socket_t sock, bool keepalive) { if (sock SOCKET_INVALID) { errno EINVAL; return -1; } int optval keepalive ? 1 : 0; if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, optval, sizeof(optval)) 0) { LOG_DEBUG(SOCKET, Failed to set SO_KEEPALIVE on fd%d: %s, sock, strerror(errno)); return -1; } LOG_DEBUG(SOCKET, Set SO_KEEPALIVE%d on fd%d, optval, sock); return 0; } ​ /** * brief 设置发送缓冲区大小 * * param sock Socket句柄 * param size 缓冲区大小字节 * return int 0成功-1失败 */ int sock_set_send_buffer(socket_t sock, int size) { if (sock SOCKET_INVALID || size 0) { errno EINVAL; return -1; } if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, size, sizeof(size)) 0) { LOG_DEBUG(SOCKET, Failed to set SO_SNDBUF on fd%d: %s, sock, strerror(errno)); return -1; } LOG_DEBUG(SOCKET, Set SO_SNDBUF%d on fd%d, size, sock); return 0; } ​ /** * brief 设置接收缓冲区大小 * * param sock Socket句柄 * param size 缓冲区大小字节 * return int 0成功-1失败 */ int sock_set_recv_buffer(socket_t sock, int size) { if (sock SOCKET_INVALID || size 0) { errno EINVAL; return -1; } if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, size, sizeof(size)) 0) { LOG_DEBUG(SOCKET, Failed to set SO_RCVBUF on fd%d: %s, sock, strerror(errno)); return -1; } LOG_DEBUG(SOCKET, Set SO_RCVBUF%d on fd%d, size, sock); return 0; } ​ /** * brief 设置Linger选项 * * param sock Socket句柄 * param enable 是否启用Linger * param timeout_sec 超时时间秒 * return int 0成功-1失败 */ int sock_set_linger(socket_t sock, bool enable, int timeout_sec) { if (sock SOCKET_INVALID) { errno EINVAL; return -1; } struct linger l; l.l_onoff enable ? 1 : 0; l.l_linger timeout_sec; if (setsockopt(sock, SOL_SOCKET, SO_LINGER, l, sizeof(l)) 0) { LOG_DEBUG(SOCKET, Failed to set SO_LINGER on fd%d: %s, sock, strerror(errno)); return -1; } LOG_DEBUG(SOCKET, Set SO_LINGER: onoff%d, linger%d on fd%d, l.l_onoff, l.l_linger, sock); return 0; } ​ /** * brief 获取Socket错误状态 * * param sock Socket句柄 * param error 输出错误码 * return int 0成功-1失败 */ int sock_get_error(socket_t sock, int* error) { if (sock SOCKET_INVALID || !error) { errno EINVAL; return -1; } socklen_t len sizeof(*error); if (getsockopt(sock, SOL_SOCKET, SO_ERROR, error, len) 0) { return -1; } return 0; }第四部分socket_util.c 实现/** * file socket_util.c * brief Socket工具函数实现 * * 实现地址处理、错误处理等工具函数。 * 提供便捷的地址创建和转换功能。 * * version 1.0 * date 2024-01-01 * copyright Copyright (c) 2024 */ ​ #include socket.h #include stdlib.h #include string.h #include unistd.h #include sys/socket.h #include netinet/in.h #include arpa/inet.h #include netdb.h #include errno.h ​ /* 内部辅助函数 */ ​ /** * brief 解析主机名 * * param host 主机名或IP地址 * param addr 输出IPv4地址 * return int 0成功-1失败 */ static int resolve_hostname(const char* host, struct in_addr* addr) { if (!host || !addr) { return -1; } /* 首先尝试直接解析为IP地址 */ if (inet_pton(AF_INET, host, addr) 1) { return 0; } /* 如果失败尝试通过DNS解析 */ struct addrinfo hints, *result NULL; memset(hints, 0, sizeof(hints)); hints.ai_family AF_INET; hints.ai_socktype SOCK_STREAM; int ret getaddrinfo(host, NULL, hints, result); if (ret ! 0) { return -1; } /* 获取第一个IPv4地址 */ struct addrinfo* p; for (p result; p ! NULL; p p-ai_next) { if (p-ai_family AF_INET) { struct sockaddr_in* sin (struct sockaddr_in*)p-ai_addr; *addr sin-sin_addr; freeaddrinfo(result); return 0; } } freeaddrinfo(result); return -1; } ​ /** * brief 解析IPv6主机名 * * param host 主机名或IPv6地址 * param addr 输出IPv6地址 * return int 0成功-1失败 */ static int resolve_hostname_ipv6(const char* host, struct in6_addr* addr) { if (!host || !addr) { return -1; } /* 首先尝试直接解析为IPv6地址 */ if (inet_pton(AF_INET6, host, addr) 1) { return 0; } /* 如果失败尝试通过DNS解析 */ struct addrinfo hints, *result NULL; memset(hints, 0, sizeof(hints)); hints.ai_family AF_INET6; hints.ai_socktype SOCK_STREAM; int ret getaddrinfo(host, NULL, hints, result); if (ret ! 0) { return -1; } /* 获取第一个IPv6地址 */ struct addrinfo* p; for (p result; p ! NULL; p p-ai_next) { if (p-ai_family AF_INET6) { struct sockaddr_in6* sin6 (struct sockaddr_in6*)p-ai_addr; *addr sin6-sin6_addr; freeaddrinfo(result); return 0; } } freeaddrinfo(result); return -1; } ​ /** * brief 检查Unix域Socket路径长度 * * param path 路径 * return int 0有效-1过长 */ static int check_unix_path_length(const char* path) { if (!path) { return -1; } size_t len strlen(path); if (len sizeof(((struct sockaddr_un*)0)-sun_path)) { return -1; } return 0; } ​ /* 公开API实现 */ ​ /** * brief 创建IPv4地址 * * param ip IPv4地址字符串 * param port 端口 * param addr 输出地址 * return int 0成功-1失败 */ int sock_addr_ipv4(const char* ip, uint16_t port, sock_addr_t* addr) { if (!ip || !addr) { errno EINVAL; return -1; } memset(addr, 0, sizeof(*addr)); addr-family SOCK_AF_INET; addr-u.ipv4.port htons(port); struct in_addr in_addr; if (resolve_hostname(ip, in_addr) 0) { errno EINVAL; return -1; } addr-u.ipv4.addr in_addr.s_addr; return 0; } ​ /** * brief 创建IPv6地址 * * param ip IPv6地址字符串 * param port 端口 * param addr 输出地址 * return int 0成功-1失败 */ int sock_addr_ipv6(const char* ip, uint16_t port, sock_addr_t* addr) { if (!ip || !addr) { errno EINVAL; return -1; } memset(addr, 0, sizeof(*addr)); addr-family SOCK_AF_INET6; addr-u.ipv6.port htons(port); struct in6_addr in6_addr; if (resolve_hostname_ipv6(ip, in6_addr) 0) { errno EINVAL; return -1; } memcpy(addr-u.ipv6.addr, in6_addr, sizeof(in6_addr)); return 0; } ​ /** * brief 创建Unix域地址 * * param path 文件路径 * param addr 输出地址 * return int 0成功-1失败 */ int sock_addr_unix(const char* path, sock_addr_t* addr) { if (!path || !addr) { errno EINVAL; return -1; } /* 检查路径长度 */ if (check_unix_path_length(path) 0) { errno ENAMETOOLONG; return -1; } memset(addr, 0, sizeof(*addr)); addr-family SOCK_AF_UNIX; strncpy(addr-u.unix.path, path, sizeof(addr-u.unix.path) - 1); addr-u.unix.path[sizeof(addr-u.unix.path) - 1] \0; return 0; } ​ /** * brief 地址转字符串 * * param addr 地址 * param buf 输出缓冲区 * param len 缓冲区长度 * return int 0成功-1失败 */ int sock_addr_str(const sock_addr_t* addr, char* buf, size_t len) { if (!addr || !buf || len 0) { errno EINVAL; return -1; } switch (addr-family) { case SOCK_AF_INET: { struct in_addr in_addr; in_addr.s_addr addr-u.ipv4.addr; char ip_str[INET_ADDRSTRLEN]; if (!inet_ntop(AF_INET, in_addr, ip_str, sizeof(ip_str))) { return -1; } uint16_t port ntohs(addr-u.ipv4.port); snprintf(buf, len, %s:%u, ip_str, port); break; } case SOCK_AF_INET6: { struct in6_addr in6_addr; memcpy(in6_addr, addr-u.ipv6.addr, sizeof(in6_addr)); char ip_str[INET6_ADDRSTRLEN]; if (!inet_ntop(AF_INET6, in6_addr, ip_str, sizeof(ip_str))) { return -1; } uint16_t port ntohs(addr-u.ipv6.port); snprintf(buf, len, [%s]:%u, ip_str, port); break; } case SOCK_AF_UNIX: snprintf(buf, len, unix:%s, addr-u.unix.path); break; default: errno EAFNOSUPPORT; return -1; } return 0; } ​ /** * brief 从字符串解析地址 * * param str 地址字符串格式ip:port 或 /path * param addr 输出地址 * return int 0成功-1失败 */ int sock_addr_parse(const char* str, sock_addr_t* addr) { if (!str || !addr) { errno EINVAL; return -1; } /* 尝试解析为Unix域地址 */ if (str[0] /) { return sock_addr_unix(str, addr); } /* 尝试解析为IPv4地址:端口 */ char* colon strchr(str, :); if (colon) { /* 检查是否是IPv6地址包含多个冒号 */ char* second_colon strchr(colon 1, :); if (second_colon str[0] [) { /* IPv6地址格式[::1]:8080 */ char ip_str[INET6_ADDRSTRLEN]; char* end_bracket strchr(str, ]); if (!end_bracket || end_bracket colon) { errno EINVAL; return -1; } /* 提取IP地址部分 */ size_t ip_len end_bracket - str - 1; if (ip_len sizeof(ip_str)) { errno EINVAL; return -1; } strncpy(ip_str, str 1, ip_len); ip_str[ip_len] \0; /* 提取端口部分 */ char* port_str colon 1; char* endptr; long port strtol(port_str, endptr, 10); if (endptr port_str || *endptr ! \0 || port 0 || port 65535) { errno EINVAL; return -1; } return sock_addr_ipv6(ip_str, (uint16_t)port, addr); } else { /* IPv4地址格式127.0.0.1:8080 */ char ip_str[INET_ADDRSTRLEN]; size_t ip_len colon - str; if (ip_len sizeof(ip_str)) { errno EINVAL; return -1; } strncpy(ip_str, str, ip_len); ip_str[ip_len] \0; /* 提取端口部分 */ char* port_str colon 1; char* endptr; long port strtol(port_str, endptr, 10); if (endptr port_str || *endptr ! \0 || port 0 || port 65535) { errno EINVAL; return -1; } return sock_addr_ipv4(ip_str, (uint16_t)port, addr); } } /* 默认尝试解析为主机名使用默认端口0 */ return sock_addr_ipv4(str, 0, addr); } ​ /** * brief 获取错误描述 * * param err 错误码 * return const char* 错误描述 */ const char* sock_strerror(int err) { switch (err) { case 0: return Success; case EINVAL: return Invalid argument; case EBADF: return Bad file descriptor; case EACCES: return Permission denied; case EADDRINUSE: return Address already in use; case EADDRNOTAVAIL: return Address not available; case EAFNOSUPPORT: return Address family not supported; case EAGAIN: return Resource temporarily unavailable; case EALREADY: return Connection already in progress; case ECONNREFUSED: return Connection refused; case ECONNRESET: return Connection reset by peer; case EDESTADDRREQ: return Destination address required; case EFAULT: return Bad address; case EHOSTUNREACH: return Host is unreachable; case EINPROGRESS: return Operation in progress; case EISCONN: return Socket is already connected; case ENETDOWN: return Network is down; case ENETUNREACH: return Network is unreachable; case ENOTSOCK: return Not a socket; case EPROTONOSUPPORT: return Protocol not supported; case ETIMEDOUT: return Connection timed out; case EWOULDBLOCK: return Operation would block; case EMSGSIZE: return Message too long; case ENOPROTOOPT: return Protocol option not supported; case EPROTOTYPE: return Wrong protocol type for socket; case ENOTCONN: return Socket not connected; case ESHUTDOWN: return Cannot send after socket shutdown; case ENOBUFS: return No buffer space available; case EOPNOTSUPP: return Operation not supported; case EPERM: return Operation not permitted; case ENOMEM: return Out of memory; default: return strerror(err); } } ​ /** * brief 获取本地地址信息 * * param sock Socket句柄 * param addr 输出地址 * return int 0成功-1失败 */ int sock_get_local_addr(socket_t sock, sock_addr_t* addr) { if (sock SOCKET_INVALID || !addr) { errno EINVAL; return -1; } struct sockaddr_storage ss; socklen_t len sizeof(ss); if (getsockname(sock, (struct sockaddr*)ss, len) 0) { return -1; } return addr_from_sys((struct sockaddr*)ss, len, addr); } ​ /** * brief 获取远程地址信息 * * param sock Socket句柄 * param addr 输出地址 * return int 0成功-1失败 */ int sock_get_remote_addr(socket_t sock, sock_addr_t* addr) { if (sock SOCKET_INVALID || !addr) { errno EINVAL; return -1; } struct sockaddr_storage ss; socklen_t len sizeof(ss); if (getpeername(sock, (struct sockaddr*)ss, len) 0) { return -1; } return addr_from_sys((struct sockaddr*)ss, len, addr); } ​ /** * brief 获取地址端口号 * * param addr 地址 * param port 输出端口号 * return int 0成功-1失败 */ int sock_addr_get_port(const sock_addr_t* addr, uint16_t* port) { if (!addr || !port) { errno EINVAL; return -1; } switch (addr-family) { case SOCK_AF_INET: *port ntohs(addr-u.ipv4.port); return 0; case SOCK_AF_INET6: *port ntohs(addr-u.ipv6.port); return 0; case SOCK_AF_UNIX: /* Unix域Socket没有端口 */ *port 0; return 0; default: errno EAFNOSUPPORT; return -1; } } ​ /** * brief 设置地址端口号 * * param addr 地址 * param port 端口号 * return int 0成功-1失败 */ int sock_addr_set_port(sock_addr_t* addr, uint16_t port) { if (!addr) { errno EINVAL; return -1; } switch (addr-family) { case SOCK_AF_INET: addr-u.ipv4.port htons(port); return 0; case SOCK_AF_INET6: addr-u.ipv6.port htons(port); return 0; case SOCK_AF_UNIX: /* Unix域Socket没有端口 */ return 0; default: errno EAFNOSUPPORT; return -1; } } ​ /** * brief 比较两个地址是否相等 * * param addr1 地址1 * param addr2 地址2 * return int 1相等0不相等-1错误 */ int sock_addr_equal(const sock_addr_t* addr1, const sock_addr_t* addr2) { if (!addr1 || !addr2) { return -1; } if (addr1-family ! addr2-family) { return 0; } switch (addr1-family) { case SOCK_AF_INET: return (addr1-u.ipv4.addr addr2-u.ipv4.addr addr1-u.ipv4.port addr2-u.ipv4.port); case SOCK_AF_INET6: return (memcmp(addr1-u.ipv6.addr, addr2-u.ipv6.addr, 16) 0 addr1-u.ipv6.port addr2-u.ipv6.port); case SOCK_AF_UNIX: return (strcmp(addr1-u.unix.path, addr2-u.unix.path) 0); default: return -1; } } ​ /** * brief 复制地址 * * param dst 目标地址 * param src 源地址 * return int 0成功-1失败 */ int sock_addr_copy(sock_addr_t* dst, const sock_addr_t* src) { if (!dst || !src) { errno EINVAL; return -1; } memcpy(dst, src, sizeof(*dst)); return 0; }第五部分编译配置和示例5.1 Makefile 示例# Makefile for Socket Library ​ CC gcc CFLAGS -Wall -Wextra -O2 -I./include -I../lib/include LDFLAGS -L../lib -lcommon -lpthread ​ # 源文件 SRCS src/socket_core.c src/socket_io.c src/socket_opt.c src/socket_util.c OBJS $(SRCS:.c.o) ​ # 目标 TARGET libsocket.a ​ # 示例 EXAMPLES examples/echo_server examples/echo_client ​ all: $(TARGET) $(EXAMPLES) ​ # 静态库 $(TARGET): $(OBJS) ar rcs $ $^ ​ # 编译规则 %.o: %.c $(CC) $(CFLAGS) -c $ -o $ ​ # 示例程序 examples/%: examples/%.c $(TARGET) $(CC) $(CFLAGS) $ -o $ $(TARGET) $(LDFLAGS) ​ clean: rm -f $(OBJS) $(TARGET) $(EXAMPLES) ​ .PHONY: all clean5.2 简单示例echo_server.c/** * file echo_server.c * brief 简单的Echo服务器示例 */ ​ #include socket.h #include stdio.h #include string.h #include signal.h ​ static volatile int running 1; ​ void signal_handler(int sig) { running 0; printf(\nShutting down...\n); } ​ int main(int argc, char* argv[]) { /* 设置信号处理 */ signal(SIGINT, signal_handler); /* 创建TCP Socket */ socket_t sock sock_create(SOCK_AF_INET, SOCK_TYPE_STREAM); if (sock SOCKET_INVALID) { fprintf(stderr, Failed to create socket: %s\n, sock_strerror(errno)); return 1; } /* 设置地址重用 */ sock_set_reuseaddr(sock, true); /* 绑定地址 */ sock_addr_t addr; if (sock_addr_ipv4(0.0.0.0, 8080, addr) 0) { fprintf(stderr, Failed to create address\n); sock_close(sock); return 1; } if (sock_bind(sock, addr) 0) { fprintf(stderr, Failed to bind: %s\n, sock_strerror(errno)); sock_close(sock); return 1; } /* 开始监听 */ if (sock_listen(sock, 10) 0) { fprintf(stderr, Failed to listen: %s\n, sock_strerror(errno)); sock_close(sock); return 1; } printf(Echo server listening on port 8080...\n); /* 主循环 */ while (running) { /* 接受连接 */ socket_t client sock_accept(sock, NULL, 1000); if (client SOCKET_INVALID) { if (errno ! ETIMEDOUT errno ! EINTR) { fprintf(stderr, Accept failed: %s\n, sock_strerror(errno)); } continue; } printf(Client connected\n); /* 处理客户端 */ char buffer[1024]; while (running) { ssize_t n sock_recv(client, buffer, sizeof(buffer), 1000); if (n 0) { if (n 0 errno ! ETIMEDOUT) { fprintf(stderr, Receive failed: %s\n, sock_strerror(errno)); } break; } /* 回显数据 */ buffer[n] \0; printf(Received: %s, buffer); if (sock_send(client, buffer, n, 1000) 0) { fprintf(stderr, Send failed: %s\n, sock_strerror(errno)); break; } } printf(Client disconnected\n); sock_close(client); } /* 清理 */ sock_close(sock); printf(Server stopped\n); return 0; }设计总结这个Socket模块的设计特点1.高内聚socket_core.c: 只处理Socket生命周期和连接管理socket_io.c: 只处理数据发送和接收socket_opt.c: 只处理选项设置socket_util.c: 只处理地址转换和工具函数2.低耦合每个文件独立编译不相互依赖通过公共头文件socket.h定义接口不依赖全局状态函数都是纯操作3.简洁性Socket句柄就是文件描述符零封装错误处理直接使用errno接口数量最小化只有最必要的功能4.实用性提供超时控制处理EINTR中断支持IPv4/IPv6/Unix域线程安全依赖基础库这个设计既保持了系统调用的直接性又提供了必要的封装和错误处理是一个平衡了简洁性和实用性的Socket库。第三阶段 封装这个Socket模块确实有其现实意义和价值一、封装的意义分析1.错误处理标准化// 原生代码 vs 封装后代码 ​ // 原生需要手动处理各种错误情况 int sock socket(AF_INET, SOCK_STREAM, 0); if (sock 0) { perror(socket); return -1; } ​ // 设置非阻塞 int flags fcntl(sock, F_GETFL, 0); if (flags 0) { perror(fcntl); close(sock); return -1; } if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) 0) { perror(fcntl); close(sock); return -1; } ​ // 设置地址重用 int reuse 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reuse, sizeof(reuse)) 0) { perror(setsockopt); close(sock); return -1; } ​ // 封装后统一错误处理 socket_t sock sock_create(SOCK_AF_INET, SOCK_TYPE_STREAM); if (sock SOCKET_INVALID) { LOG_ERROR(Failed to create socket: %s, sock_strerror(errno)); return -1; } sock_set_nonblock(sock, true); sock_set_reuseaddr(sock, true);意义减少50%以上的样板代码错误处理集中化。2.跨平台兼容性准备虽然当前是Linux但设计时已考虑扩展// 封装层可以隐藏平台差异 #ifdef __linux__ #define SOCK_CLOSE close #elif _WIN32 #define SOCK_CLOSE closesocket #endif ​ // 使用统一的接口 sock_close(sock); // 内部处理平台差异3.资源管理自动化// 封装可以提供RAII风格的管理 typedef struct { socket_t sock; // 自动记录创建时间、统计信息等 } managed_socket_t; ​ // 可以在close时自动清理相关资源 int sock_close(socket_t sock) { // 1. 取消所有pending操作 // 2. 关闭socket // 3. 更新统计信息 // 4. 记录日志 // 5. 通知监控系统 }4.性能监控和统计// 封装可以透明地添加统计 ssize_t sock_send(socket_t sock, const void* buf, size_t len, int timeout_ms) { struct timespec start, end; clock_gettime(CLOCK_MONOTONIC, start); ssize_t result /* 实际发送 */; clock_gettime(CLOCK_MONOTONIC, end); double elapsed (end.tv_sec - start.tv_sec) * 1000.0 (end.tv_nsec - start.tv_nsec) / 1000000.0; // 记录到统计系统 update_stats(SEND_OPERATION, len, elapsed, result); return result; }5.安全增强// 可以添加安全检查 int sock_bind(socket_t sock, const sock_addr_t* addr) { // 1. 检查地址是否合法 if (!validate_address(addr)) { errno EINVAL; return -1; } // 2. 检查端口权限root需要1024 if (geteuid() 0 addr-u.ipv4.port 1024) { LOG_WARN(Root binding to privileged port); } // 3. 记录安全日志 log_security_event(BIND, sock, addr); return bind(sock, ...); }二、实际应用场景的价值场景1大规模服务器开发// 在大型服务器中需要 // 1. 连接池管理 // 2. 超时统一控制 // 3. 熔断机制 // 4. 监控告警 ​ // 封装可以透明实现这些 socket_t sock connection_pool_get(); if (sock_send(sock, request, len, 100) 0) { // 自动记录失败触发熔断 connection_mark_bad(sock); return -1; }场景2协议实现// 实现HTTP、Redis等协议时 typedef struct { socket_t sock; buffer_t input_buf; buffer_t output_buf; protocol_parser_t parser; } protocol_connection_t; ​ // 封装可以集成缓冲和解析 int http_send_request(protocol_connection_t* conn, http_request_t* req) { // 序列化请求 serialize_http_request(req, conn-output_buf); // 发送自动处理分片、重试 return sock_send_buffered(conn-sock, conn-output_buf); }场景3测试和模拟// 封装可以方便地mock和测试 #ifdef TESTING // 测试环境下使用mock socket socket_t mock_sock_create(...) { return create_mock_socket(); } ssize_t mock_sock_send(...) { return record_and_mock_send(); } #endif三、具体封装价值的体现价值1开发效率提升// 实现一个完整的TCP服务器 ​ // 原生约200行代码大量重复错误处理 // 封装约50行代码清晰易读 socket_t server sock_create(SOCK_AF_INET, SOCK_TYPE_STREAM); sock_set_reuseaddr(server, true); ​ sock_addr_t addr; sock_addr_ipv4(0.0.0.0, 8080, addr); sock_bind(server, addr); sock_listen(server, 128); ​ while (running) { socket_t client sock_accept(server, NULL, 100); if (client ! SOCKET_INVALID) { handle_client(client); } }价值2维护性提升// 当需要修改超时策略时 ​ // 没有封装修改所有send/recv调用点可能几十处 // 有封装只修改sock_send/sock_recv实现 ​ // 新增TCP keepalive支持 int sock_set_keepalive(socket_t sock, int idle, int interval, int count) { // 一处实现所有使用处自动受益 }价值3团队协作规范// 确保团队使用统一的 // 1. 错误处理方式 // 2. 日志格式 // 3. 超时值 // 4. 缓冲区大小 ​ // 避免不同开发者写出风格迥异的代码四、是否应该封装的判断标准应该封装的情况项目规模大10个文件多个开发者需要重用在多处使用相似代码需要维护长期维护的项目需要监控需要统计和诊断团队协作需要统一编码规范不应该封装的情况一次性脚本用完就丢极端性能敏感每个CPU周期都重要特殊系统调用需要直接控制学习目的理解底层机制五、对当前项目的建议基于common基础库这个Socket封装的价值与现有基础设施集成// 直接使用common库的日志、内存、线程 LOG_DEBUG(SOCKET, Created socket fd%d, fd); void* buf common_malloc(size); common_mutex_lock(socket_mutex);统一项目管理一致的代码风格统一的错误处理集成的监控统计为未来扩展预留添加SSL/TLS支持支持IPv6过渡集成连接池添加重试机制结论封装的意义在于✅不是为了封装而封装✅不是隐藏系统调用仍可直接访问fd✅是为了提供一致的开发体验✅是为了减少重复代码✅是为了集中维护通用逻辑✅是为了便于监控和调试对于项目这个适度的封装在以下方面提供了价值错误处理标准化利用common库资源管理简化自动清理可维护性提升集中修改可测试性增强易于mock团队协作友好统一接口这是一个务实的封装不过度设计不隐藏重要细节但提供了实际开发中需要的便利性和一致性。
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

网络公司取什么名字好西安seo关键词推广

在渗透测试过程中,我们经常会遇到以下场景:某处于域中的服务器通过路由做端口映射,对外提供web服务,我们通过web脚本漏洞获得了该主机的system权限,如果甲方有进一步的内网渗透测试需求,以证明企业所面临的…

张小明 2026/1/8 5:37:14 网站建设

公司开发网站wordpress 网站图标设置

如何在Windows XP上让Protel99SE“起死回生”?——一次关于老软件与新系统的博弈你有没有试过,在一台装着Windows XP的旧机器上,双击CLIENT.EXE却弹出“无法创建数据库”或干脆直接崩溃?这不是偶然。这是一个基于Win9x架构的经典E…

张小明 2026/1/7 4:47:51 网站建设

网站内页做友链开周边网站怎么做品牌

第一章:军工级无人机路径规划技术概述在现代军事与战略应用中,军工级无人机的自主路径规划能力直接决定了其任务执行效率与生存能力。这类系统不仅需要应对复杂多变的战场环境,还需满足高实时性、高鲁棒性与抗干扰通信等严苛要求。核心设计目…

张小明 2026/1/7 4:47:50 网站建设

网站导航条设计欣赏网站建设建设公司资质要求

Vue-Good-Table-Next:让数据展示变得轻松愉悦的Vue 3表格解决方案 【免费下载链接】vue-good-table-next 项目地址: https://gitcode.com/gh_mirrors/vu/vue-good-table-next 还在为Vue项目中的数据表格发愁吗?每次面对复杂的数据展示需求&#…

张小明 2026/1/7 4:47:50 网站建设

网站建设编辑叫什么岗位城市建设模拟游戏登陆网站

LobeChat 的 API 扩展之路:GraphQL 是否可行? 在构建现代 AI 聊天应用时,开发者越来越关注系统的可扩展性与前后端协作效率。LobeChat 作为一款基于 Next.js 的开源大语言模型(LLM)交互门户,凭借其优雅的 U…

张小明 2026/1/6 13:56:23 网站建设

站酷网素材图库临沧网站建设ynyue

MacType高DPI终极方案:完美解决Windows高分屏字体模糊问题 【免费下载链接】mactype Better font rendering for Windows. 项目地址: https://gitcode.com/gh_mirrors/ma/mactype 在4K显示器上阅读文档时,你是否经常感到眼睛疲劳?Wind…

张小明 2026/1/7 4:47:54 网站建设