源代码
我在代码外面都有十分具体的正文,所以就间接放上代码啦

1 客户端
头文件 mainwindow.h

ifndef MAINWINDOW_H

define MAINWINDOW_H

include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{

Q_OBJECT

public:

MainWindow(QWidget *parent = nullptr);~MainWindow();

signals:

void startConnect(unsigned short,QString);// 发送文件信号void sendFile(QString path);

private slots:

void on_connectServer_clicked();void on_selFile_clicked();void on_sendFile_clicked();

private:

Ui::MainWindow *ui;

};

endif // MAINWINDOW_H

源文件 mainwindow.cpp

include "mainwindow.h"

include "ui_mainwindow.h"

include <QMessageBox>

include <QThread>

include "sendfile.h"

include <QFileDialog>

MainWindow::MainWindow(QWidget *parent)

: QMainWindow(parent), ui(new Ui::MainWindow)

{

ui->setupUi(this);// 设置IP和端口ui->ip->setText("127.0.0.1");ui->port->setText("8989");// 设置进度条ui->progressBar->setRange(0,100);ui->progressBar->setValue(0);// 客户端在子线程中连贯服务器// 创立线程对象QThread* t = new QThread;// 创立工作对象SendFile* worker = new SendFile;// 将worker挪动到子线程t中worker->moveToThread(t);// 当发送sendFile信号,让worker的sendFile函数解决(子线程)connect(this,&MainWindow::sendFile,worker,&SendFile::sendFile);// 通过信号,让worker开始工作// 因为worker 曾经挪动到了子线程中,因而connectServer这个槽函数是在子线程中执行的connect(this,&MainWindow::startConnect,worker,&SendFile::connectServer);// 解决子线程发送的信号// 连贯胜利connect(worker,&SendFile::connectOK,this,[=](){    QMessageBox::information(this,"连贯服务器","曾经胜利的连贯了服务器,祝贺!");});// 断开连接connect(worker,&SendFile::gameover,this,[=](){    // 资源开释    t->quit();    t->wait();    worker->deleteLater();    t->deleteLater();});connect(worker,&SendFile::curPercent,ui->progressBar,&QProgressBar::setValue);// 启动线程t->start();

}

MainWindow::~MainWindow()
{

delete ui;

}

void MainWindow::on_connectServer_clicked()
{

QString ip = ui->ip->text();unsigned short port = ui->port->text().toUShort();emit startConnect(port,ip);

}

void MainWindow::on_selFile_clicked()
{

QString path = QFileDialog::getSaveFileName();// 判断门路是否为空if(path.isEmpty()){    QMessageBox::warning(this,"关上文件","抉择的文件门路不能为空");    return;}ui->filePath->setText(path);

}

void MainWindow::on_sendFile_clicked()
{

// 发送文件信号emit sendFile(ui->filePath->text());

}

头文件 Send File.h

ifndef SENDFILE_H

define SENDFILE_H

include <QObject>

include <QTcpSocket>

class SendFile : public QObject
{

Q_OBJECT

public:

explicit SendFile(QObject *parent = nullptr);// 连贯服务器void connectServer(unsigned short port,QString ip);// 发送文件void sendFile(QString path);

signals:

// 告诉主线程连贯胜利void connectOK();// 告诉主线程连贯胜利void gameover();// 告诉主线程发送文件进度百分比void curPercent(int num);

private:

QTcpSocket* m_tcp;

};

endif // SENDFILE_H

源文件SendFile.cpp

include "sendfile.h"

include <QFile>

include <QHostAddress>

include <QFileInfo>

SendFile::SendFile(QObject* parent) : QObject(parent)
{

}

void SendFile::connectServer(unsigned short port, QString ip)
{

m_tcp = new QTcpSocket;m_tcp->connectToHost(QHostAddress(ip),port);// 告诉主线程连贯胜利connect(m_tcp,&QTcpSocket::connected,this,&SendFile::connectOK);// 告诉主线程断开连接connect(m_tcp,&QTcpSocket::disconnected,this,[=](){    // 断开连接,开释资源    m_tcp->close();    m_tcp->deleteLater();    emit gameover();});

}

void SendFile::sendFile(QString path)
{

QFile file(path);// 获取文件信息QFileInfo info(path);int fileSize = info.size();file.open(QFile::ReadOnly);// 一行一行的读文件while(!file.atEnd()){    static int num = 0;    // 为了让服务器端晓得什么时候进行接管,所以得发送文件的大小    if(num ==0){        m_tcp->write((char*)&fileSize,4);    }    QByteArray line = file.readLine();    // 计算百分比,发给主线程    num +=line.size();    int percent =(num*100/fileSize);    emit curPercent(percent);    m_tcp->write(line);}

}

3.2 服务端
头文件mainwindow.h

ifndef MAINWINDOW_H

define MAINWINDOW_H

include <QMainWindow>

include <QTcpServer>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{

Q_OBJECT

public:

MainWindow(QWidget *parent = nullptr);~MainWindow();

private slots:

void on_setListen_clicked();

private:

Ui::MainWindow *ui;QTcpServer* m_s;

};

endif // MAINWINDOW_H

源文件maindow.cpp

include "mainwindow.h"

include "ui_mainwindow.h"

include <QMessageBox>

include <QTcpSocket>

include "recvfile.h"

MainWindow::MainWindow(QWidget *parent)

: QMainWindow(parent), ui(new Ui::MainWindow)

{

ui->setupUi(this);m_s = new QTcpServer(this);connect(m_s,&QTcpServer::newConnection,this,[=](){    QTcpSocket* tcp = m_s->nextPendingConnection();    // 创立子线程,tcp通过参数传递    RecvFile* subThread = new RecvFile(tcp);    subThread->start();    connect(subThread,&RecvFile::over,this,[=](){       subThread->exit();       subThread->wait();       subThread->deleteLater();       QMessageBox::information(this,"文件承受","文件接管结束!!!");    });});

}

MainWindow::~MainWindow()
{

delete ui;

}

void MainWindow::on_setListen_clicked()
{

unsigned short port = ui->port->text().toUShort();m_s->listen(QHostAddress::Any,port);

}

头文件recvfile.h

ifndef RECVFILE_H

define RECVFILE_H

include <QThread>

include <QTcpSocket>

class RecvFile : public QThread
{

Q_OBJECT

public:

explicit RecvFile(QTcpSocket* tcp,QObject *parent = nullptr);

protected:

void run() override;

private:

QTcpSocket* m_tcp;

signals:

void over();

};

endif // RECVFILE_H

源文件recvfile.cpp

include "recvfile.h"

include <QFile>

RecvFile::RecvFile(QTcpSocket tcp,QObject parent) : QThread(parent)
{

m_tcp = tcp;

}

void RecvFile::run()
{

QFile* file = new QFile("recv.txt");file->open(QFile::WriteOnly);// 接收数据connect(m_tcp,&QTcpSocket::readyRead,this,[=](){    static int count = 0;    static int total = 0;    if(count == 0){        m_tcp->read((char*)&total,4);    }    // 读出残余数据    QByteArray all = m_tcp->readAll();    count += all.size();    file->write(all);    if(count == total){        m_tcp->close();        m_tcp->deleteLater();        file->close();        file->deleteLater();        emit over();    }});// 进入事件循环exec();

}