Qt学习:QT中TCP传输文件
Posted 唐维康
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Qt学习:QT中TCP传输文件相关的知识,希望对你有一定的参考价值。
知识点
- 服务端与客户端的通信
- 文件读写
- 文件窗口QFileDialog
- QString字符串的切分section
- 每次只发送4比特数据大小
- 先发送文件信息,再传数据,防止TCP黏包 QTimer使用
总结:出了一个非常粗心的bug:在h里面声明的变量,特别是int类型的,刚开始要进行初始化,比如sendSize += len; len是整型数据,最终sendSize是等于一个非常大的数据,我的理解是一个地址,地址+整型len,lsendSize在h文件声明了,但在cpp文件没有初始化造成的。
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 ms
myTimer->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_OBJECT
public:
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_OBJECT
public:
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传输文件的主要内容,如果未能解决你的问题,请参考以下文章