# 局域网文件传输工具 **Repository Path**: LTSKF/LANFileTransfer ## Basic Information - **Project Name**: 局域网文件传输工具 - **Description**: No description available - **Primary Language**: C++ - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-04-07 - **Last Updated**: 2025-04-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: Qt, TCP, file ## README # 局域网文件传输工具 #### 介绍 本项目是一个基于Qt开发的局域网文件传输工具,在同一网络下可以实现PC设备之间的点对点单向传输。 #### 软件架构 基于Qt 使用cpp语言 Tcp协议 #### 安装教程 1. fork项目。 2. 启动Qt进行编译运行。 3. 启动服务器端选择需要传输文件所在文件夹(该步骤会读取文件夹中所有文件发给客户端,请注意路径安排)。 4. 客户端启动,输入ip和端口(由服务器端提供),连接成功后会获取可下载文件列表,选择列表点击下载就可以了。 5. 该项目非常简陋,只是初学Tcp后实践开发的小型项目,没法保证传输数据的绝对安全。 #### 参与贡献 1. [灵荼山克府 (LTSKF) - Gitee.com](https://gitee.com/LTSKF) [ltskf@qq.com](https://gitee.com/link?target=mailto%3Altskf%40qq.com) #### 项目展示 ![](./mdImage/PixPin_2025-04-07_18-50-01.png) ![](./mdImage/PixPin_2025-04-08_11-54-30.png) #### 项目介绍 1. 该项目分成两部分,分别是客服端工程文件和服务器端工程文件,下面将从这两个方面对项目进行介绍。 2. 首先是服务器工程文件。 1. 文件夹选择按钮点击事件 ```cpp // 选择文件夹按钮的点击事件 void MainWindow::on_pushButtonChooseDir_clicked() { QString tempPath = QFileDialog::getExistingDirectory(); if(tempPath == nullptr){ QMessageBox::information(this, "注意", "你需要选择一个文件夹才行!"); return ; } dirPath = tempPath; ui->pushButtonOpenServer->setEnabled(true); } ``` 按钮被点击后会弹出路径选择窗口选择路径,选择完成后路径会保存到成员变量中备用。 2. 开启服务器按钮被点击后的事件 ```cpp // 打开服务器服务的按钮点击事件 void MainWindow::on_pushButtonOpenServer_clicked() { // 开启服务器的监听, 端口 server->listen(QHostAddress(ui->comboBoxIPAddress->currentText()), 6789); ui->textBrowserLog->append("服务器启动监听,等待客户端连接"); // 在客户端连接后配置信号和槽 connect(server, &QTcpServer::newConnection, this, [this]{ if(socket != nullptr)// 只允许一个客户端连接 return; socket = server->nextPendingConnection(); ui->pushButtonChooseDir->setEnabled(false); ui->pushButtonOpenServer->setEnabled(false); ui->textBrowserLog->append("客户端连接成功!!!"); downloadItemSendToClient(); connectSocket(); }); } ``` 首先服务器会监听客户端的连接,设置了ip地址和端口号,然后配置信号和槽,newConnection是新客户端连接时server发出的信号,接收到该信号后配置ui状态,并通过nextPendingConnection获取与新客户端通讯的套接字,注意,这里是单用户,所以没有多线程等处理。之后将下载信息封装后传递给客户端。 3. 关键代码,读取文件并将文件发送给客户端 ```cpp // 打开成功,传输文件(关键代码) void MainWindow::sendFile(QFile &file) { // 先发送标识符表示即将开始传输 //socket->write("8"); //socket->flush(); while (!file.atEnd()) { // 假设目标是x kb/s, 数字可以换成 x * 1024; socket->write(file.read(1024 * 5)); qDebug() << "发送中"; // 可以添加适当的延迟,确保数据发送完成 //QThread::msleep(50); socket->waitForBytesWritten(); } //socket->waitForBytesWritten(); // 传输结束 传输标识符6,在大型项目中这些数字标识符可以用宏替换 //socket->write("6"); ui->textBrowserLog->append("下载完毕!!!"); file.close(); } ``` 通过file对象读取文件内容,将文件内容循环发送给客户端,发送一次后就需要等待刷新套接字缓存。 3. 接着是客户端 1. 点击连接按钮尝试连接服务器 ```cpp // 点击连接按钮的监听事件 void MainWindow::on_pushButtonConnect_clicked() { QString ipAddress = ui->lineEditIPAddress->text(); QString port = ui->lineEditPort->text(); if(ipAddress == nullptr || port == nullptr){ QMessageBox::information(this, "注意", "请确保ip和port都已经填写!"); return ; } // 连接服务器 socket->connectToHost(QHostAddress(ipAddress), port.toUInt()); socketConnect(); } ``` connectToHost是关键代码 2. 点击下载按钮的事件处理 ```cpp // 点击下载按钮的监听事件 void MainWindow::on_pushButtonDowload_clicked() { QString tempPath = QFileDialog::getExistingDirectory(); if(tempPath == nullptr){ QMessageBox::information(this, "注意", "你需要选择一个文件夹才行!"); return ; } filePath = tempPath; // 封装后的字符串 QString encapsulatedStr = ui->listWidgetDowloadItemList->currentItem()->text(); // 按分隔符分割字符串 QStringList parts = encapsulatedStr.split("\t|\t"); if (parts.size() == 2) { fileName = parts[0]; QString sizeStr = parts[1].remove(" 字节"); // 设置进度条的最大值 ui->progressBarDowload->setMaximum(sizeStr.toUInt()); socket->write(fileName.toUtf8()); isLoad = true; qDebug() << "准备接收文件"; } } ``` 还是先选文件夹,之后将选中的项目读取并拆分成两个字符串分别包含着项目名称和字节数等信息,将名称发送给服务器端作为请求,字节数则用来配置进度条。将客户端调为准备接收文件状态。 3. 关键代码,将数据下载到本地 ```cpp // 服务器传输来的信息下载到本地 void MainWindow::copyDatatoLocal(QByteArray data) { qDebug() << "开始下载"; if(file == nullptr) { file = new QFile(filePath + "/" + fileName); // 只写打开所以没有会新建 if(!file->open(QIODevice::ReadWrite)){ qDebug() << "不可抗力导致打开失败"; return ; } } file->write(data); int val = ui->progressBarDowload->value(); val += data.size(); ui->progressBarDowload->setValue(val); qDebug() << val << ":" << ui->progressBarDowload->maximum() << ":" << ui->progressBarDowload->value(); qDebug() << "写入成功"; if(ui->progressBarDowload->value() >= ui->progressBarDowload->maximum()){ qDebug() << "传输结束"; isLoad = false; if (file != nullptr) { file->close(); file = nullptr; } int max = ui->progressBarDowload->maximum(); ui->progressBarDowload->setValue(max); } } ``` 只读的方式打开文件可以新建没有的文件,write可以写入数据,获取bar的值并加上当前数据包的值就可以得到传输完后的进度,通过数值可以得到传输结束的时机。 4. 项目中用到的信号 | 信号 | 作用 | |:--------------------------:|:--------------- | | &QTcpSocket::readyRead | 收到对方发来的数据时触发的信号 | | &QTcpSocket::disconnected | 断开连接时发出的信号 | | &QTcpServer::newConnection | 有新客户端连接时发出的信号 | | &QTcpSocket::connected | 客户端成功连接服务器发出的信号 |