源代码
我在代码外面都有十分具体的正文,所以就间接放上代码啦
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();
}