Qt之文件传输服务器和客户端

tcp_client

  client.h如下:

#ifndef CLIENT_H
#define CLIENT_H

#include <QDialog>

#include <QAbstractSocket>
class QTcpSocket;
class QFile;

namespace Ui {
    class Client;
}

class Client : public QDialog {
    Q_OBJECT
public:
    explicit Client ( QWidget *parent = 0 );
    ~Client();
private:
    Ui::Client *ui;
    QTcpSocket *tcpClient;
    QFile *localFile; /* 要发送的文件 */
    qint64 totalBytes; /* 发送数据的总大小 */
    qint64 bytesWritten; /* 已经发送数据大小 */
    qint64 bytesToWrite; /* 剩余数据大小 */
    qint64 payloadSize; /* 每次发送数据的大小 */
    QString fileName; /* 保存文件路径 */
    QByteArray outBlock; /* 数据缓冲区,即存放每次要发送的数据块 */
private slots:
    void openFile();
    void send();
    void startTransfer();
    void updateClientProgress ( qint64 );
    void displayError ( QAbstractSocket::SocketError );
    void on_openButton_clicked();
    void on_sendButton_clicked();
};

#endif // CLIENT_H

  client.cpp如下:

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

#include <QtNetwork>
#include <QFileDialog>

Client::Client ( QWidget *parent ) : QDialog ( parent ), ui ( new Ui::Client ) {
    ui->setupUi ( this );
    payloadSize = 64 * 1024; /* 64KB */
    totalBytes = 0;
    bytesWritten = 0;
    bytesToWrite = 0;
    tcpClient = new QTcpSocket ( this );
    /* 当连接服务器成功时,发出connected信号,开始传送文件 */
    connect ( tcpClient, SIGNAL ( connected() ), this, SLOT ( startTransfer() ) );
    connect ( tcpClient, SIGNAL ( bytesWritten ( qint64 ) ), this, SLOT ( updateClientProgress ( qint64 ) ) );
    connect ( tcpClient, SIGNAL ( error ( QAbstractSocket::SocketError ) ), \
              this, SLOT ( displayError ( QAbstractSocket::SocketError ) ) );
    ui->sendButton->setEnabled ( false );
}

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

void Client::openFile() { /* 打开文件 */
    fileName = QFileDialog::getOpenFileName ( this );

    if ( !fileName.isEmpty() ) {
        ui->sendButton->setEnabled ( true );
        ui->clientStatusLabel->setText ( tr ( "打开文件 %1 成功!" ).arg ( fileName ) );
    }
}

void Client::send() { /* 连接到服务器 */
    ui->sendButton->setEnabled ( false );
    bytesWritten = 0; /* 初始化已发送字节为0 */
    ui->clientStatusLabel->setText ( tr ( "连接中…" ) );
    tcpClient->connectToHost ( ui->hostLineEdit->text(), ui->portLineEdit->text().toInt() );
}

void Client::startTransfer() { /* 传输文件大小等信息 */
    localFile = new QFile ( fileName );

    if ( !localFile->open ( QFile::ReadOnly ) ) {
        qDebug() << "client: open file error!";
        return;
    }

    totalBytes = localFile->size(); /* 获取文件大小 */
    QDataStream sendOut ( &outBlock, QIODevice::WriteOnly );
    sendOut.setVersion ( QDataStream::Qt_4_0 );
    QString currentFileName = fileName.right ( fileName.size() - fileName.lastIndexOf ( '/' ) - 1 );
    /* 保留总大小信息空间、文件名大小信息空间,然后输入文件名 */
    sendOut << qint64 ( 0 ) << qint64 ( 0 ) << currentFileName;
    totalBytes += outBlock.size(); /* 这里的总大小是总大小信息、文件名大小信息、文件名和实际文件大小的总和 */
    sendOut.device()->seek ( 0 );
    /* 返回outBolock的开始,用实际的大小信息代替两个qint64(0)空间 */
    sendOut << totalBytes << qint64 ( ( outBlock.size() - sizeof ( qint64 ) * 2 ) );
    bytesToWrite = totalBytes - tcpClient->write ( outBlock ); /* 发送完文件头结构后剩余数据的大小 */
    ui->clientStatusLabel->setText ( tr ( "已连接" ) );
    outBlock.resize ( 0 );
}

void Client::updateClientProgress ( qint64 numBytes ) { /* 发送数据,并更新进度条 */
    bytesWritten += ( int ) numBytes; /* 已经发送数据的大小 */

    if ( bytesToWrite > 0 ) { /* 如果已经发送了数据 */
        /* 每次发送payloadSize大小的数据,这里设置为64KB,如果剩余的数据不足64KB,就发送剩余数据的大小 */
        outBlock = localFile->read ( qMin ( bytesToWrite, payloadSize ) );
        bytesToWrite -= ( int ) tcpClient->write ( outBlock ); /* 发送完一次数据后还剩余数据的大小 */
        outBlock.resize ( 0 ); /* 清空发送缓冲区 */
    } else { /* 如果没有发送任何数据,则关闭文件 */
        localFile->close();
    }

    /* 更新进度条 */
    ui->clientProgressBar->setMaximum ( totalBytes );
    ui->clientProgressBar->setValue ( bytesWritten );

    if ( bytesWritten == totalBytes ) { /* 如果发送完毕 */
        ui->clientStatusLabel->setText ( tr ( "传送文件 %1 成功" ).arg ( fileName ) );
        localFile->close();
        tcpClient->close();
    }
}

void Client::displayError ( QAbstractSocket::SocketError ) { /* 显示错误 */
    qDebug() << tcpClient->errorString();
    tcpClient->close();
    ui->clientProgressBar->reset();
    ui->clientStatusLabel->setText ( tr ( "客户端就绪" ) );
    ui->sendButton->setEnabled ( true );
}

