#ifdef WIN32 #include "Socket_p.h" namespace Psc::socket { Ret connect(SOCKET s, const Sockaddr_In& addr_in) { SOCKADDR_IN addr{}; addr.sin_family = AF_INET; addr.sin_port = htons(static_cast(addr_in.port)); if (::inet_pton(AF_INET, addr_in.ip.c_str(), &addr.sin_addr) != 1) { return unexpected(Enum_Err(NetError::invalid_argument)); } if (::connect(s, reinterpret_cast(&addr), sizeof(addr)) == 0) { return true; // 立即成功 } const int e = ::WSAGetLastError(); // 统一按“非阻塞 connect 语义”:这些不算失败 switch (e) { case WSAEWOULDBLOCK: case WSAEINPROGRESS: case WSAEALREADY: return true; // 已发起连接,后续用 SO_ERROR 判定最终结果 default: break; } return unexpected(Enum_Err(NetErrorCategory::map_system_error(e), e)); } Ret set_block(Socket_FD that, bool blocking) { if (that == -1) return Ret(); u_long mode = blocking ? 0 : 1; // 0 为阻塞, 1 为非阻塞 if (ioctlsocket(that, FIONBIO, &mode) != 0) { LOG_FD_Debug(that, VAR_STR_2(that, blocking) + "设置socket阻塞属性错误!") } return Ret(); } NetError NetErrorCategory::map_system_error(int e) noexcept { switch (e) { case WSAEINTR: return NetError::interrupted; case WSAECANCELLED: return NetError::operation_canceled; case WSAEINVAL: return NetError::invalid_argument; case WSAEACCES: return NetError::permission_denied; case WSAENOBUFS: return NetError::resource_exhausted; case WSAEBADF: return NetError::bad_file_descriptor; case WSAENOTSOCK: return NetError::not_a_socket; case WSAEWOULDBLOCK: return NetError::would_block; case WSAEINPROGRESS: return NetError::in_progress; case WSAEALREADY: return NetError::already_in_progress; case WSAEADDRINUSE: return NetError::address_in_use; case WSAEADDRNOTAVAIL: return NetError::address_not_available; case WSAENETDOWN: return NetError::network_down; case WSAENETUNREACH: return NetError::network_unreachable; case WSAEHOSTUNREACH: return NetError::host_unreachable; case WSAENOTCONN: return NetError::not_connected; case WSAEISCONN: return NetError::already_connected; case WSAECONNREFUSED: return NetError::connection_refused; case WSAECONNRESET: return NetError::connection_reset; case WSAECONNABORTED: return NetError::connection_aborted; case WSAETIMEDOUT: return NetError::timed_out; default: return NetError::unknown_error; } } ERROR_CODE_TYPE last_socket_ec() { int wsa = ::WSAGetLastError(); return wsa; } namespace TCP { Ret> accept(SOCKET listen_fd) { SOCKADDR_IN clientAddr{}; int clientAddrSize = sizeof(clientAddr); SOCKET client_fd = ::accept(listen_fd, reinterpret_cast(&clientAddr), &clientAddrSize); if (client_fd == INVALID_SOCKET) { int e = ::WSAGetLastError(); if (e == WSAEWOULDBLOCK || e == WSAEINTR) { return std::nullopt; } const auto ne = NetErrorCategory::map_system_error(e); LOG_FD_Debug(listen_fd, std::string("accept error: ") + std::system_category().message(e)); return unexpected(Enum_Err(ne, e)); } Accept_Info info{}; info.fd = client_fd; char ipbuf[INET_ADDRSTRLEN]{}; if (::inet_ntop(AF_INET, &clientAddr.sin_addr, ipbuf, sizeof(ipbuf)) == nullptr) { int e = ::WSAGetLastError(); const auto ne = NetErrorCategory::map_system_error(e); LOG_FD_Debug(listen_fd, std::string("inet_ntop error: ") + std::system_category().message(e)); return unexpected(Enum_Err(ne, e)); } info.sockaddr.ip = ipbuf; info.sockaddr.port = ntohs(clientAddr.sin_port); return info; } } Ret recv_all(SOCKET fd) { u_long avail = 0; if (::ioctlsocket(fd, FIONREAD, &avail) != 0) { int e = ::WSAGetLastError(); return unexpected(Enum_Err(NetErrorCategory::map_system_error(e), e)); } if (avail == 0) { // 无法仅靠 FIONREAD 区分“没数据”还是“已关闭但没数据” // 如果你需要区分:可用 select 读集合 + 再 recv(1字节, MSG_PEEK) return std::string{}; } size_t to_read = avail; std::string buf; buf.resize(to_read); size_t total = 0; while (total < to_read) { int n = ::recv(fd, buf.data() + total, (int)(to_read - total), 0); if (n == SOCKET_ERROR) { int e = ::WSAGetLastError(); // 理论上 FIONREAD>0 后不该 WSAEWOULDBLOCK,但并发/竞态下可能发生 if (e == WSAEWOULDBLOCK || e == WSAEINTR) { break; // 立刻返回已读部分 } buf.resize(total); return unexpected(Enum_Err(NetErrorCategory::map_system_error(e), e)); } if (n == 0) { // 对端关闭 buf.resize(total); if (!buf.empty()) return buf; return unexpected(Enum_Err(NetError::connection_closed)); } total += (size_t)n; } buf.resize(total); //std::cout << "bufsize:" << buf.size() << std::endl; return buf; } Ret recv_once(Socket_FD fd, int max_bytes) { if (max_bytes <= 0) return unexpected(Enum_Err(NetError::invalid_argument)); std::string buf; buf.resize((size_t)max_bytes); int n = ::recv(fd, buf.data(), max_bytes, 0); if (n == SOCKET_ERROR) { int e = ::WSAGetLastError(); if (e == WSAEWOULDBLOCK || e == WSAEINTR) return std::string{}; return unexpected(Enum_Err(NetErrorCategory::map_system_error(e), e)); } if (n == 0) return unexpected(Enum_Err(NetError::connection_closed)); buf.resize((size_t)n); return buf; } Ret recv_all_until_idle( Socket_FD fd, int chunk_size, size_t max_bytes, int idle_timeout_ms, // 多久没新数据就退出 bool eof_is_ok = true // n==0 是否当作正常结束 ) { if (chunk_size <= 0 || max_bytes == 0) { return unexpected(Enum_Err(NetError::invalid_argument)); } std::string buffer; buffer.reserve(std::min(max_bytes, 64 * 1024)); size_t total = 0; while (total < max_bytes) { // 用 select 等待可读(避免阻塞卡死;也给 idle 超时提供退出点) fd_set rfds; FD_ZERO(&rfds); FD_SET(fd, &rfds); TIMEVAL tv; tv.tv_sec = idle_timeout_ms / 1000; tv.tv_usec = (idle_timeout_ms % 1000) * 1000; int s = ::select(0, &rfds, nullptr, nullptr, &tv); if (s == 0) { // 超时:认为“暂时读不到了”,退出返回已读 return buffer; } if (s == SOCKET_ERROR) { int e = ::WSAGetLastError(); return unexpected(Enum_Err(NetErrorCategory::map_system_error(e), e)); } const int want = (int)std::min((size_t)chunk_size, max_bytes - total); buffer.resize(total + (size_t)want); int n = ::recv(fd, buffer.data() + total, want, 0); if (n == SOCKET_ERROR) { int e = ::WSAGetLastError(); if (e == WSAEWOULDBLOCK || e == WSAEINTR) { buffer.resize(total); return buffer; } buffer.resize(total); return unexpected(Enum_Err(NetErrorCategory::map_system_error(e), e)); } if (n == 0) { buffer.resize(total); if (eof_is_ok) return buffer; return unexpected(Enum_Err(NetError::connection_closed)); } total += (size_t)n; buffer.resize(total); } // 达到上限:防止对端一直发导致无限读 return buffer; } bool is_client_need_close_ec(ERROR_CODE_TYPE e) { switch (e) { // 连接已失效/不再可用:应关闭 case WSAECONNRESET: // 对端复位 case WSAECONNABORTED: // 连接被中止 case WSAENOTCONN: // 未连接 case WSAETIMEDOUT: // 超时(可视为应关闭) case WSAESHUTDOWN: // 本端已 shutdown,收发被禁止 return true; // 连接拒绝通常发生在 connect 阶段;服务端 recv 上很少见。 // 这里按你原逻辑,仍视为应关闭(等价于“不可用”)。 case WSAECONNREFUSED: return true; // 非阻塞无数据/暂态:不关闭 case WSAEWOULDBLOCK: case WSAEINPROGRESS: case WSAEALREADY: case WSAEINTR: return false; // 其他错误:保守策略,不直接关闭(也可改成 true 更激进) default: return false; } } bool is_client_need_close(SOCKET s) { char buf[1]; int r = ::recv(s, buf, sizeof(buf), MSG_PEEK); if (r == 0) { // 对端正常关闭(FIN/EOF) return true; } if (r == SOCKET_ERROR) { const int e = ::WSAGetLastError(); return Psc::socket::is_client_need_close_ec(e); } // r > 0:还能读到数据,连接正常 return false; } bool is_needed_reconnect_ec(ERROR_CODE_TYPE e) { switch (e) { // 这些表示连接已失效/网络不可达:建议重连 case WSAECONNRESET: // 远端强制关闭 case WSAECONNABORTED: // 连接被中止 case WSAENOTCONN: // 未连接 case WSAETIMEDOUT: // 超时 case WSAENETDOWN: // 网络子系统不可用 case WSAENETUNREACH: // 网络不可达 case WSAEHOSTUNREACH: // 主机不可达 case WSAECONNREFUSED: // 连接被拒绝(多见于 connect 阶段;这里出现也可视为需重连) return true; // 这些表示“现在没数据/可重试/被打断”:不重连 case WSAEWOULDBLOCK: // 非阻塞暂时无数据 case WSAEINPROGRESS: // 操作进行中 case WSAEALREADY: // 已在进行 case WSAEINTR: // 被中断 return false; // 其他错误:按你的策略决定。这里保守处理为“不重连” default: return false; } } bool is_needed_reconnect(SOCKET s) { char buf[1]; int r = ::recv(s, buf, sizeof(buf), MSG_PEEK); if (r == 0) { // 对端正常关闭(FIN/EOF) return true; } if (r == SOCKET_ERROR) { const int e = ::WSAGetLastError(); return is_needed_reconnect_ec(e); } // r > 0:能窥探到数据,连接仍然活着 return false; } namespace UDP { Ret recvfrom(SOCKET receive_fd, Sockaddr_In* ret, int chunk_size) { if (chunk_size <= 0 || ret == nullptr) { return unexpected(Enum_Err(NetError::invalid_argument)); } std::string buffer; buffer.resize(static_cast(chunk_size)); SOCKADDR_IN client_addr{}; int addr_len = sizeof(client_addr); int n = ::recvfrom(receive_fd, buffer.data(), chunk_size, 0, reinterpret_cast(&client_addr), &addr_len); if (n == SOCKET_ERROR) { const int e = ::WSAGetLastError(); // 非阻塞:暂时无数据 / 被中断:维持你原来的语义,返回空串 if (e == WSAEWOULDBLOCK || e == WSAEINTR) { return std::string{}; } const auto ne = NetErrorCategory::map_system_error(e); LOG_FD_Debug(receive_fd, std::string("recvfrom error: ") + std::system_category().message(e)); return unexpected(Enum_Err(ne, e)); } // n == 0:UDP 允许 0 长度 datagram,依然需要填来源地址 char client_ip[INET_ADDRSTRLEN]{}; if (::inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN) == nullptr) { const int e = ::WSAGetLastError(); const auto ne = NetErrorCategory::map_system_error(e); LOG_FD_Debug(receive_fd, std::string("inet_ntop error: ") + std::system_category().message(e)); return unexpected(Enum_Err(ne, e)); } ret->ip = client_ip; ret->port = ntohs(client_addr.sin_port); buffer.resize(static_cast(n)); return buffer; } } } // namespace Psc::socket #endif