目录
1、效果流程
1.1 演示效果
1.2 TCP传文件流程图
2、项目结构
2.1 项目配置 TcpFile.pro
QT += core gui network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
clientwidget.cpp \
main.cpp \
serverwidget.cpp
HEADERS += \
clientwidget.h \
serverwidget.h
FORMS += \
clientwidget.ui \
serverwidget.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
2.2 主函数入口 main.cpp
#include "serverwidget.h"
#include "clientwidget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ServerWidget w;
w.show();
ClientWidget w2;
w2.show();
return a.exec();
}
3、TCP文件服务器端
3.1 设计布局 serverwidget.ui
3.2 头文件 serverwidget.h
#ifndef SERVERWIDGET_H
#define SERVERWIDGET_H
#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QFile>
#include <QFileInfo>
#include <QFileDialog>
#include <QTimer>
//DEBUG
#include <QtDebug>
#define cout qDebug()<<"["<<__FILE__<<":"<<__LINE__<<__TIME__<<"] "
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_btnFile_clicked();
//发送文件按钮
void on_btnSend_clicked();
private:
Ui::ServerWidget *ui;
/*--------funtion----------*/
void systemInit();
void sendData();
/*--------variable---------*/
QTcpServer *tcpServer;
QTcpSocket *tcpSocket;
QFile file; //文件对象
QString fileName; //文件名字
qint64 fileSize; //文件大小
qint64 sendSize; //已发送文件大小
QTimer *timer; //启动发送真正数据定时器
};
#endif // SERVERWIDGET_H
3.3 源文件 serverwidget.cpp
#include "serverwidget.h"
#include "ui_serverwidget.h"
ServerWidget::ServerWidget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::ServerWidget)
{
ui->setupUi(this);
/*------user-------*/
systemInit();
}
ServerWidget::~ServerWidget()
{
delete ui;
}
/*------------------------------------------
* funtion
*------------------------------------------*/
//用户系统初始化
void ServerWidget::systemInit()
{
tcpServer = NULL;
tcpSocket = NULL;
timer = new QTimer(this);
tcpServer = new QTcpServer(this);
tcpServer->listen(QHostAddress::Any,8888);
setWindowTitle("TCP服务器:8888");
ui->btnFile->setEnabled(false);
ui->btnSend->setEnabled(false);
connect(tcpServer,&QTcpServer::newConnection,[=](){
tcpSocket = tcpServer->nextPendingConnection();
QString ip = tcpSocket->peerAddress().toString();
quint16 port = tcpSocket->peerPort();
//cout << ip << port;
QString str = QString("[%1:%2] 成功连接").arg(ip).arg(port);
ui->textBrowser->append(str);
ui->btnFile->setEnabled(true);
});
connect(timer,&QTimer::timeout,[=](){
timer->stop();
sendData();
});
}
void ServerWidget::sendData()
{
qint64 len = 0;
ui->textBrowser->append("文件正在发送中...");
do{
len = 0;
//每次发送的数据量4K
char buf[4*1024] = {0};
//读取文件中数据
len = file.read(buf,sizeof(buf));
//读取多少数据 发送多少数据
len = tcpSocket->write(buf,len);
//发送数据量累积
sendSize += len;
}while(len > 0);
if(file.size() == sendSize){
ui->textBrowser->append("文件发送完成");
file.close();
ui->btnFile->setEnabled(false);
ui->btnSend->setEnabled(false);
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
}
/*------------------------------------------
* slots
*------------------------------------------*/
//选择文件按钮
void ServerWidget::on_btnFile_clicked()
{
QString filePath = QFileDialog::getOpenFileName(this,"open","../");
//cout << filePath;
if(!filePath.isEmpty()){
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){
ui->textBrowser->append(filePath);
ui->btnFile->setEnabled(false);
ui->btnSend->setEnabled(true);
}else{
cout << "只读方式打开文件失败";
}
}else{
cout << "选择文件路径出错";
}
}
//发送文件按钮
void ServerWidget::on_btnSend_clicked()
{
//发送文件头信息
QString head = QString("head##%1##%2").arg(fileName).arg(fileSize);
qint64 len = tcpSocket->write(head.toUtf8());
if(len > 0){
//发送真正的文件信息
timer->start(20);
}else{
cout << "头信息发送失败";
ui->btnFile->setEnabled(false);
ui->btnSend->setEnabled(false);
file.close();
}
}
4、TCP文件客户端
4.1 设计布局 clientwidget.ui
4.2 头文件 clientwidget.h
#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H
#include <QWidget>
#include <QTcpSocket>
#include <QHostAddress>
#include <QFile>
#include <QMessageBox>
#include <QtDebug>
#define cout qDebug()<<"["<<__FILE__<<":"<<__LINE__<<__TIME__<<"] "
namespace Ui {
class ClientWidget;
}
class ClientWidget : public QWidget
{
Q_OBJECT
public:
explicit ClientWidget(QWidget *parent = nullptr);
~ClientWidget();
private slots:
void on_btnConnect_clicked();
void on_btnClose_clicked();
private:
Ui::ClientWidget *ui;
/*--------funtion----------*/
void systemInit();
/*--------variable---------*/
QTcpSocket *tcpSocket;
QFile file; //文件对象
QString fileName; //文件名字
qint64 fileSize; //文件大小
qint64 recvSize; //已接收文件大小
bool isStart; //消息头标志
};
#endif // CLIENTWIDGET_H
4.3 源文件 clientwidget.cpp
#include "clientwidget.h"
#include "ui_clientwidget.h"
ClientWidget::ClientWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::ClientWidget)
{
ui->setupUi(this);
/*-------user------*/
systemInit();
}
ClientWidget::~ClientWidget()
{
delete ui;
}
/*------------------------------------------
* funtion
*------------------------------------------*/
//用户系统初始化
void ClientWidget::systemInit()
{
tcpSocket = new QTcpSocket(this);
setWindowTitle("TCP客户端");
isStart = true;
ui->progressBar->setValue(0);
connect(tcpSocket,&QTcpSocket::connected,[=](){
ui->textBrowser->append("与服务器成功建立连接");
});
connect(tcpSocket,&QTcpSocket::disconnected,[=](){
ui->textBrowser->append("与服务器已经断开连接");
});
connect(tcpSocket,&QTcpSocket::readyRead,[=](){
//取出接收的内容
QByteArray buf = tcpSocket->readAll();
if(isStart){ //消息头接收
//解析头部信息 初始化
QString head = QString(buf).section("##",0,0);
fileName = QString(buf).section("##",1,1);
fileSize = QString(buf).section("##",2,2).toInt();
recvSize = 0;
if(head == "head"){
//打开文件
file.setFileName(fileName);
bool isOk = file.open(QIODevice::WriteOnly);
if(!isOk){
cout << "只读方式打开文件失败";
ui->textBrowser->append("只读方式打开文件失败");
}else{
isStart = false;
ui->progressBar->setMinimum(0);
ui->progressBar->setMaximum(fileSize/1024);
}
}else{
cout << "接收错误头部信息";
ui->textBrowser->append("收错误头部信息");
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
}else{ //文件信息接收
qint64 len = file.write(buf);
recvSize += len;
ui->progressBar->setValue(recvSize/1024);
if(fileSize == recvSize){
file.close();
QMessageBox::information(this,"完成","文件接收完成!");
ui->textBrowser->append("文件接收完成!");
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
}
});
}
/*------------------------------------------
* slots
*------------------------------------------*/
//connect 连接按钮
void ClientWidget::on_btnConnect_clicked()
{
QString ip = ui->lineEditIP->text();
quint16 port = ui->lineEditPort->text().toUInt();
tcpSocket->connectToHost(QHostAddress(ip),port);
}
void ClientWidget::on_btnClose_clicked()
{
tcpSocket->disconnectFromHost();
tcpSocket->close();
}