文件传输流程:
服务器端:
serverwidget.ui
serverwidget.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();
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>
#include<QTimer>
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(&timer,&QTimer::timeout,[=](){
//关闭定时器
timer.stop();
//发送文件
sendData();
});
}
ServerWidget::~ServerWidget()
{
delete ui;
}
//选择文件按钮
void ServerWidget::on_buttonFile_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->buttonFile->setEnabled(false);
ui->buttonSend->setEnabled(true);
}
else
{
qDebug()<<"选择文件路径出错 62";
}
}
//发送文件按钮
void ServerWidget::on_buttonSend_clicked()
{
//先发送文件头信息
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()<<"头部信息发送失败 110";
file.close();
ui->buttonFile->setEnabled(true);
ui->buttonSend->setEnabled(false);
}
}
void ServerWidget::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;
}while(len > 0);
//是否发送文件完毕
if(sendSize == fileSize)
{
ui->textEdit->append("文件发送完毕");
file.close();
//把客户端挂关闭
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
}
客户端:
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();
}
clientwidget.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 = nullptr);
~ClientWidget();
private slots:
void on_pushButton_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);
tcpSocket = new QTcpSocket(this);
isStart = true;
connect(tcpSocket,&QTcpSocket::readyRead,[=](){
//取出接收的内容
QByteArray buf = tcpSocket->readAll();
if(true == isStart)
{
//接收头
isStart = false;
//解析头部信息 QString buf = "hello##1024"
// QString str = "hello##1024##mike";
// 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 error 40";
}
}
else//文件信息
{
qint64 len = file.write(buf);
recvSize += len;
if(recvSize == fileSize)
{
file.close();
QMessageBox::information(this,"完成","文件接收完成");
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
}
});
}
ClientWidget::~ClientWidget()
{
delete ui;
}
void ClientWidget::on_pushButton_clicked()
{
//获取服务器的IP和端口
QString ip = ui->lineEditIP->text();
quint16 port = ui->lineEditPort->text().toInt();
tcpSocket->connectToHost(QHostAddress(ip),port);
}
输出如下所示:
在当前目录下可找到传输的文件