2020清华计算机大一下学期考试(第二题CS)

在这里插入图片描述在这里插入图片描述


/*
 *客户端:
 *继承于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 <QWidget>

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 <QLabel>
#include <QFileDialog>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QTextEdit>
#include <QComboBox>
#include <QTcpSocket>
#include <QFile>
#include <QTextStream>
#include <QDataStream>
#include <QTimer>
#include <QThread>
#include <QDebug>
#include <QElapsedTimer>

#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 <QWidget>
#include <QTcpSocket>

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<int> dataList;
    int NumCount = 0;
};

#endif // MYTCPSOCKET_H

******mytcpserver.h******
#ifndef MYTCPSERVER_H
#define MYTCPSERVER_H

#include <QWidget>
#include "mytcpsocket.h"
#include <QTcpServer>

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<mytcpsocket*> m_socketList;

public slots:
};

#endif // MYTCPSERVER_H
******mytcpsocket.cpp******

#include "mytcpsocket.h"
#include <QDebug>
#include <QThread>
#include <QElapsedTimer>

#define cout qDebug() << "[" << __FILE__ << ":" << __LINE__ <<"]"

mytcpsocket::mytcpsocket(qintptr socketdesc ,QTcpSocket *parent) : QTcpSocket(parent)
{
    //初始化
    this->setSocketDescriptor(socketdesc);
    //信号和槽函数的参数要一致;重名的error很多,特指QAbstractSocket::error
    connect(this, static_cast<void (QTcpSocket::*)(QAbstractSocket::SocketError)>(&QTcpSocket::error), this,&mytcpsocket::SocketErr);
}

void mytcpsocket::SocketErr(QAbstractSocket::SocketError socketError)
{
    mytcpsocket* Socket = static_cast<mytcpsocket*>(sender());
    cout << Socket->peerName() << socketError;
}

void mytcpsocket::ReadAndParseData()
{
    /*
     * 获取信号发射者->对应的通讯套接字
     * 接收字段,拆包分析包头关键字,Sort排序,Get获取
     * example:Sort#数据总数#data.....
     * Example:Get#10th
     * 返回,包头SortOK排序完成,Data返回数据
     * 以#拆包,超界无效
     */
    mytcpsocket *Socket = static_cast<mytcpsocket*>(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<int>());
         *cout<<dataList;
         */
         //升序
        std::sort(dataList.begin(),dataList.end());        
        Socket->write("SortOK#" + QString::number(Timer.elapsed()).toUtf8());
    }else if(Flag == "Get")
    {
        QString Serial = (Recv.section('#',1,1));
        cout << Serial;
        cout << NumCount;
        if(Serial == "Max")
        {
            Socket->write("Data#" + QString::number(dataList.at(NumCount-1)).toUtf8());
        }else if(Serial == "Min")
        {
            Socket->write("Data#" + QString::number(dataList.at(0)).toUtf8());
        }else
        {
            //正则替换,去掉"英文字母"
            int i = Serial.replace(QRegExp("[a-zA-Z]+"), "").toInt();
            if(i > NumCount-1 || i < 0)
            {
                //超界
                cout << "out of index";
                return;
            }else
            {
                Socket->write("Data#" + QString::number(dataList.at(i-1)).toUtf8());
            }
        }
    }
}
******mytcpserver.cpp******

#include "mytcpserver.h"
#include "mytcpsocket.h"
#include <QTcpServer>
#include <QTcpSocket>
#include <QDebug>
#include <QThread>

#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";
}
配套测试文件
清华的文件内容未知,看题描述自定义该文件。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值