基于Qt平台利用TCP协议传输文件(百度网盘分享项目)

        与UDP协议单次传输数据大小要小于64KB不同,TCP协议利用套接字传输数据对数据大小没有限制,而且TCP协议的传输是可靠的,不会丢包,但是相应的传输速率会慢与UDP。

        编程使用的是TCP SOCKET套接字。项目文件用百度网盘分享:

 链接:https://pan.baidu.com/s/1kkDPIsK4jBxM1_m9iGs05Q 
提取码:1234

1. 客户端UI

        有几点注意事项:

        1.客户端如果要传输文件到服务器端,需要指明服务器端的IP和Port。

        2.connect:在填入服务器IP和Port后,按下此按钮进行服务端和客户端的连接。

        3.进度条:表示传输进度。

2.服务器UI

3.客户端代码

#include "client.h"
#include "ui_client.h"
#include<QDebug>
#include<QMessageBox>//信息对话框
client::client(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::client)
{
    ui->setupUi(this);

    tcpsocket = new QTcpSocket(this);

    isstart = true;//发送文件信息/文件 标志:1/0

    // 进度条初始值为0
    ui->progressBar->setValue(0);
    connect(tcpsocket,&QTcpSocket::readyRead,[=]()
    {
        //arry存储接收到的文件信息
        QByteArray arry = tcpsocket->readAll();

        if(true == isstart)
        {
            isstart = false;

            //1、收到的是文件信息
            //拆包:文件名##大小。拆包函数:section
            fileName = QString(arry).section("##",0,0);
            fileSize = QString(arry).section("##",1,1).toInt();

            //接收到的文件大小=0
            receiveSize = 0;
            qint64 len = 0;

            //创建文件设置为只写
            file.setFileName(fileName);

            bool isOK = file.open(QIODevice::WriteOnly);//isOK:文件成功打开标志

            if(false == isOK)
            {
                qDebug()<<"文件打开失败";
                tcpsocket->disconnectFromHost();
                tcpsocket->close();
            }
            //初始化进度条
            ui->progressBar->setMinimum(0);
            ui->progressBar->setMaximum(fileSize/1024);
            ui->progressBar->setValue(0);
         }
        else
        {
            //2、收到是文件内容

            //arry存储的是接收到的文件信息,len:读取文件内容的大小
            qint64 len = file.write(arry);

            receiveSize += len;//累计已读文件大小

            //更新进度条
            ui->progressBar->setValue(receiveSize/1024);
            qDebug()<<"receivesizr = "<<receiveSize<<" filesize="<<fileSize;
            if(receiveSize == fileSize)//文件全部接收完
            {
                QMessageBox::information(this,"完成","文件已全部接收");
                //tcpsocket->write("file done");
                file.close();

                tcpsocket->disconnectFromHost();
                tcpsocket->close();

            }


        }
    });


}

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



//connect按钮槽
void client::on_pushButtoncConnect_clicked()
{
    //获取服务器IP Port
    QString ip = ui->lineEditIP->text();
    quint16 port = ui->lineEditPort->text().toInt();

    tcpsocket->connectToHost(ip,port);//请求连接
}

4.服务器端代码

#include "server.h"
#include "ui_server.h"
#include<QFileDialog>//文本对话框
#include<QFile>
#include<QFileInfo>//获取文件信息
#include<QDebug>
#include<QMessageBox>//发送文件成功进行提示
server::server(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::server)
{
    ui->setupUi(this);
    tcpServer = new QTcpServer(this);

    tcpServer->listen(QHostAddress::Any,7777);//服务器port:7777

    connect(tcpServer,&QTcpServer::newConnection,[=](){
        tcpSocket = tcpServer->nextPendingConnection();

        //以下操作目的:在edit显示申请连接的客户端IP Port

        //peerAddress:返回传来请求的IP,即客户端IP
        //peerPort:返回传来请求的端口号,即客户端Port
        QString ip = tcpSocket->peerAddress().toString();
        quint16 port = tcpSocket->peerPort();

        //在UI的edit中显示哪个客户端连接了本服务器:显示客户端IP Port
        QString temp = QString("[%1:%2]已成功连接").arg(ip).arg(port);
        ui->textEdit->setText(temp);

        //设置文件连接按钮为可按
        ui->buttonFile->setEnabled(true);
    });
    connect(&myTimer,&QTimer::timeout,[=](){
        //关闭定时器
        myTimer.stop();
        sendData();//在发送文件信息20ms后发送文件内容,防止 粘包。
    });
}

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

//“发送文件”按钮的槽函数
void server::on_buttonFile_clicked()
{
    //getOpenFileName默认文件打开路径,参数:1、放弃2、标题3、路径
    //返回打开文件路径
    QString filepath = QFileDialog::getOpenFileName(this,"Open","../");

    if(filepath.isEmpty() == false){ //文件路径是否存在
        //获取文件信息:名 路径;info获得了选择的文件的名和路径
        QFileInfo info(filepath);

        //将用户选择的文件的名和地址赋给file,file是要接收并存储的文件
        fileName = info.fileName();
        fileSize = info.size();

        sendSize = 0;//发送文件大小=0
        //设置文件名
        file.setFileName(filepath);

        //打开文件为只读
        //打开文件是否成功
        bool isok = file.open(QIODevice::ReadOnly);
        if(isok == false)
        {
            qDebug()<<"文件打开失败";

        }

        //文件路径显示
        ui->textEdit->append(filepath);
        ui->buttonFile->setEnabled(false);
        ui->buttonSend->setEnabled(true);
    }
    else
    {
        qDebug()<<"文件路径选择失败";
    }
}



//“发送文件”的槽函数
//由ui之间创建槽函数不用connect
void server::on_buttonSend_clicked()
{
    //1、先发送文件信息

    //str即要发送信息
    QString str = QString("%1##%2").arg(fileName).arg(fileSize);//组包,可在客户端解包
    //len:发送的字节数。发送文件信息
    quint64 len = tcpSocket->write(str.toUtf8().data());

    if(len>0)//发送消息成功
    {
        myTimer.start(20);//间隔20ms触发timeout信号
    }
    else
    {
        qDebug()<<"发送文件信息失败";
        file.close();
        tcpSocket->disconnectFromHost();
        tcpSocket->close();
    }


}
void server::sendData()
{
    qint64 len = 0;//len记录已经发送了多少文件
    do
    {
        char buf[4*1024] = {0};

        //读文件内容
        len = file.read(buf,sizeof (buf));//读指定大小:buf的内容。返回的len:所读文件大小
        //读多少发多少
        len = tcpSocket->write(buf,len);//返回len:发送内容的大小
        //统计发送文件大小
        sendSize+=len;//已发送文件大小

    }while(len>0);
    if(sendSize == fileSize)//发送文件大小==文件总大小
    {
        //完毕是标题
        QMessageBox::information(this,"完毕","文件传输完成");
        qDebug()<<"sendsize = "<<sendSize<<" filesize = "<<fileSize;
        //传输完断开连接
        tcpSocket->disconnectFromHost();
        tcpSocket->close();
    }



}

猜你喜欢

转载自blog.csdn.net/marujie123/article/details/125118934