TCP传文件流程图
clientwidget.ui
serverwidget.ui
clientwidget.h
#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H
#include <QWidget>
#include <QTcpSocket>
#include <QFile>
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;
qint64 fileSize;
qint64 recvSize; //已经发送文件的大小
bool isStart;
};
#endif // CLIENTWIDGET_H
clientwidget.cpp
#include "clientwidget.h"
#include "ui_clientwidget.h"
#include <QDebug>
#include <QMessageBox>
#include <QHostAddress>
ClientWidget::ClientWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::ClientWidget)
{
ui->setupUi(this);
isStart = true;
setWindowTitle("客户端");
ui->progressBar->setValue(0);
tcpSocket = new QTcpSocket(this);
connect(tcpSocket, &QTcpSocket::readyRead, [=](){
//取出接收内容
QByteArray buf = tcpSocket->readAll();
if(true == isStart)
{
//接收头
isStart = false;
//解析头部信息 QString buf = "hello##1024"
// QString str = "hello##1024";
//str.section("##", 0, 0)
fileName = QString(buf).section("##", 0, 0);
fileSize = QString(buf).section("##", 1, 1).toInt();
recvSize = 0;
//打开文件
file.setFileName(fileName);
bool isOK = file.open(QIODevice::WriteOnly);
if(false == isOK)
{
qDebug() << "WriteOnly err";
tcpSocket->disconnectFromHost(); //断开连接
tcpSocket->close();
return ;
}
//弹出对话框,显示接收文件的信息
QString str = QString("接受的文件:[%1: %2kb]").arg(fileName).arg(fileSize/1024);
QMessageBox::information(this, "文件信息",str);
//设置进度条
ui->progressBar->setMinimum(0); //最小值
ui->progressBar->setMaximum(fileSize/1024); //最大值
ui->progressBar->setValue(0); //设置当前值
}
else //文件信息
{
qint64 len = file.write(buf);
if(len > 0)
{
recvSize += len;
// QString str = QString::number(recvSize);
// tcpSocket->write(str.toUtf8().data());
//qDebug() << len;
}
//更新进度条
ui->progressBar->setValue(recvSize/1024);
if(recvSize == fileSize)
{
//先给服务器端发送接收文件完成
tcpSocket->write("file done");
QMessageBox::information(this, "完成", "文件接收完成");
file.close();
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);
isStart = true;
//设置进度条
ui->progressBar->setValue(0);
}
serverwidget.h
#ifndef SERVERWIDGET_H
#define SERVERWIDGET_H
#include <QWidget>
#include <QTcpServer> //监听套接字
#include <QTcpSocket> //通信套接字
#include <QFile>
#include <QTimer>
namespace Ui {
class ServerWidget;
}
class ServerWidget : public QWidget
{
Q_OBJECT
public:
explicit ServerWidget(QWidget *parent = 0);
~ServerWidget();
void sendData(); //发送文件函数
private slots:
void on_buttonFile_clicked();
void on_buttonSend_clicked();
private:
Ui::ServerWidget *ui;
QTcpServer* tcpServer;
QTcpSocket* tcpSocket;
QFile file; //文件对象
QString fileName;
qint64 fileSize;
qint64 sendSize; //已经发送文件的大小
QTimer timer; //定时器
};
#endif // SERVERWIDGET_H
serverwidget.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->buttonFile->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->buttonFile->setEnabled(true);
connect(tcpSocket, &QTcpSocket::readyRead, [=](){
//获取客户端信息
QByteArray buf = tcpSocket->readAll();
if(QString(buf) == "file done")
{
ui->textEdit->append("文件发送完毕");
file.close();
//断开客户端
//tcpSocket->disconnectFromHost();
//tcpSocket->close();
}
// else
// {
// qDebug() << buf;
// }
});
});
connect(&timer, &QTimer::timeout, this, [=](){
//关闭定时器
timer.stop();
//发送文件
sendData();
});
}
ServerWidget::~ServerWidget()
{
delete ui;
}
//选择文件对话框
void ServerWidget::on_buttonFile_clicked()
{
QString path = QFileDialog::getOpenFileName(this, "open", "../");
if(false == path.isEmpty())
{
fileName.clear();
fileSize = 0; //初始化文件大小
sendSize = 0; //初始化发送文件的大小
//获取文件信息
QFileInfo info(path);
fileName = info.fileName(); //获取文件名字
fileSize = info.size(); // 获取文件大小
//以只读的方式打开文件
file.setFileName(path);
bool isOK = file.open(QIODevice::ReadOnly);
if(false == isOK)
{
qDebug() << "只读方式打开失败";
}
//提示打开文件的路径
ui->textEdit->append(path);
ui->buttonFile->setEnabled(false); //失能选择文件按钮
ui->buttonSend->setEnabled(true); //使能发送文件按钮
}
else
{
qDebug() << "选择文件路径出错";
}
}
//发送文件按钮
void ServerWidget::on_buttonSend_clicked()
{
ui->buttonSend->setEnabled(false);
//先发送文件头信息 文件名##文件大小
QString head = QString("%1##%2").arg(fileName).arg(fileSize);
//发送头部信息
qint64 len = tcpSocket->write(head.toUtf8());
if(len > 0)
{
//再发送正真的文件信息
//为了防止TCP粘包 需要通过定时器延时 20 ms
timer.start(20);
}
else
{
qDebug() << "头部信息发送失败";
file.close();
ui->buttonFile->setEnabled(true);
ui->buttonSend->setEnabled(false);
}
}
void ServerWidget::sendData() //发送文件函数
{
ui->textEdit->append("正在发送文件……");
qint64 len = 0;
do
{
//每次发送数据的大小
char buf[4*1024] = {0};
len = 0;
//从文件中读数据
len = file.read(buf, sizeof(buf));
//发送数据 读多少 发多少
len = tcpSocket->write(buf, len);
//类成员sendSize累加
sendSize += len;
}while(len > 0);
//是否发送文件完毕
// if(sendSize == fileSize)
// {
// ui->textEdit->append("发送文件完毕");
// file.close();
// tcpSocket->disconnectFromHost();
// tcpSocket->close();
// }
}