Qt tcp实现文件发送

TCP即TransmissionControl Protocol,传输控制协议。与UDP不同,它是面向连接和数据流的可靠传输协议。也就是说,它能使一台计算机上的数据无差错的发往网络上的其他计算机,所以当要传输大量数据时,我们选用TCP协议。

TCP协议的程序使用的是客户端/服务器(C/S)模式,在Qt中提供了QTcpSocket类来编写客户端程序,使用QTcpServer类编写服务器端程序。我们在服务器端进行端口的,一旦发现客户端的连接请求,就会发出newConnection()信号,可以关联这个信号到我们自己的槽进行数据的发送。而在客户端,一旦有数据到来就会发出readyRead()信号,可以关联此信号进行数据的接收。其实,在程序中最难理解的地方就是程序的发送和接收了,为了让大家更好的理解,

下面我们已发送文件为案例
pro 文件
在这里插入图片描述
客户端 ui界面
在这里插入图片描述
.h 文件

#include <QMainWindow>
#include <QtNetwork>
#include <QFileDialog>
#include <QFileInfo>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_pB_open_clicked();   //打开文件
    void on_pB_Send_clicked();  //发送文件

    void send();  //连接服务器
    void startTransfer();  //发送文件大小等信息
    void updateClientProgress(qint64); //发送数据,更新进度条
    void displayError(QAbstractSocket::SocketError); //显示错误
    void openFile();   //打开文件

private:
    Ui::MainWindow *ui;
    QTcpSocket *tcpClient;
    QFile *localFile;  //要发送的文件
    qint64 totalBytes;  //数据总大小
    qint64 bytesWritten;  //已经发送数据大小
    qint64 bytesToWrite;   //剩余数据大小
    qint64 loadSize;   //每次发送数据的大小
    QString fileName;  //保存文件路径
    QByteArray outBlock;  //数据缓冲区,即存放每次要发送的数据
};

.cpp 文件

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    loadSize = 4*1024;
    totalBytes = 0;
    bytesWritten = 0;
    bytesToWrite = 0;
    tcpClient = new QTcpSocket(this);  //创建TCP客户端
    //当连接服务器成功时,发出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->pB_Send->setEnabled(false);
}

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

void MainWindow::on_pB_open_clicked()
{
    openFile();
}

void MainWindow::on_pB_Send_clicked()
{
    send();
}

void MainWindow::send()
{
    ui->pB_Send->setEnabled(false);
    bytesWritten=0;
    ui->label_ClientStatus->setText(tr("连接中..."));
    //连接主机
    tcpClient->connectToHost(ui->lineEdit_host->text(),
                             ui->lineEdit_prot->text().toInt());
}

void MainWindow::startTransfer()
{
    localFile = new QFile(fileName);
    if(!localFile->open(QFile::ReadOnly))
    {
        qDebug() << "open file error!";
        return;
    }

    //文件总大小
    totalBytes = localFile->size();

    QDataStream sendOut(&outBlock,QIODevice::WriteOnly);
    sendOut.setVersion(QDataStream::Qt_5_8);
    //当前文件名称
    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->label_ClientStatus->setText(tr("已连接"));
    outBlock.resize(0);
}

