知识点

  • 服务端与客户端的通信
  • 文件读写
  • 文件窗口QFileDialog
  • QString字符串的切分section
  • 每次只发送4比特数据大小
  • 先发送文件信息,再传数据,防止TCP黏包 QTimer使用

总结:出了一个非常粗心的bug:在h里面声明的变量,特别是int类型的,刚开始要进行初始化,比如sendSize += len; len是整型数据,最终sendSize是等于一个非常大的数据,我的理解是一个地址,地址+整型len,lsendSize在h文件声明了,但在cpp文件没有初始化造成的。

完整项目github地址:

https://github.com/taw19960426/Qt_study/tree/main/QTcpFile

结果演示

流程图

tcpserverwidget.cpp

#include "tcpserverwidget.h"
#include "ui_tcpserverwidget.h"
#include <QFileInfo>
#include <QFileDialog>
#include <QFile>#define cout qDebug() << "[" << __FILE__ <<":" << __LINE__ << "]"TcpServerWidget::TcpServerWidget(QWidget *parent) :QWidget(parent),ui(new Ui::TcpServerWidget)
{ui->setupUi(this);setWindowTitle("服务器端口:8888");//两个按钮都不能按ui->buttonFile->setEnabled(false);ui->buttonSend->setEnabled(false);//监听套接字tcpServer=new QTcpServer(this);//监听tcpServer->listen(QHostAddress::Any,8888);connect(tcpServer,&QTcpServer::newConnection,[=](){//取出建立好连接的套接字tcpSocket=tcpServer->nextPendingConnection();//获取对方的IP和端口QString ip=tcpSocket->peerAddress().toString();qint16 port =tcpSocket->peerPort();QString ipDate=QString("[ip=%1 port=%2] 建立好连接了!!").arg(ip).arg(port);ui->textEdit->append(ipDate);ui->buttonFile->setEnabled(true);});myTimer=new QTimer(this);connect(myTimer,&QTimer::timeout,[=](){//关闭定时器myTimer->stop();//发送文件sendDate();});
}TcpServerWidget::~TcpServerWidget()
{delete ui;
}//打开文件 获取文件的基本信息
void TcpServerWidget::on_buttonFile_clicked()
{QString filePath = QFileDialog::getOpenFileName(this,tr("Open File"),"../");//cout<<filePath;fileName.clear();fileSize=0;//获取文件的基本信息//QFileInfo获取文件信息QFileInfo FileDate(filePath);//qDebug()<<FileDate.exists();if(FileDate.exists()){qDebug() << "文件名字:" <<FileDate.fileName();qDebug() << "文件大小:" << FileDate.size()<<"bit";fileName=FileDate.fileName();//cout<<fileName;fileSize=FileDate.size();//cout<<fileSize;}//打开文件if(!filePath.isEmpty()){//只读方式打开文件//指定文件的名字file.setFileName(filePath);//打开文件bool openOk=file.open(QIODevice::ReadOnly);if(openOk){//提示打开文件的路径ui->textEdit->append("文件打开成功了。");}else{cout<<"文件打开失败了。";}}ui->buttonFile->setEnabled(false);ui->buttonSend->setEnabled(true);}//先发送文件信息 再发送数据
void TcpServerWidget::on_buttonSend_clicked()
{//文件信息先发送 “fileName_fileSize”QString head=QString("%1**%2").arg(fileName).arg(fileSize);//给对方发送数据, 使用套接字是tcpSocket//cout<<head;qint64 len;len=tcpSocket->write(head.toUtf8().data());//发送成功了if(len>0){//再发送数据//发送真正的文件信息//防止TCP黏包//需要通过定时器延时 20 msmyTimer->start(20);}else{//如果发送失败file.close();ui->buttonFile->setEnabled(true);ui->buttonSend->setEnabled(false);}
}void TcpServerWidget::sendDate(){ui->textEdit->append("正在发送数据");qint64 len=0;sendSize=0;do{//每次发送数据的大小char buf[4*1024] = {0};len = 0;//往文件中读数据len = file.read(buf, sizeof(buf));//cout<<len;//发送数据,读多少,发多少len=tcpSocket->write(buf,len);//cout<<len;//发送的数据需要累积sendSize += len;cout<<"sendSize="<<sendSize;}while(len>0);//cout<<"是否发送文件完毕";//cout<<"sendSize="<<sendSize;//cout<<"fileSize"<<fileSize;//是否发送文件完毕if(sendSize==fileSize){ui->textEdit->append("数据发送完毕");file.close();//主动和客户端端口连接tcpSocket->disconnectFromHost();tcpSocket->close();tcpSocket = NULL;}
}

tcpserverwidget.h

#ifndef TCPSERVERWIDGET_H
#define TCPSERVERWIDGET_H#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QFile>
#include <QTimer>namespace Ui {class TcpServerWidget;
}class TcpServerWidget : public QWidget
{Q_OBJECTpublic:explicit TcpServerWidget(QWidget *parent = 0);~TcpServerWidget();private slots:void on_buttonFile_clicked();void on_buttonSend_clicked();private:Ui::TcpServerWidget *ui;QTcpServer *tcpServer; //监听套接字QTcpSocket *tcpSocket; //通信套接字QString fileName;//文件名字qint64 fileSize;//文件大小qint64 sendSize;//已经发了多少数据//文件对象QFile file;//发送数据的函数void sendDate();QTimer *myTimer;
};#endif // TCPSERVERWIDGET_H

tcpclientwidget.cpp

#include "tcpclientwidget.h"
#include "ui_tcpclientwidget.h"
#include <QMessageBox>
#include <QHostAddress>#define cout qDebug() << "[" << __FILE__ <<":" << __LINE__ << "]"TcpClientWidget::TcpClientWidget(QWidget *parent) :QWidget(parent),ui(new Ui::TcpClientWidget)
{ui->setupUi(this);setWindowTitle("客户端");startInfo=true;tcpSocket=new QTcpSocket(this);ui->progressBar->setValue(0); //当前值connect(tcpSocket,&QTcpSocket::connected,[=](){ui->textEdit->setText("与服务端已经成功连接!");});//从通信套接字里面取内容connect(tcpSocket,&QTcpSocket::readyRead,[=](){//获取对方发送的内容QByteArray array = tcpSocket->readAll();if(startInfo){startInfo=false;receSize=0;//字符串切割“fileName_fileSize”QString temp=QString(array);
//                        fileName=temp.section("_",0,0);
//                        //cout<<fileName;
//                        fileSize=temp.section("_",1,1).toInt();//文件名fileName = QString(array).section("**", 0, 0);//文件大小fileSize = QString(array).section("**", 1, 1).toInt();//cout<<"fileSize="<<fileSize;//指定文件的名字file.setFileName(fileName);//打开文件bool openOk=file.open(QIODevice::WriteOnly);if(!openOk){cout<<"文件打开失败";tcpSocket->disconnectFromHost(); //断开连接tcpSocket->close(); //关闭套接字return; //如果打开文件失败,中断函数}ui->progressBar->setMinimum(0);ui->progressBar->setMaximum(fileSize/1024);ui->progressBar->setValue(0); //当前值}else{//是文件内容qint64 len = file.write(array);if(len>0){receSize+=len;}//更新进度条ui->progressBar->setValue(receSize/1024);if(receSize==fileSize){ui->textEdit->append("文件接收完成");QMessageBox::information(this, "完成", "文件接收完成");tcpSocket->disconnectFromHost(); //断开连接tcpSocket->close(); //关闭套接字file.close(); //关闭文件}}});
}TcpClientWidget::~TcpClientWidget()
{delete ui;
}//与服务器建立连接
void TcpClientWidget::on_buttonConnect_clicked()
{//获取服务器ip和端口QString ip=ui->lineEditIP->text();qint16 port=ui->lineEditPort->text().toInt();//主动和服务器建立连接tcpSocket->connectToHost(QHostAddress(ip),port);
}

tcpclientwidget.h

#ifndef TCPCLIENTWIDGET_H
#define TCPCLIENTWIDGET_H#include <QWidget>
#include <QTcpSocket>
#include <QFile>namespace Ui {class TcpClientWidget;
}class TcpClientWidget : public QWidget
{Q_OBJECTpublic:explicit TcpClientWidget(QWidget *parent = 0);~TcpClientWidget();private slots:void on_buttonConnect_clicked();private:Ui::TcpClientWidget *ui;QTcpSocket *tcpSocket; //通信套接字QString fileName;//文件名字qint64 fileSize;//文件大小qint64 receSize;//已经收了多少数据bool startInfo;//判断是否是接收到文件信息了//文件对象QFile file;
};#endif // TCPCLIENTWIDGET_H

