QT_使用TCP/IP传输文件
小编:啊南 220阅读 2021.01.18
首选预览一下最终实现的效果,如下图:
一、服务器端
1、widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include
#include
#include
#include
#include
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
void sendData(); //发送文件数据
private slots:
void on_buttonFile_clicked();
void on_buttonSend_clicked();
private:
Ui::Widget *ui;
QTcpServer *tcpServer; //监听套接字
QTcpSocket *tcpSocket; //通信套接字
QFile file; //文件对象
QString fileName; //文件名称
quint64 fileSize; //文件大小
quint64 sendSize; //已经发送文件大小
QTimer timer; //定时器
};
#endif // WIDGET_H
2、widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include
#include
#include
#include
#include
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
setWindowTitle("服务器端口:8899");
//禁用两个按钮
ui->buttonFile->setEnabled(false);
ui->buttonSend->setEnabled(false);
//监听套接字
tcpServer = new QTcpServer(this);
//监听
tcpServer->listen(QHostAddress::Any, 8899);
//如果客户端成功与服务器连接
//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->buttonFile->setEnabled(true);
});
connect(&timer, &QTimer::timeout, [=](){
//关闭定时器
timer.stop();
//发送文件
sendData();
});
}
Widget::~Widget()
{
delete ui;
}
//选择文件
void Widget::on_buttonFile_clicked()
{
QString filePath = QFileDialog::getOpenFileName(this,"选择文件","../");
//如果选择文件路径无效则提示
if(filePath.isEmpty()){
QMessageBox::information(this, "提示", filePath+"文件路径无效");
return ;
}
fileName.clear();
fileSize = 0;
sendSize = 0;
//获取文件信息
QFileInfo info(filePath);
fileName = info.fileName(); //获取文件名字
fileSize = info.size(); //获取文件大小
//以只读方式打开
//指定文件的名称
file.setFileName(filePath);
//打开文件
bool isOk = file.open(QIODevice::ReadOnly);
if(!isOk){
QMessageBox::information(this, "提示","只读方式打开文件失败");
return ;
}
//提示打开文件的路径
ui->textEdit->append(filePath);
ui->buttonFile->setEnabled(false);
ui->buttonSend->setEnabled(true);
}
//发送文件
void Widget::on_buttonSend_clicked()
{
//先发送文件头信息 文件名##文件大小
QString head = QString("%1##%2").arg(fileName).arg(fileSize);
//发送头部信息
qint64 len = tcpSocket->write(head.toUtf8());
//如果len大于0,则头部信息发送成功
if(len > 0){
//发送真正 的文件信息
//防止tcp黏包信息
//需要通过定时器延时20毫秒
timer.start(20);
}else{
QMessageBox::information(this, "提示","头部信息发送失败");
file.close();
ui->buttonFile->setEnabled(true);
ui->buttonSend->setEnabled(false);
return ;
}
}
// 发送文件数据
void Widget::sendData()
{
ui->buttonFile->setEnabled(false);
ui->buttonSend->setEnabled(false);
quint64 len = 0;
do{
//每次发送数据的大小
char buf[1024] = {0};
len = 0;
//往文件中读数据
len = file.read(buf,sizeof(buf));
//发送数据,读多少,发多少
len = tcpSocket->write(buf,len);
//发送的数据要累加
sendSize += len;
}while(len > 0);
//判断是否发送文件完毕
/*if(sendSize == fileSize){
QMessageBox::information(this, "提示","文件发送完毕");
ui->textEdit->append("文件发送完毕");
file.close();
//把客户端断开
tcpSocket->disconnectFromHost();
ui->buttonFile->setEnabled(true);
ui->buttonSend->setEnabled(false);
return ;
}*/
}
二、客户端
1、clientwidget.h
#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H
#include
#include
#include
namespace Ui {
class ClientWidget;
}
class ClientWidget : public QWidget
{
Q_OBJECT
public:
explicit ClientWidget(QWidget *parent = 0);
~ClientWidget();
private slots:
void on_buttonConnect_clicked();
private:
Ui::ClientWidget *ui;
QTcpSocket *tcpSocket;
QFile file; //文件对象
QString fileName; //文件名称
quint64 fileSize; //文件大小
quint64 reciveSize; //已经接收文件大小
bool isStart;
};
#endif // CLIENTWIDGET_H
2、clientwidget.cpp
#include "clientwidget.h"
#include "ui_clientwidget.h"
#include
#include
ClientWidget::ClientWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::ClientWidget)
{
ui->setupUi(this);
setWindowTitle("客户端");
ui->progressBar->setValue(0);
isStart = true;
tcpSocket = new QTcpSocket(this);
connect(tcpSocket, &QTcpSocket::readyRead,[=](){
//取现接收的内容
QByteArray buf = tcpSocket->readAll();
if(isStart == true){
isStart = false;
//解析问部信息 buf = "hello##1024"
//QString str = "hello##1024"; str.section("##",0,0);
//初始化
fileName = QString(buf).section("##",0,0);
fileSize = QString(buf).section("##",1,1).toInt();
reciveSize = 0;
//打开文件
file.setFileName("../"+fileName);
bool isOk = file.open(QIODevice::WriteOnly|QIODevice::Append);
if(isOk == false){
tcpSocket->disconnectFromHost();
tcpSocket->close();
QMessageBox::information(this, "提示", "打出文件出错");
return ;
}
//禁用连接按钮
ui->buttonConnect->setEnabled(false);
//初始化进度条
ui->progressBar->setMinimum(0);
ui->progressBar->setMaximum(fileSize/1024);
ui->progressBar->setValue(0);
}else{ //文件信息
quint64 len = file.write(buf);
if(len > 0){
reciveSize += len;
}
//更新进度条
ui->progressBar->setValue(reciveSize/1024);
if(reciveSize == fileSize){
//传输完毕后关闭文件
file.close();
QMessageBox::information(this, "提示", "文件接收完毕");
ui->buttonConnect->setEnabled(true);
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
}
});
}
ClientWidget::~ClientWidget()
{
delete ui;
}
//连接服务器
void ClientWidget::on_buttonConnect_clicked()
{
//获取服务器的IP和端口
QString ip = ui->lineEditIp->text();
quint16 port = ui->lineEditPort->text().toInt();
//连接服务器
tcpSocket->connectToHost(QHostAddress(ip),port);
ui->progressBar->setValue(0);
}
相关推荐
- Qt加载XPM图像 XPM是一种基于ASCII编码的图像格式,一般用于创建图标。由于它是ASCII编码,很方便地在代码中使用。 Qt的QPixmap类支持XPM格式,原型如下:QPixmap::QPixmap(const char *const [] xpm)摘取Qt源码中的"严重警告"XPM图标:static const char* const c…
- 3DMAX提示和技巧 本主题标识使用 Civil View 的一些重要提示和技巧。常规使用屏幕分辨率至少为 1280x1024 的 Civil View。低于此分辨率时,一些面板将占用过多屏幕空间。 将视口设置为线框显示以达到最佳性能。 要尽可能简化用户界面,请在单个视口中工作并关闭 3ds Max 命令面…