void MainWindow::updateClientProgress(qint64 numBytes)
{
    //已经发送数据的大小
    bytesWritten += (int)numBytes;
    if(bytesToWrite > 0) //如果已经发送了数据
    {
        //每次发送loadSize大小的数据,这里设置为4KB,如果剩余的数据不足4KB,
        //就发送剩余数据的大小
        outBlock = localFile->read(qMin(bytesToWrite,loadSize));

        //发送完一次数据后还剩余数据的大小
        bytesToWrite -= (int)tcpClient->write(outBlock);

        //清空发送缓冲区
        outBlock.resize(0);

    } else {
        localFile->close(); //如果没有发送任何数据,则关闭文件
    }

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

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

void MainWindow::displayError(QAbstractSocket::SocketError)
{
    qDebug() << tcpClient->errorString();
    tcpClient->close();
    ui->progressBar_client->reset();
    ui->label_ClientStatus->setText(tr("客户端就绪"));
    ui->pB_Send->setEnabled(true);
}

//打开文件
void MainWindow::openFile()
{
    fileName = QFileDialog::getOpenFileName(this);
    if(!fileName.isEmpty())
    {
        ui->pB_Send->setEnabled(true);
        ui->label_ClientStatus->setText(tr("打开文件 %1 成功!")
                                        .arg(fileName));
    }
}

思路
我们设计好界面,然后按下“打开”按钮,选择要发送的文件,这时调用了openFile()函数。然后点击“发送”按钮,调用send()函数,与服务器进行连接。当连接成功时就会发出connected()信号,这时就会执行startTransfer()函数,进行文件头结构的发送,当发送成功时就会发出bytesWritten(qint64)信号,这时执行updateClientProgress(qint64 numBytes)进行文件数据的传输和进度条的更新。这里使用了一个loadSize变量,我们在构造函数中将其初始化为4*1024即4字节,它的作用是,我们将整个大的文件分成很多小的部分进行发送,每部分为4字节。而当连接出现问题时就会发出error(QAbstractSocket::SocketError)信号,这时就会执行displayError()函数。

服务端
ui 界面
在这里插入图片描述

.h 文件

#include <QMainWindow>
#include <QtNetwork>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_pB_Start_clicked();
    void start();   //开始监听
    void acceptConnection();  //建立连接
    void updateServerProgress();  //更新进度条,接收数据
    void displayError(QAbstractSocket::SocketError socketError);//显示错误

private:
    Ui::MainWindow *ui;
    QTcpServer *tcpServer;
    QTcpSocket *tcpServerConnection;
    qint64 totalBytes;  //存放总大小信息
    qint64 bytesReceived;  //已收到数据的大小
    qint64 fileNameSize;  //文件名的大小信息
    QString fileName;   //存放文件名
    QFile *localFile;   //本地文件
    QByteArray inBlock;   //数据缓冲区
};

.cpp 文件

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    totalBytes=0;    //总大小
    bytesReceived=0;  //已经接受的数据包大小
    fileNameSize=0;   //文件名大小
    //当发现新连接时发出newConnection()信号
    tcpServer=new QTcpServer(this);
    connect(tcpServer,SIGNAL(newConnection()),this,
            SLOT(acceptConnection()));
}

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

//开始监听
void MainWindow::on_pB_Start_clicked()
{
    start();
}

void MainWindow::start()
{
    ui->pB_Start->setEnabled(false);
    bytesReceived =0;
    if(!tcpServer->listen(QHostAddress::LocalHost,6666))
    {
        qDebug() << tcpServer->errorString();
        close();
        return;
    }
    ui->label_sercerStatus->setText(tr("监听"));
}

//接受链接
void MainWindow::acceptConnection()
{
    tcpServerConnection = tcpServer->nextPendingConnection();
    connect(tcpServerConnection,SIGNAL(readyRead()),this,
            SLOT(updateServerProgress()));
    connect(tcpServerConnection,
            SIGNAL(error(QAbstractSocket::SocketError)),this,
            SLOT(displayError(QAbstractSocket::SocketError)));
    ui->label_sercerStatus->setText(tr("接受连接"));
    tcpServer->close();
}

void MainWindow::updateServerProgress()
{
    QDataStream in(tcpServerConnection);
    in.setVersion(QDataStream::Qt_5_8);
    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->label_sercerStatus->setText(tr("接收文件 %1 ...")
                                           .arg(fileName));
            bytesReceived += fileNameSize;
            localFile= new QFile(fileName);
            if(!localFile->open(QFile::WriteOnly))
            {
                qDebug() << "open file error!";
                return;
            }
        }
        else return;
    }
    if(bytesReceived < totalBytes)
    {  //如果接收的数据小于总数据,那么写入文件
        bytesReceived += tcpServerConnection->bytesAvailable();
        inBlock= tcpServerConnection->readAll();
        localFile->write(inBlock);
        inBlock.resize(0);
    }
    //更新进度条
    ui->progressBar_server->setMaximum(totalBytes);
    ui->progressBar_server->setValue(bytesReceived);

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

void MainWindow::displayError(QAbstractSocket::SocketError socketError)
{
    qDebug() << tcpServerConnection->errorString();
    tcpServerConnection->close();
    ui->progressBar_server->reset();
    ui->label_sercerStatus->setText(tr("服务端就绪"));
    ui->pB_Start->setEnabled(true);
}

