serverwidget.h
#ifndef SERVERWIDGET_H
#define SERVERWIDGET_H
#ifdef WIN32
#pragma execution_character_set("utf-8")
#endif
#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 = 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>
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::readAll,
[=]()
{
//取出客户端信息
QByteArray buf = tcpSocket->readAll();
if(QString(buf) == "file done")
{
ui->textEdit->append("文件发送完毕");
file.close();
//断开客户端端口
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
}
);
}
);
connect(&timer,&QTimer::timeout,
[=]()
{
//关闭定时器
timer.stop();
//发送文件
sendData();
}
);
}
serverWidget::~serverWidget()
{
delete ui;
}
//选择文件按钮
void serverWidget::on_buttonFile_clicked()
{
QString filePath = QFileDialog::getOpenFileName(this,"打开","../");
//判断,如果打开的路径有效
if(false == filePath.isEmpty())
{
fileName.clear();
fileSize = 0 ;
//获取文件信息
QFileInfo info(filePath);
fileName = info.fileName();//获取文件名字
fileSize = info.size();//获取文件大小
sendSize = 0 ; //已发送文件的大小,初始化为0
//只读方式打开文件
//指定文件的名字
file.setFileName(filePath);
//打开文件
bool isOK = file.open(QIODevice::ReadOnly);
if(false == isOK)
{
qDebug() << "只读方式打开文件失败 72";
}
//提示打开文件的路径
ui->textEdit->append(filePath);
ui->buttonFile->setEnabled(false);
ui->buttonSend->setEnabled(true);
}
else
{
qDebug()<<"打开的路径错误:58";
}
}
//发送文件按钮
void serverWidget::on_buttonSend_clicked()
{
//先发送文件头信息 文件名##文件大小
QString head = QString("%1##%2").arg(fileName).arg(fileSize);
//发送头部信息
qint64 len = tcpSocket->write( head.toUtf8() );
if(len > 0)//如果头部信息发送成功
{
//发送真正的文件信息
//防止TCP黏包文件,需要通过定时器延时20ms
timer.start(20);
}
else
{
qDebug() << "头部文件发送失败 101";
file.close();
ui->buttonFile->setEnabled(true);
ui->buttonSend->setEnabled(false);
}
}
void serverWidget::sendData()
{
qint64 len = 0;
do
{
//每次发送数据的大小,4k
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();
}
}
clientwidget.h
#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H
#ifdef WIN32
#pragma execution_character_set("utf-8")
#endif
#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_buttonConnect_clicked();
private:
Ui::ClientWidget *ui;
QTcpSocket *tcpSocket;
QFile file;//文件对象
QString fileName;//文件名字
qint64 fileSize;//文件大小
qint64 receiveSize;//已经收到文件的大小
bool isStart;//定义一个标识位
};
#endif // CLIENTWIDGET_H
clientwidget.cpp
#include "clientwidget.h"
#include "ui_clientwidget.h"
#include<QDebug>
#include<QMessageBox>
#include<QHostAddress>
#include<QProgressBar>
ClientWidget::ClientWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::ClientWidget)
{
ui->setupUi(this);
tcpSocket = new QTcpSocket(this);
isStart = true;
//进度条设置当前值0
ui->progressBar->setValue(0);
connect(tcpSocket,&QTcpSocket::readyRead,
[=]()
{
//取出接收的内容
QByteArray buf = tcpSocket->readAll();
if(true == isStart)
{
//接收头
isStart = false;
//解析头部信息,拆包,类似数组取下标的方式
//QString str = "hello##1024##mike"
//str.section("##",0,0)
//初始化
fileName = QString(buf).section("##",0,0);
fileSize = QString(buf).section("##",1,1).toInt();
receiveSize = 0;
//打开文件
file.setFileName(fileName);
bool isOK = file.open(QIODevice::WriteOnly);
if(false == isOK)
{
qDebug() << "WriteOnly error 38";
}
//弹出对话框,显示接收文件的信息
QString str1 = QString("接收的文件:[%1:%2kb]").arg(fileName).arg(fileSize/1024);
ui->textEdit->append(str1);
//QMessageBox::information(this,"文件信息",str1);
//设置进度条
ui->progressBar->setMinimum(0);//最小值
ui->progressBar->setMaximum(fileSize/1024);//最大值
ui->progressBar->setValue(0);//当前值
}
//读文件信息
else
{
qint64 len = file.write(buf);
receiveSize += len;
//客户端接收了多少,反馈给服务器
//QString str = QString::number(receiveSize);
//tcpSocket->write(str.toUtf8().data());
//更新进度条
ui->progressBar->setValue(receiveSize/1024);
if(receiveSize == fileSize)
{
//给服务器发送(接收文件完成)
//tcpSocket->write("file done");
file.close();
QMessageBox::information(this,"完成","文件接收完成");
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);
}