使用tcp的文件传输

服务器端:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QDialog>
#include <QAbstractSocket>
#include <QTcpServer>

class QTcpSocket;
class QFile;
class MainWindow : public QDialog
{
    Q_OBJECT

public:
    MainWindow(QDialog *parent = nullptr);
    ~MainWindow();
private slots:
    void start();
    void acceptConnection();
    void updateServerProgress();
    void displayError(QAbstractSocket::SocketError socker_error);
private:
    QTcpServer tcp_server_;
    QTcpSocket *tcp_server_connection_;
    qint64 total_bytes_;        //存放总大小信息
    qint64 bytes_received_;     //已收到数据的大小
    qint64 file_name_size_;     //文件名的大小信息
    QString file_name_;//存放文件名
    QFile *local_file_;//本地文件
    QByteArray in_block_;//数据缓冲区
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include <QtNetwork>

MainWindow::MainWindow(QDialog *parent)
    : QDialog(parent)
{
    //一旦有客户端连接到服务器,则发射newConnection信号
    connect(&tcp_server_, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
    start();
}

MainWindow::~MainWindow()
{
}

void MainWindow::start()
{
    if(!tcp_server_.listen(QHostAddress::LocalHost, 6666)){
        qDebug() << tcp_server_.errorString();
        close();
        return;
    }
    total_bytes_ = 0;
    bytes_received_ = 0;
    file_name_size_ = 0;
}

void MainWindow::acceptConnection()
{
    tcp_server_connection_ = tcp_server_.nextPendingConnection();
    connect(tcp_server_connection_, SIGNAL(readyRead()), this, SLOT(updateServerProgress()));
    connect(tcp_server_connection_, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError)));
    qDebug() << QString::fromLocal8Bit("接受连接");
    //关闭服务器,不在进行监听
    tcp_server_.close();
}

void MainWindow::updateServerProgress()
{
    QDataStream in(tcp_server_connection_);
    in.setVersion(QDataStream::Qt_5_6);
    //如果接收到的数据小于16个字节,保存到来的头文件结构
    if(bytes_received_ <= sizeof(qint64)*2){
        if((tcp_server_connection_->bytesAvailable() >= sizeof(qint64)*2) && (file_name_size_ == 0)){
            //接收数据总大小信息和文件名大小信息
            in >> total_bytes_ >> file_name_size_;
            bytes_received_ += sizeof(qint64)*2;
        }
        if((tcp_server_connection_->bytesAvailable() >= file_name_size_) && (file_name_size_ != 0)){
            //接收文件名,并建立文件
            in >> file_name_;
            qDebug() << QString::fromLocal8Bit("接收文件");
            qDebug() << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");//当前系统时间
            bytes_received_ += file_name_size_;
            local_file_ = new QFile(file_name_);
            if(!local_file_->open(QFile::WriteOnly)){
                qDebug() << "server: open file error!";
                return;
            }
        }else{
            return;
        }
    }
    //如果接收数据小于总数据,那么写入文件
    if(bytes_received_ < total_bytes_){
        bytes_received_ += tcp_server_connection_->bytesAvailable();
        in_block_ = tcp_server_connection_->readAll();
        local_file_->write(in_block_);
        in_block_.resize(0);
    }
    //进度
    qDebug() << 100*bytes_received_/total_bytes_;
    //接受数据完成时
    if(bytes_received_ == total_bytes_){
        tcp_server_connection_->close();
        local_file_->close();
        qDebug() << QString::fromLocal8Bit("接受文件成功");
        qDebug() << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");//当前系统时间
    }
}

void MainWindow::displayError(QAbstractSocket::SocketError socker_error)
{
    qDebug() << tcp_server_connection_->errorString();
    tcp_server_connection_->close();
}

客户端:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QAbstractSocket>

class QTcpSocket;
class QFile;
class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
private slots:
    void openFile();
    void send();
    void startTransfer();
    void updateClientProgress(qint64 num_bytes);
    void displayError(QAbstractSocket::SocketError);
