/*
*客户端:
*继承于QWidget的派生类ClientWidget
*自定义提升控件QWidget
*QTcpSocket连接服务端,文件操作
*自定义协议: 1.以#拆包;包头分"Sort" and "Get"
* 2.Sort#数据总数#数据内容...
* 3.Get#10th
*/
/*
*服务端:
*继承于QTcpSocket的mytcpsocket
*继承于QTcpServer的mytcpserver
*每有新客户端连接,new 新的通信套接字和子线程处理
*同时为其注册connect信号与槽
*std::sort排序
*返回包:1.以#发包;包头分为"SortOK" and "Data"
*/
客户端
******ClientWidget.h******
#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H
#include
QT_BEGIN_NAMESPACE
class QTcpSocket;
class QLabel;
class QLineEdit;
class QFileDialog;
class QPushButton;
class QHBoxLayout;
class QVBoxLayout;
class QTextEdit;
class QComboBox;
class QElapsedTimer;
QT_END_NAMESPACE
class ClientWidget : public QWidget
{
Q_OBJECT
public:
explicit ClientWidget(QWidget *parent = nullptr);
private:
void CreateHBoxLayout1();
void CreateHBoxLayout2();
void CreateHBoxLayout3();
void CreateHBoxLayout4();
QTcpSocket *TcpSocket;
QLabel *LB_Title;
QLabel *LB_Operator;
QFileDialog *FileDialog;
QPushButton *PB_GetFilePath;
QPushButton *PB_Sort;
QPushButton *PB_GetResult;
QHBoxLayout *HBoxLayout1;
QHBoxLayout *HBoxLayout2;
QHBoxLayout *HBoxLayout3;
QHBoxLayout *HBoxLayout4;
QVBoxLayout *VBoxLayout;
QTextEdit *TE_ShowTimeCount;
QComboBox *CB_Box;
QTextEdit *TE_ShowOperate;
QString FilePath;
int SendTimeCount = 0;
int Count = 0;//数据总数
QElapsedTimer *Timer1;
signals:
public slots:
void GetFileInfo();
void ConnectServer();
void FileOperation();
void TimeStop();
void GetDataSend();
void GetServerResult();
void DisConnectedDeal();
void DealDestroyed();
};
#endif // CLIENTWIDGET_H
******ClientWidget.cpp******
#include "clientwidget.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define cout qDebug() << "[" << __FILE__ << ":" << __LINE__ << "]"
ClientWidget::ClientWidget(QWidget *parent) : QWidget(parent)
{
//如果再this->SetLayout 会警告
//Attempting to add QLayout "" to ClientWidget "", which already has a layout
VBoxLayout = new QVBoxLayout(this);//指定父对象 == setLayout
//第一行
CreateHBoxLayout1();
//第二行
CreateHBoxLayout2();
//第三行
CreateHBoxLayout3();
//第四行
CreateHBoxLayout4();
VBoxLayout->addItem(HBoxLayout1);
VBoxLayout->addItem(HBoxLayout2);
VBoxLayout->addItem(HBoxLayout3);
VBoxLayout->addItem(HBoxLayout4);
TcpSocket = new QTcpSocket;
//计时器
Timer1 = new QElapsedTimer;
connect(PB_GetFilePath,&QPushButton::clicked,this,&ClientWidget::GetFileInfo);
connect(TcpSocket,&QTcpSocket::connected,
[=]()
{
//链接上后,Sort有效
connect(PB_Sort,&QPushButton::clicked,this,&ClientWidget::FileOperation);
});
connect(TcpSocket,&QTcpSocket::readyRead,this,&ClientWidget::GetServerResult);
connect(PB_GetResult,&QPushButton::clicked,this,&ClientWidget::GetDataSend);
connect(this,&QWidget::destroyed,this,&ClientWidget::DealDestroyed);
connect(TcpSocket,&QTcpSocket::disconnected,this,&ClientWidget::DisConnectedDeal);
}
void ClientWidget::DealDestroyed()
{
cout << "DealDestroyed";
delete TcpSocket;
delete Timer1;
}
void ClientWidget::CreateHBoxLayout1()
{
HBoxLayout1 = new QHBoxLayout;
LB_Title = new QLabel(tr("DataSet"),this);
LB_Title->setFixedSize(40,40);
PB_GetFilePath = new QPushButton(tr("FilePath"),this);
PB_GetFilePath->setFixedSize(80,30);
PB_Sort = new QPushButton(tr("Sort"),this);
PB_Sort->setFixedSize(60,30);
HBoxLayout1->addWidget(LB_Title);
HBoxLayout1->addWidget(PB_GetFilePath);
HBoxLayout1->addWidget(PB_Sort);
}
void ClientWidget::CreateHBoxLayout2()
{
HBoxLayout2 =new QHBoxLayout;
TE_ShowTimeCount = new QTextEdit(this);
TE_ShowTimeCount->setFixedSize(260,40);
HBoxLayout2->addWidget(TE_ShowTimeCount);
}
void ClientWidget::CreateHBoxLayout3()
{
HBoxLayout3 = new QHBoxLayout;
LB_Operator = new QLabel(tr("Operator"),this);
CB_Box = new QComboBox(this);
PB_GetResult= new QPushButton(tr("Get"),this);
LB_Operator->setFixedSize(60,40);
CB_Box->setFixedSize(60,20);
PB_GetResult->setFixedSize(60,30);
PB_GetResult->setEnabled(false);
CB_Box->addItem(tr("Min"));
CB_Box->addItem(tr("Max"));
CB_Box->addItem(tr("10th"));
CB_Box->addItem(tr("20th"));
CB_Box->addItem(tr("100th"));
HBoxLayout3->addWidget(LB_Operator);
HBoxLayout3->addWidget(CB_Box);
HBoxLayout3->addWidget(PB_GetResult);
}
void ClientWidget::CreateHBoxLayout4()
{
HBoxLayout4 = new QHBoxLayout;
TE_ShowOperate = new QTextEdit(this);
TE_ShowOperate->setFixedSize(260,40);
HBoxLayout4->addWidget(TE_ShowOperate);
}
void ClientWidget::GetFileInfo()
{
FilePath = QFileDialog::getOpenFileName(this,tr("Open"),"/","Word(*.txt)");
if(FilePath.isNull())
{
cout << "File Path Get Failed";
return;
}
else
{
PB_Sort->setEnabled(true);
if(TcpSocket->state() == QAbstractSocket::ConnectedState)
{
return;
}else
{
emit ClientWidget::ConnectServer();
}
}
}
void ClientWidget::ConnectServer()
{
QString IP = QString("127.0.0.1");
//TcpSocket->abort();
//TcpSocket->reset();
TcpSocket->connectToHost(IP,2333);
}
void ClientWidget::FileOperation()
{
Timer1->restart();
cout << "ConnectSuccess!";
PB_Sort->setEnabled(false);
QFile File(FilePath);
cout << FilePath;
if(File.open(QIODevice::Text | QIODevice::ReadOnly))
{
Count = 0;
QString FileData;
QString str;
QTextStream Stream(&File);
while(!Stream.atEnd())
{
Count += 1;
Stream >> str;
FileData += str + "#";
}
cout << Count;
//用"#"拆包,第0号表示类型,Sort(排序),第1号是数据总数
//第0号 == Get(取值),第一号表示有序队列下标
TcpSocket->write(QString("Sort").toUtf8() + "#" + QString::number(Count).toUtf8() + "#" + FileData.toUtf8());
emit TimeStop();
File.close();
}
else
{
cout << "File Open Failed";
return;
}
}
void ClientWidget::GetDataSend()
{
TcpSocket->write(QString("Get").toUtf8() + "#" + CB_Box->currentText().toUtf8());
}
void ClientWidget::GetServerResult()
{
QString Recv = TcpSocket->readAll();
QString Flag = Recv.section("#",0,0);
cout << Recv;
cout << Flag;
//排序OK
if(Flag == "SortOK")
{
PB_GetResult->setEnabled(true);
TE_ShowTimeCount->append("SortTime(ms):"+Recv.section("#",1,1));
}else if(Flag == "Data")//Get数据
{
TE_ShowOperate->setText(QString::number(Recv.section("#",1,1).toInt()));
cout << (QString::number(Recv.section("#",1,1).toInt()));
}else
{
cout << "WrongInfo!";
return;
}
}
void ClientWidget::TimeStop()
{
if(Timer1->isValid())
{
TE_ShowTimeCount->setText(QString::number(Timer1->elapsed()) + "ms");
}
}
void ClientWidget::DisConnectedDeal()
{
cout << "DisConnected!";
PB_GetResult->setEnabled(false);
PB_Sort->disconnect();
}
服务端
******mytcpsocket.h******
#ifndef MYTCPSOCKET_H
#define MYTCPSOCKET_H
#include
#include
class mytcpsocket : public QTcpSocket
{
Q_OBJECT
public:
explicit mytcpsocket(qintptr socketdesc,QTcpSocket *parent = nullptr);
signals:
public slots:
void SocketErr(QAbstractSocket::SocketError socketError);
void ReadAndParseData();
private:
QVector dataList;
int NumCount = 0;
};
#endif // MYTCPSOCKET_H
******mytcpserver.h******
#ifndef MYTCPSERVER_H
#define MYTCPSERVER_H
#include
#include "mytcpsocket.h"
#include
class mytcpserver : public QTcpServer
{
Q_OBJECT
public:
explicit mytcpserver(const std::string &ip, quint16 port,QWidget *parent = nullptr);
signals:
protected:
//重构该虚函数,有新连接会自动调用
void incomingConnection(qintptr socketDescriptor);
private:
//Socket队列,新客户端进入,通讯套接字压入队列,注册一条Connect
QList m_socketList;
public slots:
};
#endif // MYTCPSERVER_H
******mytcpsocket.cpp******
#include "mytcpsocket.h"
#include
#include
#include
#define cout qDebug() << "[" << __FILE__ << ":" << __LINE__ <<"]"
mytcpsocket::mytcpsocket(qintptr socketdesc ,QTcpSocket *parent) : QTcpSocket(parent)
{
//初始化
this->setSocketDescriptor(socketdesc);
//信号和槽函数的参数要一致;重名的error很多,特指QAbstractSocket::error
connect(this, static_cast(&QTcpSocket::error), this,&mytcpsocket::SocketErr);
}
void mytcpsocket::SocketErr(QAbstractSocket::SocketError socketError)
{
mytcpsocket* Socket = static_cast(sender());
cout << Socket->peerName() << socketError;
}
void mytcpsocket::ReadAndParseData()
{
/*
* 获取信号发射者->对应的通讯套接字
* 接收字段,拆包分析包头关键字,Sort排序,Get获取
* example:Sort#数据总数#data.....
* Example:Get#10th
* 返回,包头SortOK排序完成,Data返回数据
* 以#拆包,超界无效
*/
mytcpsocket *Socket = static_cast(sender());
QString Recv = Socket->readAll();
cout << QThread::currentThread();
QString Flag = (Recv.section('#',0,0));
if(Flag == "Sort")
{
QElapsedTimer Timer;
Timer.start();
NumCount = (Recv.section('#',1,1)).toInt();
dataList.resize(NumCount);
for(int i = 0;i < NumCount ;i++)
{
//cout << (Recv.section('#',i+2,i+2)).toInt();
//cout << i;
//从0开始存,100个,即0~99
dataList.replace(i,(Recv.section('#',i+2,i+2)).toInt());
}
/*
*降序
*std::sort(dataList.begin(),dataList.end(),std::greater());
*cout<
******mytcpserver.cpp******
#include "mytcpserver.h"
#include "mytcpsocket.h"
#include
#include
#include
#include
#define cout qDebug() << "[" << __FILE__ << ":" << __LINE__ <<"]"
mytcpserver::mytcpserver(const std::string &ip, quint16 port,QWidget *parent) : QTcpServer(parent)
{
if(ip.empty())
{
this->listen(QHostAddress::LocalHost, port);
}
else
{
this->listen(QHostAddress(ip.c_str()), port);
}
}
//传进来一个(socketDescriptor)套接字描述符
void mytcpserver::incomingConnection(qintptr socketDescriptor)
{
mytcpsocket *Socket = new mytcpsocket(socketDescriptor);
m_socketList.append(Socket);
//为当前套接字注册Connect,每当readyRead执行处理槽函数
connect(Socket, &mytcpsocket::readyRead, Socket, &mytcpsocket::ReadAndParseData);
//为当前套接字new一个线程
QThread *Thread = new QThread(this);
//为当前套接字注册Connect,连接中断,线程退出
connect(Socket, &mytcpsocket::disconnected, Thread, &QThread::quit);
//为当前套接字注册Connect,线程停止,注销该套接字
connect(Thread,&QThread::finished,Socket,&mytcpsocket::deleteLater);
//mytcpsocket移入子线程
Socket->moveToThread(Thread);
Thread->start();
cout << "new connection";
}
配套测试文件
清华的文件内容未知,看题描述自定义该文件。