文件传输流程:

服务器端:
serverwidget.ui

serverwidget.h
#ifndef SERVERWIDGET_H
#define SERVERWIDGET_H
#include <QWidget>
#include<QTcpServer>//监听套接字
#include<QTcpSocket>//通信套接字
#include<QFile>
#include<QTimer>
QT_BEGIN_NAMESPACE
namespace Ui { class ServerWidget; }
QT_END_NAMESPACE
class ServerWidget : public QWidget
{
    Q_OBJECT
public:
    ServerWidget(QWidget *parent = nullptr);
    ~ServerWidget();
    void sendData();//发送文件数据
private slots:
    void on_buttonFile_clicked();
    void on_buttonSend_clicked();
private:
    Ui::ServerWidget *ui;
    QTcpServer *tcpServer;//监听套接字
    QTcpSocket *tcpSocket;//通信套接字
    QFile file;//文件对象
    QString fileName;//文件名字
    qint64 fileSize;//文件大小
    qint64 sendSize;//已经发送文件大小
    QTimer timer;//定时器
};
#endif // SERVERWIDGET_Hserverwidget.cpp
#include "serverwidget.h"
#include "ui_serverwidget.h"
#include<QFileDialog>
#include<QDebug>
#include<QFileInfo>
#include<QTimer>
ServerWidget::ServerWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::ServerWidget)
{
    ui->setupUi(this);
    //监听套接字
    tcpServer = new QTcpServer(this);
    //监听
    tcpServer->listen(QHostAddress::Any,8888);
    setWindowTitle("服务器端口为:8888");
    //两个按钮都不能按
    ui->buttonFile->setEnabled(false);
    ui->buttonSend->setEnabled(false);
    //如果客户端成功和服务器连接
    //tcpServer会自动触发newConnection()
    connect(tcpServer,&QTcpServer::newConnection,[=](){
        //取出建立好连接的套接字
        tcpSocket = tcpServer->nextPendingConnection();
        //获取对方的IP和端口
        QString ip = tcpSocket->peerAddress().toString();
        quint16 port = tcpSocket->peerPort();
        QString str = QString("[%1:%2] 成功连接").arg(ip).arg(port);
        ui->textEdit->setText(str);//显示到编辑区
        //成功连接后,才能选择文件
        ui->buttonFile->setEnabled(true);
    });
    connect(&timer,&QTimer::timeout,[=](){
        //关闭定时器
        timer.stop();
        //发送文件
        sendData();
    });
}
ServerWidget::~ServerWidget()
{
    delete ui;
}
//选择文件按钮
void ServerWidget::on_buttonFile_clicked()
{
    QString filePath = QFileDialog::getOpenFileName(this,"open","../");
    if(false == filePath.isEmpty())//如果选择文件路径有效
    {
        fileName.clear();
        fileSize = 0;
        //获取文件信息
        QFileInfo info(filePath);
        fileName = info.fileName();//获取文件名字
        fileSize = info.size();//获取文件大小
        sendSize = 0;//发送文件的大小
        //只读方式打开
        //指定文件的名字
        file.setFileName(filePath);
        //打开文件
        bool isOK = file.open(QIODevice::ReadOnly);
        if(false == isOK)
        {
            qDebug()<<"只读的方式打开文件失败 77";
        }
        //提示打开文件的路径
        ui->buttonFile->setEnabled(false);
        ui->buttonSend->setEnabled(true);
    }
    else
    {
        qDebug()<<"选择文件路径出错 62";
    }
}
//发送文件按钮
void ServerWidget::on_buttonSend_clicked()
{
    //先发送文件头信息
    QString head = QString("%1##%2").arg(fileName).arg(fileSize);
    //发送头部信息
    qint64 len = tcpSocket->write(head.toUtf8());
    if(len > 0)//头部信息发送成功
    {
        //发送真正的文件信息
        //防止TCP黏包问题
        //需要通过定时器延时20 ms
        timer.start(20);
    }
    else
    {
        qDebug()<<"头部信息发送失败 110";
        file.close();
        ui->buttonFile->setEnabled(true);
        ui->buttonSend->setEnabled(false);
    }
}
void ServerWidget::sendData()
{
    qint64 len = 0;
    do
    {
        char buf[4*1024] = {0};
        len = 0;
        //往文件在读数据
        len = file.read(buf,sizeof(buf));
        //发送数据,读多少,发多少
        len = tcpSocket->write(buf,len);
        //发送的数据需要积累
        sendSize += len;
    }while(len > 0);
    //是否发送文件完毕
    if(sendSize == fileSize)
    {
        ui->textEdit->append("文件发送完毕");
        file.close();
        //把客户端挂关闭
        tcpSocket->disconnectFromHost();
        tcpSocket->close();
    }
}客户端:
main.cpp
#include "serverwidget.h"
#include"clientwidget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    ServerWidget w;
    w.show();
    ClientWidget w2;
    w2.show();
    return a.exec();
}
clientwidget.ui

clientwidget.h
#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H
#include <QWidget>
#include<QTcpSocket>//通信套接字
#include<QFile>
namespace Ui {
class ClientWidget;
}
class ClientWidget : public QWidget
{
    Q_OBJECT
public:
    explicit ClientWidget(QWidget *parent = nullptr);
    ~ClientWidget();
private slots:
    void on_pushButton_clicked();
private:
    Ui::ClientWidget *ui;
    QTcpSocket *tcpSocket;//通信套接字
    QFile file;//文件对象
    QString fileName;//文件名字
    qint64 fileSize;//文件大小
    qint64 recvSize;//已经接收文件大小
    bool isStart;
};
#endif // CLIENTWIDGET_H
clientwidget.cpp
#include "clientwidget.h"
#include "ui_clientwidget.h"
#include<QDebug>
#include<QMessageBox>
#include<QHostAddress>
ClientWidget::ClientWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ClientWidget)
{
    ui->setupUi(this);
    tcpSocket = new QTcpSocket(this);
    isStart = true;
    connect(tcpSocket,&QTcpSocket::readyRead,[=](){
       //取出接收的内容
        QByteArray buf = tcpSocket->readAll();
        if(true == isStart)
        {
            //接收头
            isStart = false;
            //解析头部信息 QString buf = "hello##1024"
//            QString str = "hello##1024##mike";
//            str.section("##",0,0);//以##进行拆分
            //初始化
            fileName = QString(buf).section("##",0,0);
            fileSize = QString(buf).section("##",1,1).toInt();
            recvSize = 0;
            //打开文件
            file.setFileName(fileName);
            bool isOK = file.open(QIODevice::WriteOnly);
            if(false == isOK)
            {
                qDebug()<<"WriteOnly error 40";
            }
        }
        else//文件信息
        {
            qint64 len = file.write(buf);
            recvSize  += len;
            if(recvSize == fileSize)
            {
                file.close();
                QMessageBox::information(this,"完成","文件接收完成");
                tcpSocket->disconnectFromHost();
                tcpSocket->close();
            }
        }
    });
}
ClientWidget::~ClientWidget()
{
    delete ui;
}
void ClientWidget::on_pushButton_clicked()
{
    //获取服务器的IP和端口
    QString ip = ui->lineEditIP->text();
    quint16 port = ui->lineEditPort->text().toInt();
    tcpSocket->connectToHost(QHostAddress(ip),port);
}
输出如下所示:

在当前目录下可找到传输的文件












![[Java基础揉碎]多线程基础](https://img-blog.csdnimg.cn/direct/38d62559dde34969be57bd157d36634f.png)






