1. 程式人生 > >Qt---多執行緒應用的例子

Qt---多執行緒應用的例子

這裡寫圖片描述

伺服器端

這裡寫圖片描述

TimeThread建立TcpSocket,負責實現Run()函式,傳送伺服器端資訊,然後斷開連線。
TimeSever中建立TimeThread,實incomingConnection(int socketDescriptor)函式每當有新的客戶端連線時,建立新的執行緒,將執行緒結束函式與對話方塊中的退出按鈕繫結,然後啟動執行緒
Dialog中建立TimeSever,對客戶端監聽

.pro中新增:

QT       += network

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(); signals: void error(QTcpSocket::SocketError socketError); private: int socketDescriptor; }; #endif // TIMETHREAD_H

timethread.cpp

#include "timethread.h"
#include <QDateTime>
#include <QByteArray>
#include <QDataStream>

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_4_3); 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(int socketDescriptor);

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(int 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();
}

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 = 0);
    ~Dialog();

public slots:
    void slotShow();

private:
    QLabel *Label1;
    QLabel *Label2;
    QPushButton *quitBtn;
    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("多執行緒時間伺服器"));

    Label1 =new QLabel(tr("伺服器埠:"));
    Label2 = new QLabel;

    quitBtn = new QPushButton(tr("退出"));
    QHBoxLayout *BtnLayout = new QHBoxLayout;
    BtnLayout->addStretch(1);
    BtnLayout->addWidget(quitBtn);
    BtnLayout->addStretch(1);

    QVBoxLayout *mainLayout = new QVBoxLayout(this);
    mainLayout->addWidget(Label1);
    mainLayout->addWidget(Label2);
    mainLayout->addLayout(BtnLayout);

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

    count=0;
    timeServer = new TimeServer(this);
    if(!timeServer->listen())
    {
        QMessageBox::critical(this,tr("多執行緒時間伺服器"),
        tr("無法啟動伺服器:%1.").arg(timeServer->errorString()));
        close();
        return;
    }
    Label1->setText(tr("伺服器埠:%1.").arg(timeServer->serverPort()));
}

Dialog::~Dialog()
{

}

void Dialog::slotShow()
{
    Label2->setText(tr("第%1次請求完畢。").arg(++count));
}

main.cpp

#include "dialog.h"
#include <QApplication>

/*
 *TimeThread建立TcpSocket,負責實現Run()函式,傳送伺服器端資訊,然後斷開連線
 *TimeSever中建立TimeThread,實現incomingConnection(int socketDescriptor)函式
 *每當有新的客戶端連線時,建立新的執行緒,將執行緒結束函式與對話方塊中的退出按鈕繫結,然後啟動執行緒
 *Dialog中建立TimeSever,對客戶端監聽
 */

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

客戶端

這裡寫圖片描述

初始化中建立socket,點選“獲取時間”按鈕後,socket連線伺服器,
當伺服器傳送來資料時,訊號函式readyRead()執行,觸readTime()函式獲取伺服器端時間。
在讀取資料時,採用QDataStream

.pro

QT       += 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 = 0);
    ~TimeClient();
public slots:
    void enableGetBtn();
    void getTime();
    void readTime();
    void showError(QAbstractSocket::SocketError socketError);
private:
    QLabel *serverNameLabel;
    QLineEdit *serverNameLineEdit;
    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("伺服器名:"));
    serverNameLineEdit = new QLineEdit("Localhost");

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

    QGridLayout *layout = new QGridLayout;
    layout->addWidget(serverNameLabel, 0, 0);
    layout->addWidget(serverNameLineEdit, 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(serverNameLineEdit, 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();
}

TimeClient::~TimeClient()
{

}

void TimeClient::enableGetBtn()
{
    getBtn->setEnabled(!serverNameLineEdit->text().isEmpty() && !portLineEdit->text().isEmpty());
}

void TimeClient::getTime()
{
    getBtn->setEnabled(false);
    time2u =0;
    tcpSocket->abort();  //取消已有連線
    tcpSocket->connectToHost(serverNameLineEdit->text(), portLineEdit->text().toInt());
}

void TimeClient::readTime()
{
    QDataStream in(tcpSocket);
    in.setVersion(QDataStream::Qt_4_3);
    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);
}

main.cpp

#include "timeclient.h"
#include <QApplication>

/*
 * 初始化中建立socket,點選“獲取時間”按鈕後,socket連線伺服器,
 * 當伺服器傳送來資料時,訊號函式readyRead()執行,觸發readTime()函式獲取伺服器端時間
 * 在讀取資料時,採用QDataStream
 */
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    TimeClient w;
    w.show();

    return a.exec();
}