void Client::on_openButton_clicked() { /* 打开按钮 */
    ui->clientProgressBar->reset();
    ui->clientStatusLabel->setText ( tr ( "状态:等待打开文件!" ) );
    openFile();
}

void Client::on_sendButton_clicked() { /* 发送按钮 */
    send();
}

  main.cpp如下:

#include <QtGui/QApplication>
#include "client.h"
#include <QTextCodec>

int main ( int argc, char *argv[] ) {
    QApplication a ( argc, argv );
    QTextCodec::setCodecForTr ( QTextCodec::codecForLocale() );
    Client w;
    w.show();
    return a.exec();
}

tcp_server

  server.h如下:

#ifndef SERVER_H
#define SERVER_H

#include <QDialog>
#include <QAbstractSocket>
#include <QTcpServer>
class QTcpSocket;
class QFile;

namespace Ui {
    class Server;
}

class Server : public QDialog {
    Q_OBJECT
public:
    explicit Server ( QWidget *parent = 0 );
    ~Server();
private:
    Ui::Server *ui;
    QTcpServer tcpServer;
    QTcpSocket *tcpServerConnection;
    qint64 totalBytes; /* 存放总大小信息 */
    qint64 bytesReceived; /* 已收到数据的大小 */
    qint64 fileNameSize; /* 文件名的大小信息 */
    QString fileName; /* 存放文件名 */
    QFile *localFile; /* 本地文件 */
    QByteArray inBlock; /* 数据缓冲区 */
private slots:
    void start();
    void acceptConnection();
    void updateServerProgress();
    void displayError ( QAbstractSocket::SocketError socketError );
    void on_startButton_clicked();
};

#endif // SERVER_H

  server.cpp如下:

#include "server.h"
#include "ui_server.h"
#include <QtNetwork>

Server::Server ( QWidget *parent ) : QDialog ( parent ), ui ( new Ui::Server ) {
    ui->setupUi ( this );
    connect ( &tcpServer, SIGNAL ( newConnection() ), this, SLOT ( acceptConnection() ) );
}

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

void Server::start() { /* 开启监听 */
    if ( !tcpServer.listen ( QHostAddress::LocalHost, 6666 ) ) {
        qDebug() << tcpServer.errorString();
        close();
        return;
    }

    ui->startButton->setEnabled ( false );
    totalBytes = 0;
    bytesReceived = 0;
    fileNameSize = 0;
    ui->serverStatusLabel->setText ( tr ( "监听" ) );
    ui->serverProgressBar->reset();
}

void Server::acceptConnection() { /* 接收连接 */
    tcpServerConnection = tcpServer.nextPendingConnection();
    connect ( tcpServerConnection, SIGNAL ( readyRead() ), this, SLOT ( updateServerProgress() ) );
    connect ( tcpServerConnection, SIGNAL ( error ( QAbstractSocket::SocketError ) ), \
              this, SLOT ( displayError ( QAbstractSocket::SocketError ) ) );
    ui->serverStatusLabel->setText ( tr ( "接受连接" ) );
    tcpServer.close(); /* 关闭服务器,不再进行监听 */
}

void Server::updateServerProgress() { /* 接收文件并更新进度条 */
    QDataStream in ( tcpServerConnection );
    in.setVersion ( QDataStream::Qt_4_0 );

    if ( bytesReceived <= sizeof ( qint64 ) * 2 ) { /* 如果接收到的数据小于16个字节,保存到来的文件头结构 */
        if ( ( tcpServerConnection->bytesAvailable() >= sizeof ( qint64 ) * 2 ) && ( fileNameSize == 0 ) ) {
            in >> totalBytes >> fileNameSize; /* 接收数据总大小信息和文件名大小信息 */
            bytesReceived += sizeof ( qint64 ) * 2;
        }

        if ( ( tcpServerConnection->bytesAvailable() >= fileNameSize ) && ( fileNameSize != 0 ) ) {
            in >> fileName; /* 接收文件名,并建立文件 */
            ui->serverStatusLabel->setText ( tr ( "接收文件 %1 …" ).arg ( fileName ) );
            bytesReceived += fileNameSize;
            localFile = new QFile ( fileName );

            if ( !localFile->open ( QFile::WriteOnly ) ) {
                qDebug() << "server: open file error!";
                return;
            }
        } else {
            return;
        }
    }

    if ( bytesReceived < totalBytes ) { /* 如果接收的数据小于总数据,那么写入文件 */
        bytesReceived += tcpServerConnection->bytesAvailable();
        inBlock = tcpServerConnection->readAll();
        localFile->write ( inBlock );
        inBlock.resize ( 0 );
    }

    ui->serverProgressBar->setMaximum ( totalBytes );
    ui->serverProgressBar->setValue ( bytesReceived );

    if ( bytesReceived == totalBytes ) { /* 接收数据完成时 */
        tcpServerConnection->close();
        localFile->close();
        ui->startButton->setEnabled ( true );
        ui->serverStatusLabel->setText ( tr ( "接收文件 %1 成功!" ).arg ( fileName ) );
    }
}

void Server::displayError ( QAbstractSocket::SocketError socketError ) { /* 显示错误 */
    qDebug() << tcpServerConnection->errorString();
    tcpServerConnection->close();
    ui->serverProgressBar->reset();
    ui->serverStatusLabel->setText ( tr ( "服务端就绪" ) );
    ui->startButton->setEnabled ( true );
}

void Server::on_startButton_clicked() { /* 开始监听按钮 */
    start();
}

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值