QT中通过Tcp协议的多线程的文件传输(服务器)

首先新建一个项目命名为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

#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

#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

#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

#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的文件,里面是这样的

 选择发送这个文件

 

 接受完后我们去服务器的文件夹里可以找到这个接受来的文件

打开后内容是一样的

 

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Qt使用多线程进行TCP文件传输可以分为以下几个步骤: 1. 创建一个TCP服务器和一个TCP客户端。 2. 在TCP服务器,为每个连接创建一个线程,并在该线程处理文件的传输。 3. 在TCP客户端,创建一个线程,该线程负责发送文件给服务器。 4. 在服务器和客户端之间建立连接后,客户端将文件发送到服务器。 5. 服务器收到文件后,在相应的线程将文件保存到本地。 下面是一个简单的示例代码,可以供您参考: 1. TCP服务器端代码: ``` void Server::startServer() { tcpServer = new QTcpServer(this); connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection())); if (!tcpServer->listen(QHostAddress::Any, 12345)) { qDebug() << "Unable to start the server: " << tcpServer->errorString(); return; } qDebug() << "Server is running on port " << tcpServer->serverPort(); } void Server::newConnection() { QTcpSocket* clientSocket = tcpServer->nextPendingConnection(); ServerThread* thread = new ServerThread(clientSocket, this); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); thread->start(); } ``` 2. TCP服务器端线程代码: ``` ServerThread::ServerThread(qintptr socketDescriptor, QObject *parent) : QThread(parent), socketDescriptor(socketDescriptor) { } void ServerThread::run() { QTcpSocket tcpSocket; if (!tcpSocket.setSocketDescriptor(socketDescriptor)) { return; } QFile file("/path/to/save/file"); if (!file.open(QIODevice::WriteOnly)) { return; } QByteArray buffer; while (tcpSocket.bytesAvailable() > 0) { buffer = tcpSocket.read(1024); file.write(buffer); } file.close(); } ``` 3. TCP客户端代码: ``` void Client::sendFile(QString filePath) { QThread* thread = new QThread(); ClientWorker* worker = new ClientWorker(filePath); worker->moveToThread(thread); connect(thread, SIGNAL(started()), worker, SLOT(sendFile())); connect(worker, SIGNAL(finished()), thread, SLOT(quit())); connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater())); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); thread->start(); } ``` 4. TCP客户端线程代码: ``` ClientWorker::ClientWorker(QString filePath) : filePath(filePath) { } void ClientWorker::sendFile() { QTcpSocket tcpSocket; tcpSocket.connectToHost("127.0.0.1", 12345); if (!tcpSocket.waitForConnected()) { return; } QFile file(filePath); if (!file.open(QIODevice::ReadOnly)) { return; } QByteArray buffer; while (!file.atEnd()) { buffer = file.read(1024); tcpSocket.write(buffer); } file.close(); } ``` 请注意,这只是一个简单的示例代码,您需要根据您的实际需求进行修改和优化。同时,确保您的代码具有足够的安全性和可靠性,以避免数据丢失和安全问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值