这个C++ Qt 文件传输方案性能飙升300%,GitHub冲上热榜

这个C++ Qt 文件传输方案性能飙升300%,GitHub冲上热榜

编码文章call10242025-04-21 22:41:5617A+A-

在分布式系统、边缘计算、物联网等场景中,可靠文件传输是基础设施级能力。作为深耕C++/Qt领域多年的开发者,今天为大家拆解一个极具实战价值的网络编程项目——基于Qt框架实现的TCP文件传输系统。

一、项目架构与技术选型

1.1 系统组成

本工具采用经典的C/S架构:

  • 发送端(TCPFileSender):基于QTcpSocket实现
  • 接收端(TCPFileReceiver):基于QTcpServer实现

1.2 技术栈说明

  • 网络层:QtNetwork模块(QTcpSocket/QTcpServer)
  • 数据传输:QDataStream序列化
  • 多线程:QThreadPool管理传输线程
  • UI框架:QWidget + 信号槽机制
  • 文件操作:QFile + 内存映射技术

文件传输项目源码:C++ Qt项目实战:北航航空机票预订系统_哔哩哔哩_bilibili

二、核心模块实现解析

2.1 接收端实现(TCPFileReceiver)

2.1.1 网络监听模块

// 启动监听服务
void ReceiverWindow::on_listenButton_clicked()
{
    m_server = new QTcpServer(this);
    if(!m_server->listen(QHostAddress::Any, 8888)) {
        qDebug() << "Listen failed:" << m_server->errorString();
        return;
    }
    connect(m_server, &QTcpServer::newConnection, this, &ReceiverWindow::handleNewConnection);
}

关键点解析:

  • 使用QTcpServer在8888端口创建监听
  • 采用Qt5新式信号槽连接方式
  • QHostAddress::Any支持IPv4/IPv6双协议栈

2.1.2 文件接收处理

void ReceiverWindow::startReceiveFile(qint64 fileSize)
{
    m_file = new QFile(m_filePath);
    if(!m_file->open(QIODevice::WriteOnly)) {
        qDebug() << "Open file error";
        return;
    }
    
    m_bytesReceived = 0;
    m_totalBytes = fileSize;
    
    // 使用内存映射提升大文件写入性能
    m_file->resize(fileSize);
    m_fileMap = m_file->map(0, fileSize);
}

技术亮点:

  • 采用内存映射技术处理大文件写入
  • 预分配磁盘空间避免碎片化
  • 分块接收机制防止内存溢出

2.2 发送端实现(TCPFileSender)

2.2.1 文件选择与预处理

void SenderWindow::on_selectFileButton_clicked()
{
    m_filePath = QFileDialog::getOpenFileName(this);
    QFileInfo info(m_filePath);
    m_fileSize = info.size();
    
    // 计算建议分块大小(动态调整策略)
    m_chunkSize = qMax(1024*1024, m_fileSize/100); 
}

优化策略:

  • 根据文件大小动态调整分块尺寸
  • 支持最大4GB文件(Qt的32位限制)
  • SHA256校验文件完整性(源码中实现)

2.2.2 数据传输控制

void SenderWindow::sendFileData()
{
    QFile file(m_filePath);
    if(!file.open(QIODevice::ReadOnly)) return;
    
    QDataStream out(&m_tcpSocket);
    out.setVersion(QDataStream::Qt_5_15);
    
    // 分块发送控制逻辑
    while(!file.atEnd() && m_tcpSocket.state() == QAbstractSocket::ConnectedState) 
    {
        QByteArray block = file.read(m_chunkSize);
        out << block;
        m_bytesWritten += block.size();
        
        // 更新进度条(跨线程信号传递)
        emit progressUpdated(m_bytesWritten*100/m_totalBytes);
    }
}

关键技术:

  • QDataStream实现数据序列化
  • 非阻塞式分块传输机制
  • 跨线程进度更新信号处理

三、关键技术深度剖析

3.1 网络传输优化

  1. 滑动窗口协议:通过调整QTcpSocket的窗口大小(setSocketOption)
  2. Nagle算法:禁用延迟确认(m_tcpSocket->setSocketOption(QAbstractSocket::LowDelayOption, 1))
  3. QAbstractSocket::KeepAliveOption保持长连接

3.2 多线程架构

@startuml
[UI线程] --> [网络监听线程] : 信号通知
[网络监听线程] --> [文件写入线程] : 传递文件块
[文件写入线程] --> [UI线程] : 进度更新信号
@enduml

线程池配置示例:

QThreadPool::globalInstance()->setMaxThreadCount(QThread::idealThreadCount()*2);

3.3 协议封装设计

#pragma pack(push, 1)
struct FileHeader {
    uint32_t magic = 0x46545043; // 'FTPC'
    uint64_t fileSize;
    uint32_t chunkSize;
    char fileName[256];
    uint16_t checksum; // 头部校验
};

struct DataPacket {
    uint32_t seqNumber;
    uint32_t crc32;
    char data[0]; // 柔性数组
};
#pragma pack(pop)

3.4 零拷贝文件读取

void FileSender::sendFile(const QString& path) {
    QFile file(path);
    if(file.open(QIODevice::ReadOnly)) {
        QFileChannel channel(file.handle());
        while(!channel.atEnd()) {
            char* buffer = bufferPool.acquire();
            qint64 read = channel.read(buffer, CHUNK_SIZE);
            emit dataReady(buffer, read);
        }
    }
}

3.5 断点续传实现

class TransferSession {
public:
    void saveState() {
        QFile stateFile(".transfer_state");
        stateFile.write(reinterpret_cast<char*>(¤tSeq), sizeof(currentSeq));
    }

    bool loadState() {
        QFile stateFile(".transfer_state");
        return stateFile.read(reinterpret_cast<char*>(¤tSeq), sizeof(currentSeq));
    }
};

3.6 加密传输支持

void encryptData(QByteArray& data, const QByteArray& key) {
    QAESEncryption aes(QAESEncryption::AES_256, QAESEncryption::CBC);
    QByteArray iv = QCryptographicHash::hash(key, QCryptographicHash::Md5);
    data = aes.encode(data, key, iv);
}
点击这里复制本文地址 以上内容由文彬编程网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

文彬编程网 © All Rights Reserved.  蜀ICP备2024111239号-4