Qt多线程——实现一个多线程的网络时间服务器

1.要求

我们需要实现一个多线程的网络实际服务器:每当有新的客户请求到达时,服务器将启动一个新的线程为它返回当前的时间,服务完毕之后,这个线程将会自动退出。同时,用户界面会显示当前已经接收请求的次数。

2.执行效果

在这里插入图片描述

3.代码实现

1.服务端代码

创建 Qt项目名为 TimeServer,定义服务器端界面类 Dialog继承自 QDialog

TimeServer.pro中添加 network

在这里插入图片描述

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QLabel>
#include <QPushButton>


class TimeServer;

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = nullptr);
    ~Dialog();

    //监听端口
    QLabel * port_label;
    //请求次数
    QLabel * request_count_label;

    //退出按钮
    QPushButton * quitBtn;

public slots:
    //用于界面上显示的请求次数
    void slotShow();

private:
   TimeServer * timeServer;
   int count;

};
#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QMessageBox>

#include "timeserver.h"


Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    setWindowTitle(tr("多线程时间服务器"));

    port_label = new QLabel(tr("服务器端口:"));

    request_count_label = new QLabel;

    quitBtn = new QPushButton(tr("退出"));

    count = 0;

    timeServer = new TimeServer(this);

    QHBoxLayout * btnLayout = new QHBoxLayout;
    btnLayout->addStretch(1);
    btnLayout->addWidget(quitBtn);
    btnLayout->addStretch(1);

    QVBoxLayout *mainLayout = new QVBoxLayout(this);

    mainLayout->addWidget(port_label);
    mainLayout->addWidget(request_count_label);
    mainLayout->addLayout(btnLayout);

    if(!timeServer->listen()){
        QMessageBox::critical(this,tr("多线程时间服务器"),
                             tr("无法启动服务器: %1. ").arg(timeServer->errorString()));
        close();
        return;
    }
    port_label->setText(tr("服务器端口 : %1.").arg(timeServer->serverPort()));

    //点击退出按钮 退出
    connect(quitBtn,SIGNAL(clicked()),this,SLOT(close()));

}

void Dialog::slotShow(){
    request_count_label->setText(tr("第 %1 次请求完毕.").arg(++count));

}

Dialog::~Dialog()
{
}

timethread.h

#ifndef TIMETHREAD_H
#define TIMETHREAD_H

#include <QThread>
#include <QtNetwork>
#include <QTcpSocket>

class TimeThread : public QThread
{
    Q_OBJECT
public:
    TimeThread(int socketDescriptor,QObject * parent = 0);
    void run() override;

signals:
   void error(QTcpSocket::SocketError socketError);

private:
   int socketDescriptor;
};

#endif // TIMETHREAD_H

timethread.cpp

#include "timethread.h"

TimeThread::TimeThread(int socketDescriptor,QObject * parent):
    QThread(parent),socketDescriptor(socketDescriptor)
{

}

void TimeThread::run(){
   QTcpSocket tcpSocket;

   //连接失败
   if(!tcpSocket.setSocketDescriptor(socketDescriptor)){
       emit error(tcpSocket.error());
       return;
   }

   QByteArray block;
   QDataStream out(&block , QIODevice::WriteOnly);
   out.setVersion(QDataStream::Qt_5_9);

   //获取当前时间的秒数
   uint time2u = QDateTime::currentDateTime().toTime_t();
   out<<time2u;

   tcpSocket.write(block);
   //断开连接
   tcpSocket.disconnectFromHost();
   //等待返回
   tcpSocket.waitForDisconnected();
}

timeserver.h

#ifndef TIMESERVER_H
#define TIMESERVER_H

#include <QTcpServer>

class Dialog;  //服务端的声明

class TimeServer : public QTcpServer
{
    Q_OBJECT
public:
    TimeServer(QObject * parent = 0);

protected:
    void incomingConnection(qintptr socketDescriptor) override;

private:
   Dialog * dlg;
};

#endif // TIMESERVER_H

timeserver.cpp

#include "timeserver.h"

#include "timethread.h"
#include "dialog.h"


TimeServer::TimeServer(QObject * parent) : QTcpServer(parent)
{
    dlg = (Dialog*) parent;
}

void TimeServer::incomingConnection(qintptr socketDescriptor){
    TimeThread * thread = new TimeThread(socketDescriptor,0);

    connect(thread,SIGNAL(finished()),dlg,SLOT(slotShow()));

    connect(thread,SIGNAL(finished()),thread,SLOT(deleteLater()),
            Qt::DirectConnection);

    thread->start();
}

main.cpp

#include "dialog.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Dialog w;
    w.show();
    return a.exec();
}

2. 客户端代码

创建 Qt项目名为 TimeClient,定义服务器端界面类 TimeClient继承自 QDialog

TimeClient.pro中添加 network

在这里插入图片描述

timeclient.h

#ifndef TIMECLIENT_H
#define TIMECLIENT_H

