用Tcp实现文件传输

客户端client.h

#ifndef CLIENT_H
#define CLIENT_H

#include <QWidget>
#include <QUdpSocket>
#include <QTcpSocket>
#include <QFile>
#include <QFileDialog>
#include <QProgressBar>
#include <QTimer>
#include <QDebug>

#include "stdlib.h"

namespace Ui {
class client;
}

class client : public QWidget
{
    Q_OBJECT

public:
    explicit client(QWidget *parent = 0);
    Ui::client *ui;
    ~client();

private:  


    QTcpSocket *tcpClient;
    QFile *localFile;
    QPushButton *btn1,*btn2;
    QDialog *dialog;    //资源选择框
    QPushButton *btn3;

    QProgressBar *bar1;

    QString filename;       //保存文件路径
    QByteArray outBlock;     //数据缓冲区
    qint64 totalBytes;       //文件总字节数
    qint64 fileSize;         //文件名字的字节数
    qint64 bytestoWrite;     //尚未发送的字节数
    qint64 bytesWritten;     //已发送的字节数
    qint64 loadSize;         //每次发送数据的大小
private slots:
    void updateFileProgress(qint64 numBytes);   //更新文件发送进度
    void send_File();       //发送文件
    void select_File();     //选择文件
    void startTransfer();   //发送文件大小等信息

};

#endif //

client.cpp

#include "client.h"
#include "ui_client.h"



client::client(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::boxing)
{
    ui->setupUi(this);
    tcpClient = new QTcpSocket(this);
    loadSize = 4*1024;
    totalBytes=0;
    bytestoWrite=0;
    bytesWritten=0;

    connect(tcpClient,SIGNAL(connected()),this,SLOT(startTransfer()));
    connect(ui->pushButton,SIGNAL(clicked(bool)),this,SLOT(select_File()));//连接选择文件按钮
    connect(ui->pushButton_4,SIGNAL(clicked(bool)),this,SLOT(send_File()));//连接发送文件按钮


 //只要数据已写入TCP套接字,byteswritten信号就会被发出
    connect(tcpClient,SIGNAL(bytesWritten(qint64)),this,SLOT(updateFileProgress(qint64)));
}

client::~client()
{
    delete ui;
}




void client::select_File()
{
   
    this->filename = QFileDialog::getOpenFileName(this,"Open a file","/a","files(*)");
    bar1->setValue(0);
}

void client::send_File()
{
    
    tcpClient->connectToHost("127.0.0.1",1234);//调试阶段用本机
}
void client::startTransfer()
{
    localFile = new QFile(filename);
    if(!localFile->open(QFile::ReadOnly))
    {
        qDdebug()<<"文件打开失败!";
        return;
    }
    totalBytes = localFile->size();         //文件总大小
    QDataStream sendout(&outBlock,QIODevice::WriteOnly);
    sendout.setVersion(QDataStream::Qt_4_8);
    QString currentFileName = filename.right(filename.size()-filename.lastIndexOf("/")-1);   
    sendout<<qint64(0)<<qint64(0)<<currentFileName;     //依次写入总大小信息空间,文件名大小信息空间,文件名
    totalBytes += outBlock.size();       //文件名大小和实际文件大小的总和
    sendout.device()->seek(0);
    //返回outblock的开始,用实际大小代替两个qint64空间
    sendout<<totalBytes<<qint64((outBlock.size()-sizeof(qint64)*2));
    bytestoWrite = totalBytes-tcpClient->write(outBlock);
    outBlock.resize(0);

}
void client::updateFileProgress(qint64 numBytes)
{
    bytesWritten += (int)numBytes;
    if(bytestoWrite>0)
    {
        outBlock=localFile->read(qMin(bytestoWrite,loadSize));
        bytestoWrite -= ((int)tcpClient->write(outBlock));
        outBlock.resize(0);
    }
    else
    {
        localFile->close();
    }
    bar1->setMaximum(totalBytes);
    bar1->setValue(bytesWritten);
    dialog1->show();
    if(bytesWritten == totalBytes)
    {
      
        localFile->close();
        delete localFile;               
disconnect(tcpClient,SIGNAL(bytesWritten(qint64)),this,SLOT(updateFileProgress(qint64)));
        totalBytes=0;
        bytestoWrite=0;
        bytesWritten=0;
        tcpClient->close();
    }
}


