文件传输软件
首先我们明确,这是一个局域网文件传输工具,具体功能实现,用网络编程,同样要设置端口号,IP地址等,这个软件已经用起来比U盘方便跟多,比平常U盘等移动存储工具的传输速率高。
传输文件数据时候,设置文件头包含信息,包括文件大小,文件名,防止出错在文件头加了个标示,读取到标识才开始传文件数据,还需要设置缓冲区,缓冲区传文件开始之前先清空。
对于文件传输来说,相当于数据先进缓冲区,之后在从缓冲区去文件数据,这样的话在接收端看到的进度条效果会比发送端进度条延后一些。
发送端
接收端
选择打开文件。
等待确认。
接收端确认
确认接收文件
接收成功。
F盘已经有文件存在。
发送端:
#include "testclient.h" #include "ui_testclient.h" #include <string> TestClient::TestClient(QWidget *parent) : QWidget(parent), ui(new Ui::TestClient) { ui->setupUi(this); socket = new QTcpSocket(); loadSize = qint64(4*1024); this->onReset(); connect(socket,SIGNAL(connected()),this,SLOT(startTransfer())); connect(socket,SIGNAL(bytesWritten(qint64)),this,SLOT(updateProgress(qint64))); connect(socket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(displayError(QAbstractSocket::SocketError))); connect(ui->pushButton_file,SIGNAL(clicked()),this,SLOT(openFile())); connect(ui->pushButton_send,SIGNAL(clicked()),this,SLOT(onSend())); connect(ui->pushButton_abort,SIGNAL(clicked()),this,SLOT(onAbort())); connect(socket,SIGNAL(readyRead()),this,SLOT(onRead())); } TestClient::~TestClient() { delete ui; delete socket; delete localFile; } void TestClient::openFile() { fileName = QFileDialog::getOpenFileName(this); if(!fileName.isEmpty()) { localFile = new QFile(fileName); ui->pushButton_send->setEnabled(true); ui->pushButton_file->setDisabled(true); ui->pushButton_abort->setEnabled(true); ui->textEdit->append(tr("Open %1 success.").arg(fileName)); } } void TestClient::onSend() { if (0 == flag) { flag = 0; ui->progressBar->reset(); ui->pushButton_send->setDisabled(true); ui->pushButton_send->setText(tr("Pause")); bytesWritten = 0; ui->textEdit->append(tr("Connecting to host.")); socket->connectToHost(ui->lineEdit_host->text(),ui->lineEdit_port->text().toInt()); if(!socket->waitForConnected(3000)) { ui->textEdit->append(tr("Connect timed out.")); return; } } else if (1 == flag) { flag = 2; ui->pushButton_send->setText(tr("Continue")); } else { flag = 1; ui->pushButton_send->setText(tr("Pause")); ui->textEdit->append(tr("Send %1 continue.").arg(currentFileName)); this->updateProgress(0); } } void TestClient::onRead() { int length = socket->bytesAvailable(); char readBuf[10]; memset(readBuf,0,sizeof(readBuf)); socket->read(readBuf,length); //ui->textEdit->append(tr("Read %1 from host.").arg(readBuf)); if (0 == strcmp(readBuf,"yes")) { flag = 1; ui->textEdit->append(tr("Host has comfirmed. Sending %1.").arg(currentFileName)); ui->pushButton_send->setEnabled(true); this->updateProgress(0); } else { socket->abort(); localFile->close(); this->onReset(); ui->textEdit->append(tr("Send %1 failed. Host denied transfer.").arg(currentFileName)); } } void TestClient::onAbort() { this->onReset(); ui->textEdit->append(tr("Send %1 abort.").arg(currentFileName)); socket->abort(); localFile->close(); } void TestClient::onReset() { ui->progressBar->reset(); ui->pushButton_send->setText(tr("Send")); ui->pushButton_send->setDisabled(true); ui->pushButton_abort->setDisabled(true); ui->pushButton_file->setEnabled(true); flag = 0; totalBytes = 0; bytesWritten = 0; bytesToWrite = 0; } void TestClient::startTransfer() { if(!localFile->open(QFile::ReadOnly)) { ui->textEdit->append(tr("Open file failed.")); return; } totalBytes = localFile->size(); QDataStream sendOut(&outBlock,QIODevice::WriteOnly); sendOut.setVersion(QDataStream::Qt_4_6); currentFileName = fileName.right(fileName.size() - fileName.lastIndexOf('/')-1); sendOut << qint64(0) << qint64(0) << currentFileName; totalBytes += outBlock.size(); sendOut.device()->seek(0); sendOut<<totalBytes<<qint64((outBlock.size() - sizeof(qint64)*2)); socket->write(outBlock); socket->flush(); // bytesWritten += socket->write(outBlock); bytesToWrite = totalBytes - bytesWritten; ui->progressBar->setMaximum(totalBytes); ui->textEdit->append(tr("Conected, watting for comformation.")); outBlock.resize(0); ui->pushButton_abort->setEnabled(true); ui->textEdit->append(tr("%1 of %2 . done %3 left").arg(bytesWritten).arg(totalBytes).arg(bytesToWrite)); } void TestClient::updateProgress(qint64 numBytes) { bytesWritten += numBytes; if (1 == flag) { if(bytesToWrite > 0) { outBlock = localFile->read(qMin(bytesToWrite,loadSize)); bytesToWrite -= socket->write(outBlock); outBlock.resize(0); } else { ui->textEdit->append(tr("Finish sending %1 of %2 . done %3 left").arg(bytesWritten).arg(totalBytes).arg(bytesToWrite)); } if(bytesWritten == totalBytes) { this->onReset(); ui->textEdit->append(tr("Send file %1 success.").arg(currentFileName)); localFile->close(); //socket->close(); } } else { ui->textEdit->append(tr("Sending %1 puased.").arg(currentFileName)); } ui->progressBar->setValue(bytesWritten); } void TestClient::displayError(QAbstractSocket::SocketError) { if(bytesWritten != totalBytes) { this->onReset(); socket->abort(); localFile->close(); ui->textEdit->append(tr("Send %1 failed. Error: %2 .").arg(currentFileName).arg(socket->errorString())); } }
#ifndef TESTCLIENT_H #define TESTCLIENT_H #include <QWidget> #include <QTcpSocket> #include <QFileDialog> namespace Ui { class TestClient; } class TestClient : public QWidget { Q_OBJECT public: explicit TestClient(QWidget *parent = 0); ~TestClient(); private: Ui::TestClient *ui; QTcpSocket *socket; QFile *localFile; //要发送的文件 qint64 totalBytes; //数据总大小 qint64 bytesWritten; //已经发送数据大小 qint64 bytesToWrite; //剩余数据大小 qint64 loadSize; //每次发送数据的大小 QString fileName; //保存文件路径 QString currentFileName; QByteArray outBlock; //数据缓冲区,即存放每次要发送的数据 volatile int flag; private slots: void openFile(); void onSend(); void onRead(); void onAbort(); void onReset(); void startTransfer(); void updateProgress(qint64); void displayError(QAbstractSocket::SocketError); }; #endif // TESTCLIENT_H
接收端:
#include "testserver.h" #include "ui_testserver.h" TestServer::TestServer(QWidget *parent) : QWidget(parent), ui(new Ui::TestServer) { ui->setupUi(this); server = new QTcpServer(this); this->onReset(); if(!server->listen(QHostAddress::Any,6666)) { ui->textEdit->append(tr("Listening faild.")); return; } ui->textEdit->append(tr("listening...")); connect(server,SIGNAL(newConnection()),this,SLOT(incoming())); connect(ui->pushButton_confirm,SIGNAL(clicked()),this,SLOT(onComfirm())); connect(ui->pushButton_abort,SIGNAL(clicked()),this,SLOT(onAbort())); } TestServer::~TestServer() { delete ui; } void TestServer::recieveFile() { QDataStream in(socket); in.setVersion(QDataStream::Qt_4_6); if(bytesReceived <= sizeof(qint64)*2) { ui->progressBar->reset(); //如果接收到的数据小于16个字节,那么是刚开始接收数据,我们保存到//来的头文件信息 if((socket->bytesAvailable() >= sizeof(qint64)*2) && (fileNameSize == 0)) { //接收数据总大小信息和文件名大小信息 in >> totalBytes >> fileNameSize; ui->progressBar->setMaximum(totalBytes); bytesReceived += sizeof(qint64) * 2; qDebug() << bytesReceived; } if((socket->bytesAvailable() >= fileNameSize) && (fileNameSize != 0)) { //接收文件名,并建立文件 in >> fileName; ui->textEdit->append(QString(tr("Recieving file %1 size: %2").arg(fileName).arg(totalBytes))); bytesReceived += fileNameSize; qDebug() << bytesReceived; localFile = new QFile("F://" + fileName); if(!localFile->open(QFile::WriteOnly)) { ui->textEdit->append("open file error!"); return; } }else return; ui->pushButton_abort->setEnabled(true); ui->pushButton_confirm->setEnabled(true); } if(bytesReceived < totalBytes) { //如果接收的数据小于总数据,那么写入文件 bytesReceived += socket->bytesAvailable(); inBlock = socket->readAll(); localFile->write(inBlock); inBlock.resize(0); } ui->progressBar->setValue(bytesReceived); if(bytesReceived == totalBytes) { //接收数据完成时 ui->textEdit->append(QString(tr("Recieving file %1 size success!").arg(fileName))); socket->close(); localFile->close(); this->onReset(); } } void TestServer::incoming() { socket = server->nextPendingConnection(); connect(socket,SIGNAL(readyRead()),this,SLOT(recieveFile())); connect(socket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(displayError(QAbstractSocket::SocketError))); } void TestServer::onComfirm() { ui->pushButton_confirm->setDisabled(true); socket->write("yes"); socket->flush(); } void TestServer::onAbort() { this->onReset(); socket->close(); localFile->remove(); localFile->close(); ui->textEdit->append(QString(tr("Recieving file %1 aborted!").arg(fileName))); } void TestServer::onReset() { ui->progressBar->reset(); ui->pushButton_confirm->setDisabled(true); ui->pushButton_abort->setDisabled(true); totalBytes = 0; bytesReceived = 0; fileNameSize = 0; } void TestServer::displayError(QAbstractSocket::SocketError) { if (bytesReceived != totalBytes) { ui->textEdit->append(tr("Recieve %1 failed. Error: %2 .").arg(fileName).arg(socket->errorString())); localFile->remove(); localFile->close(); this->onReset(); socket->abort(); } }
#ifndef TESTSERVER_H #define TESTSERVER_H #include <QWidget> #include <QTcpServer> #include <QTcpSocket> #include <QFile> namespace Ui { class TestServer; } class TestServer : public QWidget { Q_OBJECT public: explicit TestServer(QWidget *parent = 0); ~TestServer(); private: Ui::TestServer *ui; QTcpServer *server; QTcpSocket *socket; qint64 totalBytes; //存放总大小信息 qint64 bytesReceived; //已收到数据的大小 qint64 fileNameSize; //文件名的大小信息 QString fileName; //存放文件名 QFile *localFile; //本地文件 QByteArray inBlock; //数据缓冲区 private slots: void recieveFile(); void incoming(); void onComfirm(); void onAbort(); void onReset(); void displayError(QAbstractSocket::SocketError); }; #endif // TESTSERVER_H
https://files.cnblogs.com/li-zi/FileSend.rar 发送端源码
https://files.cnblogs.com/li-zi/FileRecieve.rar 接收端源码