目录
前言
TCP传文件
服务器端
UI
.pro工程文件
QT += core gui network
CONFIG+=C++11
.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();
private slots:
void on_ButtonsFile_clicked();
void on_ButtonSend_clicked();
void sendData();//发送文件数据
private:
Ui::ServerWidget *ui;
QTcpServer *tcpServer;//监听套接字
QTcpSocket *tcpSocket;//通信套接字
QFile File;//文件对象
QString fileName;//文件名字
qint64 fileSize;//文件大小
qint64 sendSize;//已经发送文件的大小
QTimer timer;//定时器
};
#endif // SERVERWIDGET_H
.cpp文件
#include "serverwidget.h"
#include "ui_serverwidget.h"
#include <QFileDialog>
#include <QDebug>
#include <QFileInfo>
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->ButtonsFile->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->ButtonsFile->setEnabled(true);
ui->ButtonSend->setEnabled(true);
});
connect(&timer,&QTimer::timeout,
[=]()
{
//关闭定时器
timer.stop();
qDebug()<<"connect 关闭定时器,发生文件sendData";
//发生文件
sendData();
});
}
ServerWidget::~ServerWidget()
{
delete ui;
}
//选择文件按钮
void ServerWidget::on_ButtonsFile_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->textEdit->append(filePath);
ui->ButtonsFile->setEnabled(true);
ui->ButtonSend->setEnabled(true);
}
else
{
qDebug()<<"选择文件路径出错,62";
}
}
//发送文件按钮
void ServerWidget::on_ButtonSend_clicked()
{
qDebug()<<"按下发送按键";
//先发送文件头信息 文件名##文件大小
QString head = QString ("%1##%2").arg(fileName).arg(fileSize);
qDebug()<<"head:"<<head;
//发送文件头信息
qint64 len = tcpSocket->write(head.toUtf8());
qDebug()<<"len:"<<len;
if(len>0)//头信息发送成功
{
//发送真正的文件信息
//防止Tcp粘包文件
//需要定时器延时20ms
timer.start(20);
qDebug()<<"timer.start(20);";
}
else
{
qDebug()<<"头信息发送失败 105";
File.close();
ui->ButtonsFile->setEnabled(true);
ui->ButtonSend->setEnabled(false);
}
}
//发送文件数据
void ServerWidget::sendData()
{
qDebug()<<"发送文件数据,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;
qDebug()<<len;
}while(len>0);
//是否发送文件完毕
if(sendSize == fileSize)
{
ui->textEdit->append("文件发送完毕");
File.close();
//把客户端端口
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
}
客户端
UI
.h头文件
#ifndef CLIENTWIDEGT_H
#define CLIENTWIDEGT_H
#include <QWidget>
#include <QTcpSocket>
#include <QFile>
namespace Ui {
class ClientWidegt;
}
class ClientWidegt : public QWidget
{
Q_OBJECT
public:
explicit ClientWidegt(QWidget *parent = nullptr);
~ClientWidegt();
private slots:
void on_pushButton_clicked();
private:
Ui::ClientWidegt *ui;
QTcpSocket *tcpSocket;//通信套接字
QFile File;//文件对象
QString fileName;//文件名字
qint64 fileSize;//文件大小
qint64 recvSize;//已经接收文件的大小
};
#endif // CLIENTWIDEGT_H
.cpp文件
#include "clientwidegt.h"
#include "ui_clientwidegt.h"
#include <QDebug>
#include <QMessageBox>
#include <QHostAddress>
ClientWidegt::ClientWidegt(QWidget *parent) :
QWidget(parent),
ui(new Ui::ClientWidegt)
{
ui->setupUi(this);
tcpSocket = new QTcpSocket(this);
bool isStart =true;
connect(tcpSocket,&QTcpSocket::readyRead,
[&]()
{
//取出接受的内容
QByteArray buf=tcpSocket->readAll();
if(true == isStart)
{//接受头
isStart = false;
//解析头部信息 QString buf = "hello##1024"
// QString str ="hello##1024#Dante";
// str.section("##",0,0);
//初始化
fileName = QString(buf).section("##",0,0);
fileSize = QString(buf).section("##",1,1).toInt();
recvSize = 0;
//打开文件
File.setFileName(fileName);
qDebug()<<"客户端接收到头文件fileName:"<<fileName<<fileSize;
bool isOK=File.open(QIODevice::WriteOnly);
if(false == isOK)
{
qDebug()<<"WriteOnly error 35";
}
}
else if(false == isStart)//文件信息
{
qint64 len = File.write(buf);
recvSize += len;
if(recvSize == fileSize)
{
File.close();
QMessageBox::information(this,"完成","文件接收完成");
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
}
});
}
ClientWidegt::~ClientWidegt()
{
delete ui;
}
void ClientWidegt::on_pushButton_clicked()
{
//获取服务器ip和端口
QString ip=ui->lineEditIP->text();
quint16 port =ui->lineEdit_2->text().toUInt();
tcpSocket->connectToHost(QHostAddress(ip),port);
}
现象
代码里面有很多莫名奇妙的打印,那个是我用来检查那一部分出问题的
后面搞着搞着莫名奇妙就能用了,==😓
绑定进度条
QProgressBar类的公共函数列表
* QProgressBar(QWidget \\\*parent = nullptr):构造函数,创建一个新的QProgressBar对象,父对象为parent。
* virtual \\~QProgressBar():析构函数,销毁QProgressBar对象。
* Qt::Alignment alignment() const:获取进度条当前的对齐方式。
* QString format() const:获取进度条当前的显示格式。
* bool invertedAppearance() const:获取进度条是否反转外观。
* bool isTextVisible() const:获取进度条上是否显示文本。
* int maximum() const:获取进度条的最大值。
* int minimum() const:获取进度条的最小值。
* Qt::Orientation orientation() const:获取进度条的方向。
* void resetFormat():重置进度条的显示格式。
* void setAlignment(Qt::Alignment alignment):设置进度条的对齐方式。
* void setFormat(const QString &format):设置进度条的显示格式。
* void setInvertedAppearance(bool invert):设置进度条的外观是否反转。
* void setTextDirection(QProgressBar::Direction textDirection):设置进度条上文本的方向。
* void setTextVisible(bool visible):设置进度条上是否显示文本。
* virtual QString text() const:获取进度条上显示的文本。
* QProgressBar::Direction textDirection() const:获取进度条上文本的方向。
* int value() const:获取进度条当前的进度值。这些函数中,有些是获取器(getter)函数,只读取对象的属性值,例如minimum()、maximum()、orientation()等;有些是设置器(setter)函数,设置对象的属性值,例如setAlignment()、setFormat()、setTextDirection()等;还有一些是实现特定功能的函数,例如resetFormat()、setTextVisible()等。
不作演示