server.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QApplication>
#include <QUdpSocket>
#include <QDebug>
#include <QThread>
#include <QTcpServer>
#include <QTcpSocket>
#include <QFile>
#include <QDataStream>
#include <QDir>
#include <QFileDialog>
#include <QSettings>

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = 0);
    QTcpServer *fileserver;
    QTcpSocket *filesocket;
    ~MainWindow();
private:
    QString filename;     //存放文件名
    QFile *localfile;       //本地文件
    QByteArray inBlock;     //数据缓冲区
    qint64 totalBytes;      //文件总字节数
    qint64 bytestoWrite;    //尚未发送的字节数
    qint64 bytesWritten;    //已发送的字节数
    qint64 bytesReceived;   //已收到数据的大小
    qint64 filenameSize;    //存放文件名的大小
public slots:
    void acceptFileConnection();    //建立连接
    void updateFileProgres();       //更新进度,接受数据

};

#endif // MAINWINDOW_H

server.cpp

#include "mainwindow.h"
QSettings *configIni = new QSettings("config1.ini",QSettings::IniFormat);
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{

  

   filesocket = new QTcpSocket;
   fileserver = new QTcpServer;
   //tcp监听主代理传过来的文件信息
   fileserver->listen(QHostAddress("127.0.0.1"),1234);
   bytesReceived=0; //已经接受的数据包
   bytesReceived=0; //已经接受的数据包
   totalBytes=0;//总大小
   filenameSize=0;//文件名大小
   //当发现新连接时发出newConnection()信号
   connect(fileserver,SIGNAL(newConnection()),this,SLOT(acceptFileConnection()));

}

MainWindow::~MainWindow()
{
    delete recv_vm;
    delete recv_zhu;
    delete fileserver;
    delete filesocket;
    delete localfile;
}

void MainWindow::acceptFileConnection()
{
    filesocket = fileserver->nextPendingConnection();
    connect(filesocket,SIGNAL(readyRead()),this,SLOT(updateFileProgres()));//tcpsocket连接操作
  
}
void MainWindow::updateFileProgres()
{
    QDataStream infile(filesocket);
    infile.setVersion(QDataStream::Qt_4_8);
    if(bytesReceived<= sizeof(qint64)*2)
    {
        //如果接收到的数据小于16个字节,那么是刚开始接收数据,保存到头文件
        if((filesocket->bytesAvailable()>=sizeof(qint64))*2&&(filenameSize==0))
        {
            //总大小信息和文件名大小信息
           infile>>totalBytes>>filenameSize;
           bytesReceived += sizeof(qint64)*2;
        }
        if((filesocket->bytesAvailable()>=filenameSize)&&(filenameSize!=0))
        {
            //接收文件名并建立文件
            infile>>filename;
            bytesReceived += filenameSize;
            localfile = new QFile(filename);         
			QString filePath ="/fff";
            QDir dir(filePath);
            bool exits = dir.exists(filePath);
            if(exits)
            {
                qDebug()<<"文件夹已经存在";
            }
            else
            {
                bool ok = dir.mkdir(filePath);
                if(ok)
                   qDebug()<<"文件夹不存在,创建成功";
            }
            filePath = dir.absolutePath()+QString("/%1").arg(filename);
            localfile = new QFile(filePath);
             if(!localfile->open(QFile::WriteOnly))
             {
                 qDebug()<<"打开失败";
                 return;
             }
        }
        else return;
    }
    //如果接收的数据小于总数据,那么写入文件
    if(bytesReceived<totalBytes)
    {
        bytesReceived += filesocket->bytesAvailable();
        inBlock =filesocket->readAll();
        localfile->write(inBlock);
        inBlock.resize(0);
    }
    //接收数据完成时
    if(bytesReceived==totalBytes)
    {
        bytesReceived=0;
        totalBytes=0;
        filenameSize=0;
        localfile->close();
    }

}