服务器压力测试软件
开始客户端界面 ThreadNum输入预想最大线程数,以及服务器端IP。 TotalOne--TotalFour 线程随机发送数,用rand()函数获得随机值,具体实现看代码实现,rand()%4+1; 取1-4,客户端发送1, 2, 3, 4 ,自己定义一个协议,用头H,尾e来确保数据传输正确。在此之前,服务器也要检测是否连接上客户端.使用多线程编程,以及QT的信号和槽机制,在客户端建立指定线程数,观察服务器端能承受最多线程值。服务器,客户端都设有跟踪观测窗口。界面是用ui做的,发送1,2,3,4,检测规则及协议可以自己设定,在此程序中,用的是H开头,e结尾,中间夹数字,这样的话,是为了保证数据传输正确,当然程序传值还进一步的加强使用了const,这样,我们只要检测头尾传输接收正确那么就间接保证了传输数据的合法正确性。
此软件也可以计算服务器数据处理能力,以及开最大线程数。
界面输入选项:
每个线程发送数据:m 开线程总数:n 每个数据发送间隔: k (ms) 每开个线程间隔时间: a(ms)
那么数据处理能力v如下计算:
(m*k)/(m*(m*k)/a) = 1000/v v=1000*m/a
当然这个处理能力是在允许开线程范围内,也就是说,我们在计算v时尽量开适合的少些线程。
开最大线程数是需要测试才能知道,不过也需要在数据处理能力范围内。
那么我们先开少线程,计算得v之后,在v范围内测试最大线程数。这就是根本想法。 接下来我们看看操作结果。

PC端,也就是客户端开12个线程。

ARM服务器端可以承受,那么就可以计算此时数据处理能力,用上面推导算法。v=1000*111/123 大概1000左右。

在数据处理范围内开1000个线程。

ARM服务器端显示接收数据和PC客户端不一致,那么说明线程超过了最大线程。

开252个线程,结果还是与ARM服务器端不一致。

且SecureCRT显示有一个线程创建错误。
那么推测减少一个线程。

