共计 5145 个字符,预计需要花费 13 分钟才能阅读完成。
源代码
我在代码外面都有十分具体的正文,所以就间接放上代码啦
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();
}