#include <QDialog>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QDateTimeEdit>
#include <QTcpSocket>
#include <QAbstractSocket>


class TimeClient : public QDialog
{
    Q_OBJECT

public:
    TimeClient(QWidget *parent = nullptr);
    ~TimeClient();

public slots:
    void enableGetBtn();
    void getTime();
    void readTime();
    void showError(QAbstractSocket::SocketError socketError)    ;

private:
   QLabel * serverNameLabel;
   QLineEdit * serverNameEdit;
   QLabel * portLabel;
   QLineEdit * portLineEdit;
   QDateTimeEdit * dateTimeEdit;
   QLabel * stateLabel;

   QPushButton * getBtn;
   QPushButton * quitBtn;

   uint time2u;
   QTcpSocket * tcpSocket;
};
#endif // TIMECLIENT_H

timeclient.cpp

#include "timeclient.h"

#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QDataStream>
#include <QMessageBox>


TimeClient::TimeClient(QWidget *parent)
    : QDialog(parent)
{
    setWindowTitle((tr("多线程时间服务客户端")));

    serverNameLabel = new QLabel(tr("服务器名:"));
    serverNameEdit = new QLineEdit(tr("Localhost"));

    portLabel = new QLabel(tr("端口:"));
    portLineEdit = new QLineEdit;

    QGridLayout * layout = new QGridLayout;
    layout->addWidget(serverNameLabel,0,0);
    layout->addWidget(serverNameEdit,0,1);
    layout->addWidget(portLabel,1,0);
    layout->addWidget(portLineEdit,1,1);

    dateTimeEdit = new QDateTimeEdit(this);
    QHBoxLayout *layout1 = new QHBoxLayout;
    layout1->addWidget(dateTimeEdit);

    stateLabel = new QLabel(tr("获取时间"));
    QHBoxLayout * layout2 = new QHBoxLayout;
    layout2->addWidget(stateLabel);

    getBtn = new QPushButton(tr("获取时间"));
    getBtn->setDefault(true);
    getBtn->setEnabled(false);
    quitBtn = new QPushButton(tr("退出"));
    QHBoxLayout * layout3 = new QHBoxLayout;
    layout3->addStretch();
    layout3->addWidget(getBtn);
    layout3->addWidget(quitBtn);

    QVBoxLayout * mainLayout = new QVBoxLayout(this);

    mainLayout->addLayout(layout);
    mainLayout->addLayout(layout1);
    mainLayout->addLayout(layout2);
    mainLayout->addLayout(layout3);

    connect(serverNameEdit,SIGNAL(textChanged(QString)),
            this,SLOT(enableGetBtn()));

    connect(portLineEdit,SIGNAL(textChanged(QString)),
            this,SLOT(enableGetBtn()));

    connect(getBtn,SIGNAL(clicked()),this,SLOT(getTime()));
    connect(quitBtn,SIGNAL(clicked()),this,SLOT(close()));

    tcpSocket = new QTcpSocket(this);

    connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readTime()));
    connect(tcpSocket,SIGNAL(error(QAbstractSocket::SocketError)),
            this,SLOT(showError(QAbstractSocket::SocketError)));

    portLineEdit->setFocus();
}

void TimeClient::enableGetBtn(){
    //如果 serverName 和 port 都不为空,说明已经获取到了
    //即可以再次点击获取下一次的数据,故为 true
    getBtn->setEnabled(!serverNameEdit->text().isEmpty() && !portLineEdit->text().isEmpty());

}

void TimeClient::getTime(){
    getBtn->setEnabled(false);
    time2u = 0;
    tcpSocket->abort();

    //Tcp 连接
    tcpSocket->connectToHost(serverNameEdit->text(),portLineEdit->text().toInt());

}

void TimeClient::readTime(){
    QDataStream in(tcpSocket);
    in.setVersion(QDataStream::Qt_5_9);
    if(time2u == 0){
        if(tcpSocket->bytesAvailable() < (int) sizeof(uint)) return;
        in >> time2u;
    }
    dateTimeEdit->setDateTime(QDateTime::fromTime_t(time2u));
    getBtn->setEnabled(true);
}

void TimeClient::showError(QAbstractSocket::SocketError socketError){
    switch(socketError){
       case QAbstractSocket::RemoteHostClosedError:{
            break;
       }
       case QAbstractSocket::HostNotFoundError:{
            QMessageBox::information(this,tr("时间服务客户端"),tr("主机不可达!"));
            break;
       }
       case QAbstractSocket::ConnectionRefusedError:{
            QMessageBox::information(this,tr("时间服务客户端"),tr("连接被拒绝!"));
            break;
       }
       default:{
            QMessageBox::information(this,tr("时间服务客户端"),
                                     tr("产生如下错误: %1 .").arg(tcpSocket->errorString()));
       }
    }
     getBtn->setEnabled(true);
}


TimeClient::~TimeClient()
{
}

main.cpp

#include "timeclient.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    TimeClient w;
    w.show();
    return a.exec();
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值