client
This commit is contained in:
@@ -78,6 +78,83 @@ namespace QCL
|
|||||||
std::mutex clientsMutex_; ///< 保护clientSockets_的互斥锁
|
std::mutex clientsMutex_; ///< 保护clientSockets_的互斥锁
|
||||||
std::vector<int> clientSockets_; ///< 当前所有连接的客户端Socket集合
|
std::vector<int> clientSockets_; ///< 当前所有连接的客户端Socket集合
|
||||||
};
|
};
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/**
|
||||||
|
* @class TcpClient
|
||||||
|
* @brief 简单的TCP客户端类,支持自动连接、消息收发及断线重连
|
||||||
|
*
|
||||||
|
* 该类用于连接指定服务器IP与端口,
|
||||||
|
* 支持发送与接收字符串消息,
|
||||||
|
* 并提供自动重连与线程安全的消息接收。
|
||||||
|
*/
|
||||||
|
class TcpClient
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief 构造函数,指定服务器IP与端口
|
||||||
|
* @param serverIP 服务器IP地址
|
||||||
|
* @param serverPort 服务器端口号
|
||||||
|
*/
|
||||||
|
TcpClient(const std::string &serverIP, int serverPort);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 析构函数,自动断开连接并清理资源
|
||||||
|
*/
|
||||||
|
~TcpClient();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 连接服务器
|
||||||
|
* @return 连接成功返回true,失败返回false
|
||||||
|
*/
|
||||||
|
bool connectToServer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 断开与服务器的连接
|
||||||
|
*/
|
||||||
|
void disconnect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 向服务器发送字符串消息
|
||||||
|
* @param message 要发送的字符串
|
||||||
|
*/
|
||||||
|
void sendToServer(const std::string &message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 从服务器接收数据(单次调用)
|
||||||
|
* @param flag false: 非阻塞模式, true: 阻塞模式
|
||||||
|
* @return 收到的数据字符串(若无数据返回空字符串)
|
||||||
|
*/
|
||||||
|
std::string receiveFromServer(bool flag = true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取当前连接的服务器IP和端口
|
||||||
|
* @return 字符串形式的 "IP:Port"
|
||||||
|
*/
|
||||||
|
std::string getServerIPAndPort() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 判断客户端当前是否已连接
|
||||||
|
* @return 已连接返回true,否则返回false
|
||||||
|
*/
|
||||||
|
bool isConnected() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief 尝试自动重连服务器(可选)
|
||||||
|
* @param retryIntervalMs 重连间隔,单位毫秒
|
||||||
|
*/
|
||||||
|
void reconnectLoop(int retryIntervalMs = 3000);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int clientSock_; ///< 客户端Socket描述符
|
||||||
|
std::string serverIP_; ///< 服务器IP地址
|
||||||
|
int serverPort_; ///< 服务器端口号
|
||||||
|
std::atomic<bool> connected_; ///< 连接状态标志(线程安全)
|
||||||
|
std::atomic<bool> running_; ///< 是否保持运行(用于自动重连)
|
||||||
|
std::thread reconnectThread_; ///< 自动重连线程(可选)
|
||||||
|
mutable std::mutex socketMutex_; ///< 保护socket的互斥锁
|
||||||
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
/**
|
/**
|
||||||
* @brief 文件写入工具类(线程安全)
|
* @brief 文件写入工具类(线程安全)
|
||||||
|
130
src/Netra.cpp
130
src/Netra.cpp
@@ -210,6 +210,123 @@ namespace QCL
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
TcpClient::TcpClient(const std::string &serverIP, int serverPort)
|
||||||
|
: serverIP_(serverIP), serverPort_(serverPort), clientSock_(-1),
|
||||||
|
connected_(false), running_(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TcpClient::~TcpClient()
|
||||||
|
{
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TcpClient::connectToServer()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(socketMutex_);
|
||||||
|
|
||||||
|
clientSock_ = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (clientSock_ < 0)
|
||||||
|
{
|
||||||
|
perror("Socket creation failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sockaddr_in serverAddr{};
|
||||||
|
serverAddr.sin_family = AF_INET;
|
||||||
|
serverAddr.sin_port = htons(serverPort_);
|
||||||
|
if (inet_pton(AF_INET, serverIP_.c_str(), &serverAddr.sin_addr) <= 0)
|
||||||
|
{
|
||||||
|
perror("Invalid address");
|
||||||
|
close(clientSock_);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connect(clientSock_, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
|
||||||
|
{
|
||||||
|
perror("Connection failed");
|
||||||
|
close(clientSock_);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
connected_ = true;
|
||||||
|
running_ = true;
|
||||||
|
std::cout << "Connected to server " << serverIP_ << ":" << serverPort_ << std::endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpClient::disconnect()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(socketMutex_);
|
||||||
|
running_ = false;
|
||||||
|
if (connected_)
|
||||||
|
{
|
||||||
|
close(clientSock_);
|
||||||
|
connected_ = false;
|
||||||
|
std::cout << "Disconnected from server" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpClient::sendToServer(const std::string &message)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(socketMutex_);
|
||||||
|
if (!connected_)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ssize_t bytesSent = send(clientSock_, message.c_str(), message.size(), 0);
|
||||||
|
if (bytesSent <= 0)
|
||||||
|
{
|
||||||
|
perror("Send failed");
|
||||||
|
connected_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string TcpClient::receiveFromServer(bool flag)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(socketMutex_);
|
||||||
|
if (!connected_)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
char buffer[1024] = {0};
|
||||||
|
int flags = flag ? 0 : MSG_DONTWAIT;
|
||||||
|
ssize_t bytesRead = recv(clientSock_, buffer, sizeof(buffer) - 1, flags);
|
||||||
|
if (bytesRead <= 0)
|
||||||
|
{
|
||||||
|
if (bytesRead < 0 && errno == EAGAIN)
|
||||||
|
return ""; // 非阻塞下无数据
|
||||||
|
connected_ = false;
|
||||||
|
perror("Receive failed");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return std::string(buffer, bytesRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string TcpClient::getServerIPAndPort() const
|
||||||
|
{
|
||||||
|
return serverIP_ + ":" + std::to_string(serverPort_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TcpClient::isConnected() const
|
||||||
|
{
|
||||||
|
return connected_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TcpClient::reconnectLoop(int retryIntervalMs)
|
||||||
|
{
|
||||||
|
while (running_)
|
||||||
|
{
|
||||||
|
if (!connected_)
|
||||||
|
{
|
||||||
|
std::cout << "Attempting to reconnect..." << std::endl;
|
||||||
|
if (connectToServer())
|
||||||
|
{
|
||||||
|
std::cout << "Reconnected successfully!" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(retryIntervalMs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
WriteFile::WriteFile(const std::string &filePath)
|
WriteFile::WriteFile(const std::string &filePath)
|
||||||
: filePath_(filePath) {}
|
: filePath_(filePath) {}
|
||||||
|
|
||||||
@@ -314,7 +431,7 @@ namespace QCL
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WriteFile::writeAfterPatternOrAppend(const std::string &pattern, const std::string &content)
|
bool WriteFile::writeAfterPatternOrAppend(const std::string &pattern, const std::string &content)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(writeMutex_);
|
std::lock_guard<std::mutex> lock(writeMutex_);
|
||||||
|
|
||||||
@@ -507,16 +624,19 @@ namespace QCL
|
|||||||
// return lines;
|
// return lines;
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(mtx_);
|
std::lock_guard<std::mutex> lock(mtx_);
|
||||||
if (!file_.is_open()) {
|
if (!file_.is_open())
|
||||||
|
{
|
||||||
file_.open(filename_, std::ios::in | std::ios::binary);
|
file_.open(filename_, std::ios::in | std::ios::binary);
|
||||||
if (!file_.is_open()) return {};
|
if (!file_.is_open())
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
file_.clear();
|
file_.clear();
|
||||||
file_.seekg(0, std::ios::beg);
|
file_.seekg(0, std::ios::beg);
|
||||||
|
|
||||||
std::vector<std::string> lines;
|
std::vector<std::string> lines;
|
||||||
std::string line;
|
std::string line;
|
||||||
while (std::getline(file_, line)) lines.push_back(line);
|
while (std::getline(file_, line))
|
||||||
|
lines.push_back(line);
|
||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user