#include "Core/Bit.h" #include "Core/RET.hpp" #include "Core/Statistics/Frequency_Limit.h" #include "Socket_p.h" #include #include #include #include #ifdef __linux__ #include #endif #undef max #undef min namespace Psc::socket { BaseLogger *socket_logger = nullptr; std::string Sockaddr_In::to_string() const { return ip + ":" + std::to_string(port); } JSON Socket_Base::to_Json() const { JSON ret = JSON::object(); ret.append({"fd", socket_fd}); ret.append({"address", address.has_value() ? address.value().to_string() : "nullopt"}); return ret; } void log_error(BaseLogger *logger, const std::string &POS, Psc::socket::Socket_FD fd, const std::string &MSG) { static Frequency_Limit_Multi lm; bool ok = lm.test(std::to_string(fd) + "_" + Psc::to_string(last_socket_ec()) + POS); if (!ok) return; std::string msg = MSG + std::string(" ") + Psc::get_error_message() + " " + POS + "\n"; if (!logger) { std::ostringstream oss; oss << "fd:" << fd << " " << msg << std::flush; std::cout << oss.str(); } else { static Log_Type log_type({VAR_STR_1(fd)}); logger->error("", log_type, msg); } } Ret create_socket_fd(Socket_Type type) { if (type == Socket_Type::Null) { socket_logger->c_debug({}, {}, "严重错误 Socket type is Null: " + to_string(type)); return unexpected>(Enum_Err(NetError::invalid_argument)); } int t = (type == Socket_Type::TCP) ? SOCK_STREAM : SOCK_DGRAM; #if defined(__linux__) && defined(SOCK_CLOEXEC) // 尽量在 socket() 阶段原子设置(避免 fork/exec 竞争窗口) t |= SOCK_CLOEXEC; #endif Socket_FD fd = ::socket(AF_INET, t, 0); if (fd == INVALID_SOCKET) { return unexpected>(Enum_Err(NetError::unknown_error)); } return fd; } Ret set_buffer_size(Socket_FD that, size_t buffer_size) { // setsockopt(SO_RCVBUF) 在各平台基本都要求 int if (buffer_size > static_cast(std::numeric_limits::max())) { return unexpected>(Enum_Err(NetError::invalid_argument)); } int sz = static_cast(buffer_size); // Windows 的 optval 类型是 const char*;POSIX 是 const void* #ifdef _WIN32 const char* optval = reinterpret_cast(&sz); #else const void* optval = reinterpret_cast(&sz); #endif if (::setsockopt(that, SOL_SOCKET, SO_RCVBUF, optval, static_cast(sizeof(sz))) == SOCKET_ERROR) { return unexpected>(Enum_Err(NetError::unknown_error)); } return {}; } Ret close(Socket_FD that) { if (that != -1) { #ifdef _WIN32 int r = ::closesocket(that); #else int r = ::close(that); // 使用 POSIX 的 close 函数 #endif if (r == SOCKET_ERROR) { return unexpected>(Enum_Err(NetError::unknown_error)); } } return Ret(); } Ret bind(Socket_FD that, const Sockaddr_In& addr_in) { sockaddr_in addr{}; addr.sin_family = AF_INET; addr.sin_port = htons(addr_in.port); if (inet_pton(AF_INET, addr_in.ip.c_str(), &addr.sin_addr) <= 0) { static Frequency_Limit fl; if (fl.test()) { //LOG_FD_Debug(that, VAR_STR_2(addr_in.ip, addr_in.port) + "不合法的地址!"); } // 标准错误码:参数非法 return unexpected>(Enum_Err(NetError::invalid_argument)); } if (::bind(that, reinterpret_cast(&addr), sizeof(addr)) == SOCKET_ERROR) { static Frequency_Limit fl; if (fl.test()) { //LOG_FD_Debug(that, VAR_STR_2(addr_in.ip, addr_in.port) + "绑定ip端口错误!"); } // 标准错误码:直接上报系统错误(Windows=WSAGetLastError, Linux=errno) return unexpected>(Enum_Err(NetError::unknown_error)); } return {}; } Ret send(Socket_FD connected_fd, void *data, std::size_t size) { #ifdef _WIN32 int flags = 0; #else int flags = MSG_NOSIGNAL; #endif const int bytes_sent = ::send(connected_fd, (const char *)data, static_cast(size), flags); if (bytes_sent >= 0) { return bytes_sent; // 可能是部分发送,交给上层处理 } #ifdef _WIN32 const int e = ::WSAGetLastError(); // 暂态:直接忽略(不报错),让上层保留缓冲下次继续发 if (e == WSAEWOULDBLOCK || e == WSAEINTR || e == WSAEINPROGRESS || e == WSAEALREADY) { return 0; } #else const int e = errno; // 暂态:直接忽略(不报错) if (e == EAGAIN #if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) || e == EWOULDBLOCK #endif || e == EINTR || e == EINPROGRESS || e == EALREADY) { return 0; } #endif // 其它错误:返回错误(带 native 错误码,供上层决定是否 close) const auto ne = NetErrorCategory::map_system_error(e); return unexpected>(Enum_Err(ne, e)); } Ret send(Socket_FD connected_fd, const std::string &data) { if (data.empty()) { return 0; } return send(connected_fd, (uint8_t*)data.data(), data.size()); } namespace TCP { Ret set_no_delay(Socket_FD that, bool no_delay) { int flag = no_delay ? 1 : 0; auto ret = setsockopt(that, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&flag), sizeof(flag)); if (ret < 0) { LOG_FD_Debug(that, "设置socket阻塞属性错误!") return unexpected>(Enum_Err(NetError::invalid_argument)); } return Ret(); } Ret set_keep_alive(Socket_FD that, bool enable) { int flag = enable ? 1 : 0; auto ret = setsockopt(that, SOL_SOCKET, SO_KEEPALIVE, reinterpret_cast(&flag), sizeof(flag)); if (ret < 0) { LOG_FD_Debug(that, VAR_STR_2(that, enable) + "无法设置 SO_KEEPALIVE!") return unexpected>(Enum_Err(NetError::invalid_argument)); } return Ret(); } Ret listen(Socket_FD that, int backlog) { if (::listen(that, backlog) == SOCKET_ERROR) { auto ec = last_socket_ec(); LOG_FD_Debug(that, VAR_STR_2(that, backlog) + "listen 错误"); return unexpected>(Enum_Err(NetError::invalid_argument)); } return Ret(); } } // namespace TCP namespace UDP { Ret sendto(Socket_FD that, const std::string &client_ip, uint16_t client_port, const std::string &data) { #ifdef _WIN32 int flags = 0; #else int flags = MSG_NOSIGNAL; // UDP 一般不需要,但保留也无妨 #endif if (data.empty()) { return 0; // 发送 0 字节:正常 } sockaddr_in client_addr{}; client_addr.sin_family = AF_INET; client_addr.sin_port = htons(client_port); if (inet_pton(AF_INET, client_ip.c_str(), &client_addr.sin_addr) <= 0) { return unexpected>(Enum_Err(NetError::invalid_argument)); } int bytes_sent = ::sendto( that, data.data(), static_cast(data.size()), flags, reinterpret_cast(&client_addr), sizeof(client_addr)); if (bytes_sent == SOCKET_ERROR) { auto ec = last_socket_ec(); LOG_FD_Debug(that, std::string("sendto error: ") + get_error_message()); return unexpected>(Enum_Err(NetError::unknown_error)); } // UDP sendto 成功时通常 >0;若出现 0,多半是 data 为空(已提前返回) return bytes_sent; } } // namespace UDP void get_fd_set(const std::vector &fds, fd_set &ret_fd_set, int &max_fd) { FD_ZERO(&ret_fd_set); // 清空读集合 // 初始化最大文件描述符为 -1 max_fd = -1; // 将所有套接字添加到fd_set中,并找到最大套接字描述符 for (Socket_FD fd : fds) { FD_SET(fd, &ret_fd_set); if (fd > max_fd) { max_fd = fd; // 更新最大文件描述符 } } } timeval get_timeout(int timeout_ms) { timeval timeout{}; timeout.tv_sec = timeout_ms / 1000; // 秒 timeout.tv_usec = (timeout_ms % 1000) * 1000; // 微秒 return timeout; } Ret> select_read(const std::vector &recv_fd_vector, int timeout_ms) { std::vector ret; fd_set fds; int max_fd = -1; get_fd_set(recv_fd_vector, fds, max_fd); timeval timeout = get_timeout(timeout_ms); int result = select(max_fd + 1, &fds, nullptr, nullptr, &timeout); if (result <= 0) { return ret; } for (Socket_FD fd : recv_fd_vector) { if (FD_ISSET(fd, &fds)) { ret.push_back(fd); } } return ret; } Ret> select_write(std::vector fd_vector, int timeout_ms) { std::vector ret; fd_set fds; int max_fd = -1; get_fd_set(fd_vector, fds, max_fd); timeval timeout = get_timeout(timeout_ms); int result = select(max_fd + 1, nullptr, &fds, nullptr, &timeout); if (result <= 0) { return ret; } for (Socket_FD fd : fd_vector) { if (FD_ISSET(fd, &fds)) { ret.push_back(fd); } } return ret; } Ret select_write(Socket_FD that, int timeout_ms) { auto r = select_write(std::vector{that}, timeout_ms); if (!r) { return false; } return !r.value().empty(); } Ret select_read(Socket_FD that, int timeout_ms) { auto r = select_read(std::vector{that}, timeout_ms); if (!r) { return false; } return !r.value().empty(); } Ret get_dest_addr(Socket_FD that) { Sockaddr_In ret; sockaddr_in addr{}; socklen_t addrLen = sizeof(addr); if (::getpeername(that, reinterpret_cast(&addr), &addrLen) == SOCKET_ERROR) { LOG_FD_Debug(that, "获取目标地址错误!"); return unexpected>(Enum_Err(NetError::invalid_argument)); } char ipbuf[INET_ADDRSTRLEN]{}; if (!::inet_ntop(AF_INET, &addr.sin_addr, ipbuf, sizeof(ipbuf))) { // inet_ntop 失败:返回标准错误 return unexpected>(Enum_Err(NetError::invalid_argument)); } ret.ip = ipbuf; ret.port = ntohs(addr.sin_port); return ret; } Ret get_addr(Socket_FD that) { Sockaddr_In ret; sockaddr_in localAddr{}; socklen_t addrLen = sizeof(localAddr); if (::getsockname(that, reinterpret_cast(&localAddr), &addrLen) == SOCKET_ERROR) { LOG_FD_Debug(that, "获取socket地址错误!"); return unexpected>(Enum_Err(NetError::unknown_error)); // 或 get_sys_ex() } char ipbuf[INET_ADDRSTRLEN]{}; if (!::inet_ntop(AF_INET, &localAddr.sin_addr, ipbuf, sizeof(ipbuf))) { return unexpected>(Enum_Err(NetError::invalid_argument)); } ret.ip = ipbuf; ret.port = ntohs(localAddr.sin_port); return ret; } std::string socket_base_info(Socket_FD that) { auto addr = get_addr(that); auto dest_addr = get_dest_addr(that); auto s1 = addr ? addr->to_string() : Psc::to_string(addr.error()); auto s2 = dest_addr ? dest_addr->to_string() : to_string(dest_addr.error()); return "[" + s1 + "]=>[" + s2 + "]"; } Ret set_reuse(Socket_FD that, bool enable) { int flag = enable ? 1 : 0; auto ret = setsockopt(that, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&flag), sizeof(flag)); if (ret < 0) { LOG_FD_Debug(that, VAR_STR_2(that, enable) + "无法设置 SO_REUSEADDR!") return unexpected>(Enum_Err(NetError::invalid_argument, ret)); } return Ret(); } Ret set_debug(Socket_FD that, bool enable) { int flag = enable ? 1 : 0; auto ret = setsockopt(that, SOL_SOCKET, SO_DEBUG, reinterpret_cast(&flag), sizeof(flag)); if (ret < 0) { LOG_FD_Debug(that, VAR_STR_2(that, enable) + "无法设置 SO_DEBUG!") return unexpected>(Enum_Err(NetError::invalid_argument, ret)); } return Ret(); } Ret get_socket_opt(Socket_FD fd, int optname) { int optionValue; socklen_t optionLen = sizeof(optionValue); auto r = getsockopt(fd, SOL_SOCKET, optname, reinterpret_cast(&optionValue), &optionLen); if (r == SOCKET_ERROR) { LOG_FD_Debug(fd, std::to_string(optname) + "获取套接字错误!") return unexpected>(Enum_Err(NetError::invalid_argument, r)); } return optionValue; } Ret set_reuse_addr(Socket_FD that, bool enable) { int opt = enable ? 1 : 0; auto r = setsockopt(that, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt)); if (r == SOCKET_ERROR) { return unexpected>(Enum_Err(NetError::invalid_argument, r)); } return Ret(); } } // namespace Psc::socket #undef SOCKET_END