C++ 跨平台网络通信库 NetWork 设计与实现
Network 类的核心目标是简化 TCP(基于流的通信)和 UDP(基于数据报的通信)之间的 socket 操作。它负责创建 socket、服务器端的绑定与监听、客户端的连接、数据的发送与接收以及资源的释放,在此基础上添加了心跳保活机制,添加了自动重连机制。通过这个Network库,我们成功抽象了底层网络编程的复杂性,提供了简洁易用的 API 接口。通过 RAII 模式管理资源、跨平台兼容性处理
·
在C++编程中,NetWork让C++程序突破单机限制,具备与外部世界通信和协作的能力,从而构建分布式、可扩展的现代化应用。
Network 类简介
Network 类的核心目标是简化 TCP(基于流的通信)和 UDP(基于数据报的通信)之间的 socket 操作。它负责创建 socket、服务器端的绑定与监听、客户端的连接、数据的发送与接收以及资源的释放,在此基础上添加了心跳保活机制,添加了自动重连机制。
类的主要功能:
支持 TCP 和 UDP 通信:用户可以根据需求选择 TCP 或 UDP 协议
客户端-服务器模型:提供服务器端的绑定、监听和接受连接,也支持客户端的连接操作
自动资源管理:类负责 socket 创建和销毁,确保资源不会泄漏
跨平台兼容:支持 Windows 和 Linux/Unix 系统
高级网络特性:包括超时控制、心跳机制、Keep-Alive 保活等
NetWork类
class NetWork {
public:
enum class Protocol { TCP, UDP }; // 协议类型
enum class SocketType { CLIENT, SERVER }; // 套接字类型
// 错误回调类型
using ErrorCallback = std::function<void(const std::string&)>;
// 连接状态回调
using ConnectionCallback = std::function<void(bool)>;
private:
// Winsock引用计数管理
static std::atomic<int> s_wsaRefCount;
static std::mutex s_wsaMutex;
void initWinsock();
void cleanupWinsock();
public:
// 构造函数 - 添加所有成员初始化
NetWork(Protocol protocol, SocketType type);
// 移动构造函数
NetWork(NetWork&& other);
// 移动赋值运算符
NetWork& operator=(NetWork&& other);
// 析构函数
virtual ~NetWork();
// 设置错误回调
void setErrorCallback(ErrorCallback callback);
// 设置连接状态回调
void setConnectionCallback(ConnectionCallback callback);
// 设置超时(毫秒)
void setTimeout(int timeoutMs);
// 创建套接字
void createSocket(bool isIPv6 = false);
// 设置非阻塞模式
void setNonBlocking(bool nonBlocking);
template <typename T>
void sendStruct(const T& data);
// TCP服务器绑定和监听
void bindAndListen(const std::string& ip, int port, int backlog = 5);
// 接受连接
int acceptConnection(std::string& clientIP, int& clientPort);
// 设置套接字描述符
void setSocket(int socket);
// 获取套接字描述符
int getSocket() const;
// TCP客户端连接 - 添加超时处理
void connect(const std::string& ip, int port, int timeoutMs = 3000);
// UDP绑定地址
void bindAddress(const std::string & ip, int port);
// 设置保活
void setKeepAlive(bool enable, int idle = 60, int interval = 5, int count = 3);
// 设置心跳
void setHeartbeat(int interval, const std::string & message = "HEARTBEAT");
// 启动心跳
void startHeartbeat();
// 停止心跳
void stopHeartbeat();
// 关闭套接字
void closeSocket();
// 设置UDP目标地址 (客户端使用)
void setUdpTarget(const std::string & ip, int port);
// 网络诊断
static void printNetworkDiagnostics();
private:
Protocol m_protocol;
SocketType m_type;
int m_socket;
bool m_isIPv6;
int m_timeout; // 超时时间(毫秒)
// 保活设置
bool m_keepAlive;
std::atomic<bool> m_heartbeatActive;
std::thread m_heartbeatThread;
std::string m_heartbeatMsg;
int m_heartbeatInterval;
std::mutex m_heartbeatMutex;
std::condition_variable m_heartbeatCond;
// UDP目标地址
std::string m_serverAddr;
int m_serverPort;
// 回调函数
ErrorCallback m_errorCallback;
ConnectionCallback m_connectionCallback;
// 应用超时设置
void applyTimeoutOptions();
// 错误处理
void handleError(const std::string & prefix);
void handleError(const std::string & prefix, int error);
// 处理accept错误
int handleAcceptError();
};
客户端操作
如果是 TCP 协议,客户端需要连接到服务器
// 线程安全的客户端管理器
class ClientManager {
public:
// 添加客户端
void addClient(int socket, std::thread&& thread);
// 移除客户端
void removeClient(int socket);
// 停止所有客户端线程
void stopAll();
// 获取当前客户端数量
size_t size() const;
private:
std::map<int, std::thread> m_clients;
mutable std::mutex m_mutex;
};
// TCP客户端 (支持自动重连)
inline void tcpClient(const std::string & serverIp = "127.0.0.1", int serverPort = 8888) {
std::atomic<bool> clientRunning(true);
int reconnectDelay = 1; // 初始重连延迟(秒)
int connectionAttempt = 0;
while (clientRunning) {
connectionAttempt++;
try {
NetWork client(NetWork::Protocol::TCP, NetWork::SocketType::CLIENT);
client.createSocket();
// 设置连接超时(3秒)
#ifdef _WIN32
DWORD timeout = 3000;
setsockopt(client.getSocket(), SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout));
#else
struct timeval tv;
tv.tv_sec = 3;
tv.tv_usec = 0;
setsockopt(client.getSocket(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
#endif
bool connected = false;
while (!connected && clientRunning) {
try {
CLog(C_INFO) << "尝试连接服务器[" << serverIp << ":" << serverPort << "] (尝试 #" << connectionAttempt << ")";
client.connect(serverIp, serverPort);
connected = true;
reconnectDelay = 1; // 重置重连延迟
connectionAttempt = 0;
CLog(C_INFO) << "TCP客户端已连接";
// 握手响应
try {
char buffer[256];
int bytes = client.recv(buffer, sizeof(buffer));
if (bytes > 0) {
buffer[bytes] = '\0';
if (strstr(buffer, "SERVER_HANDSHAKE") != nullptr) {
CLog(C_INFO) << "收到握手消息,发送响应";
client.send("CLIENT_ACK\n", 10);
}
}
}
catch (...) {
CLog(C_INFO) << "握手过程失败,继续通信";
}
// 设置保活和心跳
client.setKeepAlive(true);
client.setHeartbeat(5, "HEARTBEAT");
client.startHeartbeat();
}
catch (const std::exception& e) {
CLog(C_ERROR) << "连接失败: " << e.what();
// 指数退避重连
for (int i = 0; i < reconnectDelay && clientRunning; i++) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
reconnectDelay = (std::min)(reconnectDelay * 2, 60); // 最大60秒
connectionAttempt++;
}
}
int messageCount = 0;
bool connectionAlive = true;
while (connectionAlive && clientRunning) {
try {
// 构造消息
std::string msg = "CLIENT_MESSAGE #" + std::to_string(++messageCount) + "\n";
// 发送消息
client.send(msg.c_str(), msg.size());
CLog(C_INFO) << "已发送: " << msg.substr(0, msg.size() - 1); // 去除换行符
// 接收服务器回复
char buffer[1024];
int bytes = client.recv(buffer, sizeof(buffer));
if (bytes > 0) {
buffer[bytes] = '\0';
CLog(C_INFO) << "收到服务器回复: " << buffer;
}
else if (bytes == 0) {
CLog(C_INFO) << "服务器断开连接";
connectionAlive = false;
}
// 等待1秒
for (int i = 0; i < 10 && connectionAlive && clientRunning; i++) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
catch (const std::exception& e) {
CLog(C_ERROR) << "通信出错: " << e.what();
connectionAlive = false;
}
}
// 关闭当前连接
client.closeSocket();
if (connectionAlive == false && clientRunning) {
CLog(C_INFO) << "连接断开,尝试重新连接...";
}
}
catch (const std::exception& e) {
CLog(C_ERROR) << "TCP客户端错误: " << e.what();
// 等待一段时间后重试
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
}
总结
通过这个Network库,我们成功抽象了底层网络编程的复杂性,提供了简洁易用的 API 接口。通过 RAII 模式管理资源、跨平台兼容性处理、以及丰富的高级功能,使得开发者可以专注于业务逻辑而不是底层网络细节。
更多推荐



所有评论(0)