GrabBag/Test/tcpclient/tcp_client_test.cpp

392 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 <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;
}