Files
CPP_Core/Socket_old/Socket.cpp
T
2026-06-16 10:56:40 +08:00

422 lines
12 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.
#include "Core/Bit.h"
#include "Core/RET.hpp"
#include "Core/Statistics/Frequency_Limit.h"
#include "Socket_p.h"
#include <cstring>
#include <iostream>
#include <string>
#include <vector>
#ifdef __linux__
#include <netinet/tcp.h>
#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<Socket_FD> 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>>(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>>(Enum_Err(NetError::unknown_error));
}
return fd;
}
Ret<void> set_buffer_size(Socket_FD that, size_t buffer_size) {
// setsockopt(SO_RCVBUF) 在各平台基本都要求 int
if (buffer_size > static_cast<size_t>(std::numeric_limits<int>::max())) {
return unexpected<Enum_Err<NetError>>(Enum_Err(NetError::invalid_argument));
}
int sz = static_cast<int>(buffer_size);
// Windows 的 optval 类型是 const char*POSIX 是 const void*
#ifdef _WIN32
const char* optval = reinterpret_cast<const char*>(&sz);
#else
const void* optval = reinterpret_cast<const void*>(&sz);
#endif
if (::setsockopt(that, SOL_SOCKET, SO_RCVBUF, optval,
static_cast<socklen_t>(sizeof(sz))) == SOCKET_ERROR) {
return unexpected<Enum_Err<NetError>>(Enum_Err(NetError::unknown_error));
}
return {};
}
Ret<void> 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>>(Enum_Err(NetError::unknown_error));
}
}
return Ret<void>();
}
Ret<void> 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>>(Enum_Err(NetError::invalid_argument));
}
if (::bind(that, reinterpret_cast<sockaddr*>(&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>>(Enum_Err(NetError::unknown_error));
}
return {};
}
Ret<int> 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<int>(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<NetError>>(Enum_Err(ne, e));
}
Ret<int> 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<void> 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<char *>(&flag), sizeof(flag));
if (ret < 0) {
LOG_FD_Debug(that, "设置socket阻塞属性错误!")
return unexpected<Enum_Err<NetError>>(Enum_Err(NetError::invalid_argument));
}
return Ret<void>();
}
Ret<void> set_keep_alive(Socket_FD that, bool enable) {
int flag = enable ? 1 : 0;
auto ret = setsockopt(that, SOL_SOCKET, SO_KEEPALIVE,
reinterpret_cast<char *>(&flag), sizeof(flag));
if (ret < 0) {
LOG_FD_Debug(that, VAR_STR_2(that, enable) + "无法设置 SO_KEEPALIVE!")
return unexpected<Enum_Err<NetError>>(Enum_Err(NetError::invalid_argument));
}
return Ret<void>();
}
Ret<void> 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>>(Enum_Err(NetError::invalid_argument));
}
return Ret<void>();
}
} // namespace TCP
namespace UDP {
Ret<int> 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>>(Enum_Err(NetError::invalid_argument));
}
int bytes_sent = ::sendto(
that, data.data(), static_cast<int>(data.size()), flags,
reinterpret_cast<const sockaddr *>(&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>>(Enum_Err(NetError::unknown_error));
}
// UDP sendto 成功时通常 >0;若出现 0,多半是 data 为空(已提前返回)
return bytes_sent;
}
} // namespace UDP
void get_fd_set(const std::vector<Socket_FD> &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<std::vector<Socket_FD>>
select_read(const std::vector<Socket_FD> &recv_fd_vector, int timeout_ms) {
std::vector<Socket_FD> 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<std::vector<Socket_FD>> select_write(std::vector<Socket_FD> fd_vector,
int timeout_ms) {
std::vector<Socket_FD> 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<bool> select_write(Socket_FD that, int timeout_ms) {
auto r = select_write(std::vector<Socket_FD>{that}, timeout_ms);
if (!r) {
return false;
}
return !r.value().empty();
}
Ret<bool> select_read(Socket_FD that, int timeout_ms) {
auto r = select_read(std::vector<Socket_FD>{that}, timeout_ms);
if (!r) {
return false;
}
return !r.value().empty();
}
Ret<Sockaddr_In> get_dest_addr(Socket_FD that) {
Sockaddr_In ret;
sockaddr_in addr{};
socklen_t addrLen = sizeof(addr);
if (::getpeername(that, reinterpret_cast<sockaddr*>(&addr), &addrLen) == SOCKET_ERROR) {
LOG_FD_Debug(that, "获取目标地址错误!");
return unexpected<Enum_Err<NetError>>(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>>(Enum_Err(NetError::invalid_argument));
}
ret.ip = ipbuf;
ret.port = ntohs(addr.sin_port);
return ret;
}
Ret<Sockaddr_In> get_addr(Socket_FD that) {
Sockaddr_In ret;
sockaddr_in localAddr{};
socklen_t addrLen = sizeof(localAddr);
if (::getsockname(that, reinterpret_cast<sockaddr*>(&localAddr), &addrLen) == SOCKET_ERROR) {
LOG_FD_Debug(that, "获取socket地址错误!");
return unexpected<Enum_Err<NetError>>(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>>(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<void> set_reuse(Socket_FD that, bool enable) {
int flag = enable ? 1 : 0;
auto ret = setsockopt(that, SOL_SOCKET, SO_REUSEADDR,
reinterpret_cast<char *>(&flag), sizeof(flag));
if (ret < 0) {
LOG_FD_Debug(that, VAR_STR_2(that, enable) +
"无法设置 SO_REUSEADDR!")
return unexpected<Enum_Err<NetError>>(Enum_Err(NetError::invalid_argument, ret));
}
return Ret<void>();
}
Ret<void> set_debug(Socket_FD that, bool enable) {
int flag = enable ? 1 : 0;
auto ret = setsockopt(that, SOL_SOCKET, SO_DEBUG,
reinterpret_cast<char *>(&flag), sizeof(flag));
if (ret < 0) {
LOG_FD_Debug(that, VAR_STR_2(that, enable) + "无法设置 SO_DEBUG!")
return unexpected<Enum_Err<NetError>>(Enum_Err(NetError::invalid_argument, ret));
}
return Ret<void>();
}
Ret<int> get_socket_opt(Socket_FD fd, int optname) {
int optionValue;
socklen_t optionLen = sizeof(optionValue);
auto r = getsockopt(fd, SOL_SOCKET, optname,
reinterpret_cast<char *>(&optionValue), &optionLen);
if (r == SOCKET_ERROR) {
LOG_FD_Debug(fd, std::to_string(optname) + "获取套接字错误!")
return unexpected<Enum_Err<NetError>>(Enum_Err(NetError::invalid_argument, r));
}
return optionValue;
}
Ret<void> 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>>(Enum_Err(NetError::invalid_argument, r));
}
return Ret<void>();
}
} // namespace Psc::socket
#undef SOCKET_END