private:
    QTcpSocket *tcp_client_;
    QFile *local_file_; //要发送的文件
    qint64 total_bytes_;        //发送数据的总大小
    qint64 bytes_written_;      //已经发送数据大小
    qint64 bytes_to_write_;     //剩余数据大小
    qint64 payload_size_;       //每次发送数据的大小
    QString file_name_; //保存文件路径
    QByteArray out_block_;  //数据缓冲区,即存放每次要发送的数据块
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include <QtNetwork>
#include <QFileDialog>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    payload_size_ = 64*1024;//64k
    total_bytes_ = 0;
    bytes_written_ = 0;
    bytes_to_write_ = 0;
    tcp_client_ = new QTcpSocket(this);
    //连接服务器成功时,会发出connected
    connect(tcp_client_, SIGNAL(connected()), this, SLOT(startTransfer()));
    //当有数据被写入,发出bytesWritten信号,参数为发出数据的大小
    connect(tcp_client_, SIGNAL(bytesWritten(qint64)), this, SLOT(updateClientProgress(qint64)));
    connect(tcp_client_, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError)));
    openFile();
    send();
}

MainWindow::~MainWindow()
{
}

void MainWindow::openFile()
{
    file_name_ = QFileDialog::getOpenFileName(this);
    if(!file_name_.isEmpty()){
        qDebug() << QString::fromLocal8Bit("打开文件成功");
    }
}

void MainWindow::send()
{
    //初始化已发送字节为0
    bytes_written_ = 0;
    qDebug() << QString::fromLocal8Bit("连接中...");
    //连接服务器
    tcp_client_->connectToHost(QHostAddress::LocalHost, 6666);
}

void MainWindow::startTransfer()
{
    local_file_ = new QFile(file_name_);
    if(!local_file_->open(QFile::ReadOnly)){
        qDebug() << "client: open file error!";
        return;
    }
    //获取文件大小
    total_bytes_ = local_file_->size();
    QDataStream send_out(&out_block_, QIODevice::WriteOnly);
    send_out.setVersion(QDataStream::Qt_5_6);
    QString current_file_name = file_name_.right(file_name_.size() - file_name_.lastIndexOf('/') - 1);
    //保留总大小信息空间、文件名大小信息空间,然后输入文件名
    send_out << qint64(0) << qint64(0) << current_file_name;
    //这里的总大小是总大小信息、文件名大小信息、文件名和实际文件大小的总和
    total_bytes_ += out_block_.size();
    send_out.device()->seek(0);
    //用实际的大小信息代替两个qint64(0)空间
    send_out << total_bytes_ << qint64((out_block_.size() - sizeof(qint64)*2));
    //发送完文件头结构后剩余数据的大小
    bytes_to_write_ = total_bytes_ - tcp_client_->write(out_block_);
    out_block_.resize(0);
}

//发送实际的文件
void MainWindow::updateClientProgress(qint64 num_bytes)
{
    //已经发送数据的大小
    bytes_written_ += num_bytes;
    //如果已经发送数据的大小
    if(bytes_to_write_ > 0){
        //每次发送payload_size_大小的数据,这里设置为64Kb,如果剩余的数据不足64KB就发发送剩余数据的大小
        out_block_ = local_file_->read(qMin(bytes_to_write_, payload_size_));
        //发送完一次数据后还剩余数据的大小
        bytes_to_write_ -= tcp_client_->write(out_block_);
        //清空发送缓存区
        out_block_.resize(0);
    }else{
        //如果没有发送任何数据,则关闭文件
        local_file_->close();
    }
    //更新进度
    qDebug() << bytes_written_/total_bytes_ << "iiiii";
    //如果发送文件成功
    if(bytes_written_ == total_bytes_){
        qDebug() << QString::fromLocal8Bit("传送文件成功");
        local_file_->close();
        tcp_client_->close();
    }
}

void MainWindow::displayError(QAbstractSocket::SocketError)
{
    qDebug() << tcp_client_->errorString();
    tcp_client_->close();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值