Qt学习(八):QT中TCP传输文件相关推荐

  1. Qt下Tcp传输文件

    Qt下Tcp传输文件 文章目录 Qt下Tcp传输文件 1.服务端 2.客户端 1.服务端 //ServerWidgets.h #ifndef SERVERWIDGET_H #define SERVER ...

  2. Qt学习之Qt基础入门(中)

    1. 前言 上一篇博客,总结了Qt的一些基础用法,这篇博客继续跟视频学习Qt的常用方法 Qt入门系列: Qt学习之C++基础 Qt学习之Qt安装 Qt学习之Qt基础入门(上) Qt学习之Qt基础入门( ...

  3. qt向服务器传输文字_使用Qt实现客户端服务端聊天和传输文件

    [实例简介] 使用Qt实现客户端服务端聊天和传输文件,带有ui设计界面 [实例截图] [核心代码] TcpFile └── TcpFile ├── TcpClient │   ├── TcpClien ...

  4. Qt学习之Qt基础入门(下)

    1. 前言 前两篇博客简单的阐述了一下Qt的入门用法,这篇博客继续跟着视频学习. Qt入门系列: Qt学习之C++基础 Qt学习之Qt安装 Qt学习之Qt基础入门(上) Qt学习之Qt基础入门(中) ...

  5. labview文件上传服务器,基于labview的局域网TCP传输文件夹问题的解决

    一.概述 用labview来做局域网的文件传输已经很久了,用tcp顺利解决了大文件的传输,其中包括几个G的文件,然而当你遇到一个文件夹里面包含的很多小文件需要传输时,一个个单独选择文件显得非常麻烦,因 ...

  6. 20190328学习笔记 - JSP 中的 tag 文件

    20190328学习笔记 - JSP 中的 tag 文件 对于tag 文件 1. 引入 tag 文件 2. 在/WEB-INF/tags/sys 下,新增一个gridselect.tag文件 3. 在 ...

  7. 嵌入式学习之QT学习---8 QT网络编程之TCP通信

    前言: Qt网络模块提供了用于编写TCP/IP客户端和服务器端程序的各种类,如用于TCP通信的QTcpSocket和QTcpServer,用于UDP通信的QUdpSocket,还有用于实现HTTP.F ...

  8. 【QT学习之路】TCP通信

    QT自带了TCP通信模块,只需在工程文件中加入QT += network,就可以添加TCP所需的头文件,下面就来实现通过TCP协议让服务器和客户端之间行通信. 一.服务器的实现 服务器端 QTcpSe ...

  9. Qt 学习(三) —— Qt 模块

    1. Qt 模块简介 Qt由许多模块组成,分别支持不同领域的功能,主要分为 Essentials 和 Add-On. Qt Essential 是基本模块,它们可以在所有受支持的开发平台和经过测试的目 ...

最新文章

  1. mysql索引之间的区别
  2. java实现二进制转16进制
  3. hdu 2196 树形dp
  4. java exception子类_Java异常 Exception类及其子类(实例讲解)
  5. sql:MySQL 6.7 表,视图,存储过程结构查询
  6. 教你用Python自制拼图小游戏,轻松搞定熊孩子
  7. Toeplitz matrix 与 Circulant matrix
  8. 【2019CCPC秦皇岛:A】Angle Beats(离线+斜率Hash+分类讨论)
  9. 果真A站完了是B站,B站后台工程源码疑似泄露,已被GitHub删除!
  10. Linux初级入门百篇-lsof工具
  11. 步进电机丢步与闭环控制
  12. 计算机专业应届毕业生找工作一定要知道的面试题--必背版
  13. 无法导入android 工程--提示项目已经存在
  14. vue-loader无法解析vue里的stylus的style,外部引入styl文件可以解析,引入VueLoaderPlugin也没用
  15. 学会这几招,能找到90%以上的资源
  16. C语言模拟银行排队叫号(顺序队)
  17. 有趣的linux LS命令
  18. 304钢好还是316钢的区别
  19. 在线学生计算机,计算机学生顶岗实习计划(网络版)
  20. 200826-C语言打印文件中的文本内容

热门文章

  1. 2017年9月2日普级组T1 正方形
  2. BZOJ 4044 Luogu P4762 [CERC2014]Virus Synthesis (回文自动机、DP)
  3. tensorflow saver_TensorFlow: Model Persistence
  4. html背景自动换,html页面换皮肤颜色、背景图片(更换页面背景,常驻缓存)刷新保存...
  5. Lucene 02 - Lucene的入门程序(Java API的简单使用)
  6. 解除被DenyHosts锁定的IP地址
  7. 手脱EZIP v1.0
  8. PL/SQL在win7/win8 x64位下使用客户端连接oracle
  9. 论管理员的不作为!!!
  10. java之jsp页面语法