在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 模式管理资源、跨平台兼容性处理、以及丰富的高级功能,使得开发者可以专注于业务逻辑而不是底层网络细节。

完整实现

Logo

分享最新、最前沿的AI大模型技术,吸纳国内前几批AI大模型开发者

更多推荐