1. 程式人生 > >Qt 多執行緒伺服器與客戶端

Qt 多執行緒伺服器與客戶端

文章目錄

  • 伺服器
  • 客戶端

思路

剛開始學是把tcp放到主執行緒的.
現在多執行緒就是把tcp放到新開闢的執行緒即可,和放在主執行緒的操作一樣

伺服器

  • 重寫void QTcpServer :: incomingConnection(qintptr socketDescriptor)函式
    有新連線的時候QTcpServer先呼叫此虛擬函式,引數socketDescriptor是原始的套接字.獲得原始套接字之後我們便可以進行處理

myserver.h

#ifndef MYSERVER_H
#define MYSERVER_H

#include <QTcpServer>

class MyThread;

class MyServer : public QTcpServer
{
    Q_OBJECT
public:
    MyServer(QWidget *parent = 0);

    virtual void incomingConnection(qintptr socketDescriptor);
signals:
    void sendReceivedFilename(const QString &fileName);
};

#endif // MYSERVER_H

myserver.cpp

#include "myserver.h"
#include "mythread.h"
#include <QDebug>

MyServer::MyServer(QWidget *parent)
{

}

void MyServer::incomingConnection(qintptr socketDescriptor)
{
    static int i = 0;
    MyThread *thread = new MyThread(0, socketDescriptor);
    thread->start();

    connect(thread, &MyThread::finished, [&]{
        qDebug() << "thread is over";
    });
    connect(thread, &MyThread::finished, &MyThread::deleteLater);
    connect(thread, &MyThread::sendReceivedFileName, this, &MyServer::sendReceivedFilename);
}

mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QWidget>

class MyTcpSocket;

class MyThread : public QThread
{
    Q_OBJECT
public:
    MyThread(QWidget *parent, qintptr socket);

private:
    qintptr p;
    MyTcpSocket *socket;
    virtual void run();

signals:
    void sendReceivedFileName(const QString &fileName);

};

#endif // MYTHREAD_H

mythread.cpp

#include "mythread.h"
#include "mysocket.h"
#include <QDebug>

MyThread::MyThread(QWidget *parent, qintptr socket) : QThread(parent)
{
    this->p = socket;

    connect(this, SIGNAL(finished()), SLOT(deletLater()));
}

void MyThread::run()
{
    MySocket *socket = new MySocket(0, this->p);
    connect(socket, &MySocket::disconnected, this, &MyThread::quit, Qt::DirectConnection);
    connect(socket, &MySocket::sendReceivedFileName, this, &MyThread::sendReceivedFileName);
    this->exec();
}

mysocket.h

#ifndef MYSOCKET_H
#define MYSOCKET_H

#include <QTcpSocket>
#include <QFile>


class MySocket : public QTcpSocket
{
    Q_OBJECT
public:
    MySocket(QWidget *parent, qintptr socket);
    //處理新來的連結
public slots:
    void on_connected();
public:
    QFile *file;
    QByteArray inBlock, outBlcok;
    int photoCount = 0;

    qint64 gotBytes = 0, fileBytes, fileNameSize, bytesReceived;
    qint64 fileSize, sendTotalBytes, bytesToWrite, bytesWritten;
    QString fileName;
    QString receivedMd5;

    int socketFlag;

    int photoN;
    int currentLocation;
    QStringList fileNameList;
    bool updateVersion;
    QString Tips;

    bool firstConnection = false;

    void replyMd5(bool boole = true);

    void sendFile(bool boole = true);

signals:
    void sendReceivedFileName(const QString &fileName);
};

#endif // MYSOCKET_H

mysocket.cpp

#include "mysocket.h"
#include <QDataStream>
#include <QCryptographicHash>
#include <QSettings>
#include <QMessageBox>
#include <QDebug>

enum socketFlag{
    md5 = 1,
    versionFlag
};

MySocket::MySocket(QWidget *parent, qintptr socket) : QTcpSocket(0)
{
    this->setSocketDescriptor(socket);

    connect(this, SIGNAL(readyRead()), this, SLOT(on_connected()));

    bytesReceived = 0;
    gotBytes = 0;
    fileBytes = 0;
    fileNameSize = 0;

    connect(this, &MySocket::disconnected, []{
        qDebug() << "disconnected";
    });
}

void MySocket::on_connected()
{
//讀到資料的操作
    qDebug() << "conn";
}

客戶端

h檔案

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "mytcpsockets.h"
#include <QTimer>

class QTcpSocket;

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

    void on_pushButton_2_clicked();

    void on_pushButton_3_clicked();

    void on_pushButton_4_clicked();

signals:
    void con(const QString &ip, int port);
    void discon();

private:
    Ui::MainWindow *ui;

    QTcpSocket *socket;

    QHash<int, QTcpSocket *> m_hash;

    MyTcpSockets *m_socket = nullptr;

    QTimer tm;
};

#endif // MAINWINDOW_H

cpp檔案

void MainWindow::on_pushButton_4_clicked()
{
    //執行緒傳送
    int b = ui->listWidget->count();
    QThread *th = new QThread;
    th->start();
    for (int i = 0; i < b; i++)
    {
        QString fileName = ui->listWidget->item(i)->text();

        MySocketTwo *two  = new MySocketTwo(fileName, i);
        connect(this, &MainWindow::con, two, &MySocketTwo::cnt, Qt::QueuedConnection);

        two->moveToThread(th);
    }
    emit this->con(ui->lineEdit->text(), 6666);

    return ;
}

mysockettwo.h

#ifndef MYSOCKETTWO_H
#define MYSOCKETTWO_H

#include <QTcpSocket>
#include <QIODevice>
#include <QHostAddress>

class QFile;
class MySocketTwo : public QTcpSocket
{
    Q_OBJECT
public:
    MySocketTwo(QString &fileName, int n, QObject *parent = 0);

    qint64 totalBytes, receivedBytes, sendBytes;
    QByteArray byteArray;
    int number = 0;
    QFile *file;
    QString fileName;

public slots:
    void cnt(const QString &ip, const int &port);
    
signals:
    void sendProgress(const int &i, const int &n);
    void sendData(const int &i, const QString &str);
};

#endif // MYSOCKETTWO_H

mysockettwo.cpp

#include "mysockettwo.h"
#include <QFile>
#include <QDataStream>
#include <QTcpSocket>
#include <QFileInfo>
#include <QCryptographicHash>

MySocketTwo::MySocketTwo(QString &fileName, int n, QObject *parent) : QTcpSocket(parent),
    totalBytes(0), receivedBytes(0), sendBytes(0)
{
//初始化訊號
    connect(this, &MySocketTwo::connected, this, &MySocketTwo::newFile);

    this->number = n;//分配序號
    this->fileName = fileName;
}


void MySocketTwo::cnt(const QString &ip, const int &port)
{
    this->connectToHost(ip, port);
    qDebug() << this->waitForConnected(5000);
    qDebug() << "connect";
}

void MySocketTwo::newFile()
{
//連線上伺服器之後的操作
}