首先新建一个项目命名为SendClientSever
因为要进行网络通信,在pro文件的第一行代码中添加network
一、窗口设计
拖一个Widget里面放入label,lineEdit,pushbutton,名称如图修改
程序设计
子线程recvfile类
新建一个类用来执行子线程
将新建的类的头文件、recvfie.h文件和.cpp的继承对象改为QThread,我们后面要用到其的run函数用来实现多线程
在recvfile.h文件中定义run函数,alt+enter可以转到cpp中添加定义因为在主线程中要创建一个RecvFile类的对象,用到其中的run进行子线程操作,要用到tcp进行通信,我们添加tcp这个参数
我们先常见一个QSoketTcp类的对象m_tcp用来接受从主线程传来的tcp
我们在再添加一个over的信号,如果文件传输完成我们就发送over这个信号给主线程
先接受从主线程传来的tcp参数
然后在recvfile.cpp在实现run函数,也就是子线程的操作
主线程mainwindow类
去mianwindow中定义一个QTcpsever的指针,用来与客户端通信
右键窗口的启动监听选择转到槽函数的clicked
实现槽函数
在构造函数中,去实例化对象,开启子线程
如果文件传输完毕就关闭子线程的操作
完整代码
recvfile.h
cpp
#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();
public slots:
};
#endif // RECVFILE_H
recvfile.cpp
cpp
#include "recvfile.h"
#include<QFile>
RecvFile::RecvFile(QTcpSocket *tcp,QObject *parent) : QThread(parent)
{
m_tcp = tcp;
}
void RecvFile::run()
{
// 创建一个新的QFile对象,用于接收文件并保存为"recv.txt"
QFile *file = new QFile("recv.txt");
// 以只写方式打开文件,如果文件已存在,将覆盖其内容
file->open(QFile::WriteOnly);
// 连接QTcpSocket的readyRead信号到接收数据的lambda函数
connect(m_tcp, &QTcpSocket::readyRead, this, [=]()
{
// 静态变量用于在lambda函数调用之间保持其值
static int count = 0; // 已接收的数据字节数
static int total = 0; // 总数据字节数(从文件头读取)
// 如果是第一次读取数据,读取文件的总大小
if(count == 0)
{
// 从套接字中读取前4个字节,表示文件的总大小
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();
}
});
// 进入事件循环,保持线程活跃,等待readyRead信号的触发
exec();
}
mainwindow.h
cpp
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include<QTcpServer>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_setListen_clicked();
private:
Ui::MainWindow *ui;
QTcpServer *m_s;
};
#endif // MAINWINDOW_H
mainwindow.cpp
cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTcpSocket>
#include<QMessageBox>
#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,[=]()//如果有客户端连接就会收到一个newconnect的信号
{
QTcpSocket *tcp = m_s->nextPendingConnection();//通过TcpSever中的方法返回一个用于通信的套接字tcp
RecvFile *subThread = new RecvFile(tcp);//实例化一个RecvFile类的对象进行子线程的操作,传入tcp参数
subThread->start();//开启子线程
connect(subThread,&RecvFile::over,this,[=]()//如果从RecvFlie类中收到一个over的信号,表示文件传输完成
{
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();//将ui中输入的端口号转换为无符号短整型存储
m_s->listen(QHostAddress::Any,port);//设置监听
}
别忘了在pro代码第一行加入 network
运行实例
我在桌面上创建了一个a.txt的文件,里面是这样的
选择发送这个文件
接受完后我们去服务器的文件夹里可以找到这个接受来的文件
打开后内容是一样的