思路
点击监听按钮,如果有新的连接newConnect() 信号 那就执行acceptConnection()
在这里插入图片描述
如果有中文乱码
那就在mian.cpp中设置n
在这里插入图片描述

  • 4
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 可以使用Qt中的QTcpSocket类和QTcpServer类来实现TCP文件传输。具体步骤如下: 1. 创建一个QTcpServer对象,并在其上调用listen()方法来监听来自客户端的连接请求。 2. 当有客户端连接请求到达时,QTcpServer会触发newConnection()信号。在该信号的槽函数中,可以使用QTcpServer的nextPendingConnection()方法获取一个QTcpSocket对象来和客户端进行通信。 3. 在QTcpSocket对象上调用connectToHost()方法连接服务器端,或者使用已连接的QTcpSocket对象进行数据传输。 4. 在QTcpSocket对象上调用write()方法发送文件内容,或者在接收方使用QTcpSocket的readyRead()信号和read()方法接收文件内容。 5. 传输完成后,关闭QTcpSocket对象和QTcpServer对象。 具体实现可以参考Qt官方文档和示例程序。 ### 回答2: Qt是一个开发C++桌面应用程序的跨平台框架,它提供了丰富的类库和工具来简化程序开发。要实现TCP文件传输,可以借助Qt的网络模块。 首先,我们需要创建一个TCP服务器和一个TCP客户端。服务器端需要监听指定的端口并接受客户端连接,而客户端需要连接到服务器并发送文件数据。 在服务器端,我们可以使用QTcpSocket和QTcpServer类来创建一个TCP服务器。可以使用QTcpServer的listen方法来绑定服务器IP地址和监听的端口。一旦有客户端连接到服务器,QTcpServer会发出newConnection信号,我们可以在这个信号槽函数中处理客户端连接。 在客户端,我们同样可以使用QTcpSocket类来创建一个TCP连接。通过调用QTcpSocket的connectToHost方法,我们可以连接到服务器的IP地址和端口。一旦连接建立成功,我们可以使用QTcpSocket的write方法来发送文件数据。 为了实现文件的传输,我们可以使用QFile类来打开文件并读取数据。在服务器端,可以将文件内容分割为较小的数据块,并使用QTcpSocket的write方法将这些数据块发送给客户端。在客户端,我们可以使用QTcpSocket的read方法接收服务器发送的数据块,并将其写入文件中。 在文件传输过程中,我们还可以使用QTcpSocket的readyRead和bytesWritten信号来处理读取和写入文件数据的细节,以确保数据的完整性和正确性。 通过以上步骤,我们可以使用Qt实现TCP文件传输。同时,Qt还提供了其他一些类和方法来处理网络连接的错误和异常,并提供了完善的错误处理机制来增加程序的稳定性和可靠性。 ### 回答3: 在Qt实现TCP文件传输需要使用QTcpSocket类和QFile类。首先,需要创建一个QTcpSocket的实例来处理网络连接。然后,连接到服务器并通过QTcpSocket的write方法发送文件的字节流。同时,使用QFile类来打开本地文件以便读取字节流并将其发送给服务器。 以下是一个简单的示例代码: ```cpp // 客户端: QTcpSocket socket; socket.connectToHost("服务器地址", 端口号); if (socket.waitForConnected()) { QFile file("本地文件路径"); if (file.open(QIODevice::ReadOnly)) { QByteArray data = file.readAll(); file.close(); socket.write(data); socket.waitForBytesWritten(); socket.disconnectFromHost(); } } else { // 连接失败的处理逻辑 } // 服务器: QTcpServer server; server.listen(QHostAddress::Any, 端口号); connect(&server, SIGNAL(newConnection()), this, SLOT(onNewConnection())); void YourClass::onNewConnection() { QTcpSocket *socket = server.nextPendingConnection(); connect(socket, SIGNAL(readyRead()), this, SLOT(onReadyRead())); connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater())); } void YourClass::onReadyRead() { QTcpSocket *socket = qobject_cast<QTcpSocket*>(sender()); QByteArray data = socket->readAll(); // 处理接收到的文件数据 } ``` 上面的代码只是实现TCP文件传输的基本框架,你还可以根据自己的需求进行相关的逻辑和错误处理。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值