很明显开251个线程和服务器刚和吻合,且服务器也确实全部接收到。
最终ARM板能开最大线程数为251,显然我们开线程都要考虑余地。
要给服务器留一个越界空间,比如最大能承受线程实际是251,那么我们做成产品或许只能说承受200。这就是余地选择。因为还有许多认为不能预测的因素会影响服务器性能。
部分源码:
客户端:
#include "testthread.h" #include <stdlib.h> #include <time.h> TestThread::TestThread(QObject *parent) : QThread(parent) { } TestThread::TestThread(QObject *parent, const char *host, const int DataTime, const long SendThreadData) : //通过构造函数传IP,这个问题调了较久才调好,注意! QThread(parent) { // hostIP = host; PerThreadData = SendThreadData; PerDataTime = DataTime; memset(hostIP,0,sizeof(hostIP)); memcpy(hostIP,host,sizeof(hostIP)); //然后就可以在run()里把hostIP直接当变量connecttohost了 } void TestThread::run() { srand(time(NULL)); socket = new QTcpSocket(); //connect(socket,SIGNAL(readyRead()),this,SLOT(onRead())); // socket->connectToHost("localhost",9090); // QString IP; socket->connectToHost(hostIP,9090); if(!socket->waitForConnected(30000)) { return; } long count,flag; for(count = 0; count < PerThreadData; count++) { flag = rand()%4 +1; switch(flag) { case 1: { socket->write("H1e"); socket->flush(); emit TestSignal(1); }; break; case 2: { socket->write("H2e"); socket->flush(); emit TestSignal(2); }; break; case 3: { socket->write("H3e"); socket->flush(); emit TestSignal(3); }; break; case 4: { socket->write("H4e"); socket->flush(); emit TestSignal(4); }; } msleep(455); //延时100ms } // exec(); //阻止线程退出 } //void TestThread::onRead() //{ // char buf[100]; // memset(buf,0,sizeof(buf)); // int length = socket->bytesAvailable(); // socket->read(buf,length); // if(buf[0] = 'H') // { // if(buf[2] = 'e') // { // int flag = buf[1] - '0'; // switch(flag) // { // case 1: // emit TestSignal(5); // break; // case 2: // emit TestSignal(6); // break; // case 3: // emit TestSignal(7); // break; // case 4: // emit TestSignal(8); // } // } // } //}
#include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); // IP = QString(ui->lineEdit_socket->text()); memset(count,0,sizeof(count)); // QString hostIP = QString(ui->lineEdit_socket->text()); time = new QTime(); connect(ui->pushButton_start,SIGNAL(clicked()),this,SLOT(onStart())); } void Widget::waitOn(long count) //每个线程相应时间 { time->restart(); while(time->elapsed() < count) { QCoreApplication::processEvents(); usleep(1000); } } void Widget::onStart() { int count; long MaxThread = (ui->lineEdit_thread->text()).toLong(); //QString IP = QString(ui->lineEdit_socket->text()); for(count = 0; count < MaxThread; count++) { TestThread *thread = new TestThread(this,(ui->lineEdit_socket->text()).toAscii(),(ui->lineEdit_ThreadTime->text()).toInt(),(ui->lineEdit_perThreadData->text()).toLong()); //connect(thread,SIGNAL(finished()),this,SLOT(deleteLater())); connect(thread,SIGNAL(TestSignal(int)),this,SLOT(onTestSignal(int))); thread->start(); waitOn((ui->lineEdit_ThreadTime->text()).toLong()); } } void Widget::onTestSignal(int tmp) { count[tmp]++; count[0]++; ui->lineEdit_1->setText(QString::number(count[1])); ui->lineEdit_2->setText(QString::number(count[2])); ui->lineEdit_3->setText(QString::number(count[3])); ui->lineEdit_4->setText(QString::number(count[4])); // ui-> ui->lineEdit_total->setText(QString::number(count[0])); } //void Widget::onServerSignal(const char *str) //{ // if(str[0] == 'H') // { // if(str[2] == 'e') // { // int flag = str[1] - '0'; // count[flag]++; // count[0]++; // ui->lineEdit_1->setText(QString::number(count[1])); // ui->lineEdit_2->setText(QString::number(count[2])); // ui->lineEdit_3->setText(QString::number(count[3])); // ui->lineEdit_4->setText(QString::number(count[4])); // ui->lineEdit_total->setText(QString::number(count[0])); // } // } //} Widget::~Widget() { delete ui; }
#ifndef TESTTHREAD_H #define TESTTHREAD_H #include <QThread> #include <QTcpSocket> class TestThread : public QThread { Q_OBJECT public: explicit TestThread(QObject *parent = 0); TestThread(QObject *parent,const char* host,const int DataTime,const long SendThreadData); signals: void TestSignal(int); public slots: private: QTcpSocket *socket; char hostIP[100]; int PerDataTime; long PerThreadData; // char buf[100]; protected: void run(); private slots: // void onRead(); }; #endif // TESTTHREAD_H
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include "testthread.h" #include <QTime> #include <QCoreApplication> #include <unistd.h> namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); private: Ui::Widget *ui; long count[10]; QTime *time; void waitOn(long); // QString IP; private slots: void onTestSignal(int); void onStart(); // void onServerSignal(const char *); //protected: // QString IP; }; #endif // WIDGET_H
服务器端:
#ifndef MYSERVER_H
#define MYSERVER_H
#include <QTcpServer>
#include "serverthread.h"
class MyServer : public QTcpServer
{
Q_OBJECT
public:
explicit MyServer(QObject *parent = 0);
signals:
void ServerSignal(const char *); //定义为const为了防止传值过程中数据意外被改变
public slots:
private:
ServerThread *thread;
private slots:
void incomingConnection(int);
void onThreadSignal(const char *);
};
#endif // MYSERVER_H
#ifndef SERVERTHREAD_H
#define SERVERTHREAD_H
#include <QThread>
#include <QTcpSocket>
class ServerThread : public QThread
{
Q_OBJECT
public:
explicit ServerThread(QObject *parent = 0);
ServerThread(QObject *parent,int handle);
signals:
void ThreadSignal(const char*);
public slots:
private:
int socketID; //线程编号
QTcpSocket *socket;
protected:
void run();
private slots:
void onRead();
// void onSend(const char *);
};
#endif // SERVERTHREAD_H
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "myserver.h"
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
MyServer *server;
long count[5];
char buf[100];
private slots:
void onServerSignal(const char *);
};
#endif // WIDGET_H
#include "myserver.h"
MyServer::MyServer(QObject *parent) :
QTcpServer(parent)
{
//this->incomingConnection();
}
void MyServer::incomingConnection(int handle) //handle线程顺序编号
{
thread = new ServerThread(this,handle);
connect(thread,SIGNAL(finished()),thread,SLOT(deleteLater()));
connect(thread,SIGNAL(ThreadSignal(const char*)),this,SLOT(onThreadSignal(const char*)));
thread->start();
}
void MyServer::onThreadSignal(const char * str)
{
emit ServerSignal(str); //emit推向主窗体
}
#include "serverthread.h"
ServerThread::ServerThread(QObject *parent) :
QThread(parent)
{
}
ServerThread::ServerThread(QObject *parent,int handle) :
QThread(parent)
{
socketID = handle;
}
void ServerThread::run()
{
socket = new QTcpSocket();
if(!socket->setSocketDescriptor(socketID)) //是否绑定成功
{
return;
}
connect(socket,SIGNAL(readyRead()),this,SLOT(onRead()));
exec(); //阻止线程退出
}
void ServerThread::onRead()
{
//char buf[100];
memset(buf,0,sizeof(buf)); //清空数组
int length = socket->bytesAvailable();
socket->read(buf,3); //读length这么多数据到buf中,这么直接取3也可以,因为是我们自己定的协议
emit ThreadSignal(buf);
// socket->write(buf,sizeof(buf));
socket->flush();
// onSend(buf);
}
// void ServerThread::onSend(const char *)
// {
// socket->write(str,sizeof(str));
// socket->flush();
// }
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
memset(count,0,sizeof(count));
server = new MyServer(this);
if(!server->listen(QHostAddress::Any,9090))
{
ui->textEdit->append("Listen failed");
return;
}
ui->textEdit->append("Listening....");
connect(server,SIGNAL(ServerSignal(const char*)),this,SLOT(onServerSignal(const char*)));
}
void Widget::onServerSignal(const char *str)
{
ui->textEdit->append(tr(str)); //str中转
if(str[0] == 'H')
{
if(str[2] == 'e')
{
int flag = str[1] - '0';
count[flag]++; //1--4接收数
count[0]++; //接受总数
ui->lineEdit_1->setText(QString::number(count[1])); //count[1]==count[tmp]不过不能代替,不然会覆盖其他
ui->lineEdit_2->setText(QString::number(count[2]));
ui->lineEdit_3->setText(QString::number(count[3]));
ui->lineEdit_4->setText(QString::number(count[4]));
ui->lineEdit_total->setText(QString::number(count[0]));
}
}
}
Widget::~Widget()
{
delete ui;
}
必须要记住一点的是,首先在.pro文件中添加network模块。如下:
QT += core gui network
TARGET = MyTestClient
TEMPLATE = app
SOURCES += main.cpp\
widget.cpp \
testthread.cpp
HEADERS += widget.h \
testthread.h
FORMS += widget.ui
各种头文件添加就不在赘述了。
大概框架是这样。压缩包服务器压力测试,里面有客户端和服务器端。 已经调试通过。
https://files.cnblogs.com/li-zi/MyTestClient.rar 客户端源码
https://files.cnblogs.com/li-zi/MytestServer.rar 服务器端源码
该源码通过交叉编译移植入ARM开发板,可以用于ARM开发板的压力测试。
本地PC机的压力测试等。 稍加改进也可以用于其他服务器压力测试。

浙公网安备 33010602011771号