GrabBag/Test/tcpclient/tcp_client_test.cpp

392 lines
12 KiB
C++
Raw Normal View History

2025-10-12 16:46:46 +08:00
#include <iostream>
#include <thread>
#include <chrono>
#include <atomic>
#include <string>
#include <iomanip>
#include <ctime>
#include <sstream>
#include <mutex>
// 包含TCPClient头文件
#include "IVrTCPClient.h"
class TCPClientTest
{
private:
IVrTCPClient* m_pClient;
std::atomic<bool> m_bRunning;
std::atomic<bool> m_bConnected;
std::string m_sServerIP;
int m_nPort;
std::atomic<int> m_nRecvCount;
std::atomic<int> m_nSendCount;
std::atomic<size_t> m_nTotalRecvBytes;
std::thread m_sendThread;
std::thread m_statsThread;
std::mutex m_consoleMutex;
std::chrono::steady_clock::time_point m_startTime;
// 测试配置
bool m_bAutoSend; // 是否自动发送测试数据
int m_nSendInterval; // 发送间隔(毫秒)
int m_nSendSize; // 每次发送的数据大小(字节)
public:
/**
* @brief
* @param serverIP IP地址
* @param port
* @param autoSend
* @param sendInterval
* @param sendSize
*/
TCPClientTest(const std::string& serverIP, int port, bool autoSend = false,
int sendInterval = 1000, int sendSize = 64)
: m_pClient(nullptr), m_bRunning(false), m_bConnected(false),
m_sServerIP(serverIP), m_nPort(port), m_nRecvCount(0),
m_nSendCount(0), m_nTotalRecvBytes(0),
m_bAutoSend(autoSend), m_nSendInterval(sendInterval), m_nSendSize(sendSize)
{
// 创建TCPClient实例
m_pClient = IVrTCPClient::CreateInstance();
if (!m_pClient) {
std::cerr << "❌ Failed to create TCPClient instance" << std::endl;
}
}
/**
* @brief
*/
~TCPClientTest()
{
Stop();
// 等待线程结束
if (m_sendThread.joinable()) {
m_sendThread.join();
}
if (m_statsThread.joinable()) {
m_statsThread.join();
}
if (m_pClient) {
m_pClient->CloseDevice();
IVrTCPClient::DestroyInstance(m_pClient);
m_pClient = nullptr;
}
}
/**
* @brief
* @return true表示成功false表示失败
*/
bool Initialize()
{
if (!m_pClient) {
return false;
}
PrintLog("🔌 Connecting to " + m_sServerIP + ":" + std::to_string(m_nPort));
// 连接设备
int result = m_pClient->LinkDevice(m_sServerIP, m_nPort, true,
[this](IVrTCPClient* pClient, bool connected, void* pParam) {
this->OnConnectionEvent(pClient, connected, pParam);
}, nullptr);
if (result != 0) {
PrintLog("❌ Failed to connect to server, error code: " + std::to_string(result));
return false;
}
// 启动工作线程
result = m_pClient->StartWork(
[this](IVrTCPClient* pClient, const char* pData, const int nLen, void* pParam) {
this->OnDataReceived(pClient, pData, nLen, pParam);
}, nullptr);
if (result != 0) {
PrintLog("❌ Failed to start client work thread, error code: " + std::to_string(result));
return false;
}
PrintLog("✅ Client initialized successfully");
return true;
}
/**
* @brief
* @return true表示成功false表示失败
*/
bool Start()
{
m_bRunning = true;
m_startTime = std::chrono::steady_clock::now();
// 启动统计线程
m_statsThread = std::thread(&TCPClientTest::StatsLoop, this);
// 如果启用自动发送,启动发送线程
if (m_bAutoSend) {
m_sendThread = std::thread(&TCPClientTest::SendDataLoop, this);
PrintLog("📤 Auto-send enabled: " + std::to_string(m_nSendSize) +
" bytes every " + std::to_string(m_nSendInterval) + " ms");
}
PrintLog("🚀 Client started, waiting for data...");
return true;
}
/**
* @brief
*/
void Stop()
{
m_bRunning = false;
// 等待线程结束
if (m_sendThread.joinable()) {
m_sendThread.join();
}
if (m_statsThread.joinable()) {
m_statsThread.join();
}
PrintLog("🛑 Client stopped");
PrintFinalStats();
}
/**
* @brief
* @return
*/
int GetRecvCount() const
{
return m_nRecvCount.load();
}
/**
* @brief
* @return
*/
int GetSendCount() const
{
return m_nSendCount.load();
}
/**
* @brief
* @return true表示已连接false表示未连接
*/
bool IsConnected() const
{
return m_bConnected.load();
}
/**
* @brief
* @param message
* @return true表示成功false表示失败
*/
bool SendTestData(const std::string& message)
{
if (!m_pClient || !m_bConnected) {
PrintLog("⚠️ Cannot send: not connected");
return false;
}
bool result = m_pClient->SendData(message.c_str(), static_cast<int>(message.length()));
if (result) {
m_nSendCount++;
PrintLog("📤 Sent: " + message + " (" + std::to_string(message.length()) + " bytes)");
} else {
PrintLog("❌ Failed to send data");
}
return result;
}
private:
/**
* @brief
* @param pClient
* @param connected
* @param pParam
*/
void OnConnectionEvent(IVrTCPClient* pClient, bool connected, void* pParam)
{
m_bConnected = connected;
if (connected) {
PrintLog("✅ Connected to server");
} else {
PrintLog("❌ Disconnected from server (Auto-reconnect enabled)");
}
}
/**
* @brief
* @param pClient
* @param pData
* @param nLen
* @param pParam
*/
void OnDataReceived(IVrTCPClient* pClient, const char* pData, const int nLen, void* pParam)
{
m_nRecvCount++;
m_nTotalRecvBytes += nLen;
// 打印接收到的数据(限制长度)
std::string data(pData, std::min(nLen, 100));
if (nLen > 100) {
data += "...";
}
PrintLog("📥 Received #" + std::to_string(m_nRecvCount.load()) + ": [" + std::to_string(nLen) + " bytes] " + data);
}
/**
* @brief
*/
void SendDataLoop()
{
int counter = 0;
while (m_bRunning) {
if (m_bConnected && m_pClient) {
// 构造测试数据
std::string message = "Client-Test-" + std::to_string(++counter);
// 填充到指定大小
if (message.length() < static_cast<size_t>(m_nSendSize)) {
message.append(m_nSendSize - message.length(), 'X');
} else if (message.length() > static_cast<size_t>(m_nSendSize)) {
message.resize(m_nSendSize);
}
bool result = m_pClient->SendData(message.c_str(), static_cast<int>(message.length()));
if (result) {
m_nSendCount++;
} else {
PrintLog("❌ Failed to send data");
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(m_nSendInterval));
}
}
/**
* @brief
*/
void StatsLoop()
{
while (m_bRunning) {
std::this_thread::sleep_for(std::chrono::seconds(5));
if (m_bRunning) {
PrintStats();
}
}
}
/**
* @brief
*/
void PrintStats()
{
auto now = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::seconds>(now - m_startTime).count();
if (duration == 0) duration = 1; // 避免除零
double recvRate = static_cast<double>(m_nRecvCount.load()) / duration;
double sendRate = static_cast<double>(m_nSendCount.load()) / duration;
double bandwidth = static_cast<double>(m_nTotalRecvBytes.load()) / duration / 1024.0; // KB/s
std::ostringstream oss;
oss << "\n📊 Statistics (Running " << duration << "s)"
<< "\n Connected: " << (m_bConnected ? "Yes" : "No")
<< "\n Received: " << m_nRecvCount.load() << " msgs (" << std::fixed << std::setprecision(2) << recvRate << " msg/s)"
<< "\n Sent: " << m_nSendCount.load() << " msgs (" << std::fixed << std::setprecision(2) << sendRate << " msg/s)"
<< "\n Bandwidth: " << std::fixed << std::setprecision(2) << bandwidth << " KB/s"
<< "\n Total Recv: " << m_nTotalRecvBytes.load() << " bytes";
PrintLog(oss.str());
}
/**
* @brief
*/
void PrintFinalStats()
{
auto now = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::seconds>(now - m_startTime).count();
if (duration == 0) duration = 1;
std::ostringstream oss;
oss << "\n📈 Final Statistics:"
<< "\n Total Runtime: " << duration << " seconds"
<< "\n Total Received: " << m_nRecvCount.load() << " messages"
<< "\n Total Sent: " << m_nSendCount.load() << " messages"
<< "\n Total Bytes Received: " << m_nTotalRecvBytes.load() << " bytes"
<< "\n Average Receive Rate: " << std::fixed << std::setprecision(2)
<< (static_cast<double>(m_nRecvCount.load()) / duration) << " msg/s"
<< "\n Average Send Rate: " << std::fixed << std::setprecision(2)
<< (static_cast<double>(m_nSendCount.load()) / duration) << " msg/s";
PrintLog(oss.str());
}
/**
* @brief 线
* @param message
*/
void PrintLog(const std::string& message)
{
std::lock_guard<std::mutex> lock(m_consoleMutex);
auto now = std::time(nullptr);
char timeStr[20];
std::strftime(timeStr, sizeof(timeStr), "%H:%M:%S", std::localtime(&now));
std::cout << "[" << timeStr << "] " << message << std::endl;
}
};
int main(int argc, char* argv[])
{
std::cout << "TCP Client Test Program" << std::endl;
std::cout << "=======================" << std::endl;
// 默认连接参数
std::string serverIP = "127.0.0.1";
int port = 8080;
if (argc > 1) {
serverIP = argv[1];
}
if (argc > 2) {
port = std::stoi(argv[2]);
}
TCPClientTest clientTest(serverIP, port);
// 初始化客户端
if (!clientTest.Initialize()) {
std::cerr << "Failed to initialize client" << std::endl;
return -1;
}
// 启动客户端
if (!clientTest.Start()) {
std::cerr << "Failed to start client" << std::endl;
return -1;
}
// 运行一段时间或等待用户输入
std::cout << "Client is running. Press Enter to stop..." << std::endl;
while(true){
std::cin.get();
std::this_thread::sleep_for(std::chrono::seconds(10));
}
// 停止客户端
clientTest.Stop();
std::cout << "TCP Client Test completed!" << std::endl;
return 0;
}