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()
{
//连接上服务器之后的操作
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值