文件传输软件

  首先我们明确,这是一个局域网文件传输工具,具体功能实现,用网络编程,同样要设置端口号,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   接收端源码

 

posted @ 2012-12-07 14:56  桥段、  阅读(1795)  评论(1编辑  收藏  举报