QT通过TCP协议传输文件

常用的网络协议分为TCP和UDP两种,两种方式各有优缺点,其中TCP的主要特点是可靠,但是速度较慢(不丢包);而UDP则是不可靠传输,但速度快(可能丢包)。今天主要介绍的就是通过QT框架和TCP协议实现简单的文件传输。

关键类

QT框架中和TCP协议相关的类主要有两个
QTcpServer 和QTcpSocket
其中QTcpServer类用来在服务器端创建服务,而QTcpSocket用来保持客户端与服务器之间的会话。

创建服务端

1、首先初始化服务端设置

//初始化server
QTcpServer *server = new QTcpServer(this);
//设置监听地址和端口(设置监听来自所有地址的 对5529端口的请求)
server->listen(QHostAddress::Any,55249);

2、设置接收到请求后创建和客户端会话的socket

//QTcpServer::newConnection在有新的连接时触发,通过槽函数MainWindow::initSocket初始化socket
connect(server,&QTcpServer::newConnection,this,&MainWindow::initSocket);

void MainWindow::initSocket()
{
//QTcpServer的nextPendingConnection()返回的是新连接的socket指针 (QTcpSocket* socket)
    socket = server->nextPendingConnection();
//TcpSocket::readyRead在有新数据到来时触发一次,这里表示有数据需要接收了,通过槽函数ainWindow::writefile处理获取到的数据
    connect(socket,&QTcpSocket::readyRead,this,&MainWindow::writefile);
}

3、获取到数据之后进行文件的读写

void MainWindow::writefile()
{
//通过readAll读取socket中的数据
    QByteArray data = socket->readAll();
    //isFile是一个bool型变量从来表示是否是文件数据,初始值为false,因为第一次发送的数据内容为文件信息,不是文件内容
    if(!isFile){
    //QString的section()用来分割字符,类似于python里的切片
        filename = QString(data).section("#",1,1);
        ui->label->setText(filename);
        filesize = QString(data).section("#",2,2).toInt();
        receiversize = 0;
        file.setFileName(filename);
        //设置文件打开模式
        if(!file.open(QIODevice::WriteOnly))
        {
            QMessageBox::warning(this,tr("Warning"),tr("文件打开出错!"));
            return;
        }
        ui->progressBar->setValue(0);
        isFile = true;
    }else
    {
    //写入文件数据
        qint64 lenthR = file.write(data);
        receiversize += lenthR;
        ui->progressBar->setValue(receiversize*100/filesize);
    }
    if(receiversize == filesize)
    {
        QMessageBox::warning(this,tr("Warning"),tr("文件接收完成!"));
        //关闭文件
        file.close();
    }

}

创建客户端

客户端较服务器端简单一些,客户端只需要创建QTcpSocket的实例化对象连接服务器即可通信。
1、初始化客户端socket

//初始化客户端socket
    socket = new QTcpSocket(this);
    //连接服务器
    socket->connectToHost("127.0.0.1",55249,QIODevice::ReadWrite);
    //观察是否连接成功
    if(socket->waitForConnected(1000))
    {
        QMessageBox::warning(this,tr("Warning"),tr("连接成功"));
    }else{
        QMessageBox::warning(this,tr("Warning"),tr("连接出错"));
    }

2、选择需要传输的文件,初始化文件信息

//默认打开D盘,选择图片类型的文件
    QString path = QFileDialog::getOpenFileName(this,tr("open File"),"d:/",tr("Images(*.png *.jpg *.xmp)"));
    //初始化文件信息
    if(!path.isEmpty())file.setFileName(path);
    if(file.open(QIODevice::ReadOnly))
    {
        QFileInfo info(path);
        filename = info.fileName();
        filesize = info.size();
        sendsize = 0;
        QMessageBox::warning(this,tr("Warning"),tr("文件加载完成"));

    }

3、发送自定义文件信息以及文件内容

	//使用定时器连接发送数据方法
	mytimer = new QTimer(this);
    connect(mytimer,QTimer::timeout,this,&MainWindow::sendData);
	//自定义文件信息
    QString buf = QString("head#%1#%2").arg(filename).arg(filesize);
    qint64 len = socket->write(buf.toUtf8().data());
    //是否发送成功
    if(len >0)
    {
    //使用定时器延时,防止粘包
        mytimer->start(1000);
    }else{
        file.close();
    }


void MainWindow::sendData()
{
    qint64 len = 0;
    do{
    //每次发送2k文件内容
        char buf[2*1024] = {0};
        len = file.read(buf,sizeof(buf));
        len = socket->write(buf,len);
        sendsize+=len;
        qDebug()<<"SendData";
    }while(len >0);
    if(sendsize == filesize)
    {
        QMessageBox::warning(this,tr("Warning"),tr("文件发送完毕"));
        socket->close();
    }

}

测试结果

本地测试可以进行图片的传输
在这里插入图片描述
在这里插入图片描述
本实例中还存在一些问题没有修复,如每次只能发送一张图片(发送完成后不能再选择图片发送等),还有很多,因为本文只进行文件传输的简单介绍,不多赘述。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值