TCPFile
tcp协议传输文件
TCPFile.pro
QT += core gui network
clientwidget.h
#include <QWidget>
#include <QTcpSocket> // 通信套接字
#include <QFile>
private slots:
void on_pushButton_clicked();
private:
QTcpSocket *tcpSocket;
QFile file; // 文件对象
QString fileName; // 文件名字
qint64 fileSize; // 文件大小
qint64 recvSize; // 已经接收文件的大小
bool isStart; // 标志位
widget.h
#include <QTcpServer> // 监听套接字
#include <QTcpSocket> // 通信套接字
#include <QFile>
#include <QTimer>
public:
void sendData(); // 发送文件数据
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
private:
QTcpServer *tcpServer;
QTcpSocket *tcpSocket;
QFile file; // 文件对象
QString fileName; // 文件名字
qint64 fileSize; // 文件大小
qint64 sendSize; // 已经发送文件的大小
QTimer timer; // 定时器
clientwidget.cpp
#include <QDebug>
#include <QMessageBox>
#include <QHostAddress>
Clientwidget::Clientwidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Clientwidget)
{
ui->setupUi(this);
isStart = true;
tcpSocket = NULL;
// 分配空间,指定父对象
tcpSocket = new QTcpSocket(this);
setWindowTitle("客户端");
// 进度条
ui->progressBar->setValue(0); // 当前值
connect(tcpSocket, &QTcpSocket::readyRead, [=](){
// 取出接收内容
QByteArray buf = tcpSocket->readAll();
if(true == isStart)
{ // 接收头信息
isStart = false;
// 解析头部信息 举例:
// 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 error";
}
// 设置进度条
ui->progressBar->setMinimum(0); // 最小值
ui->progressBar->setMaximum(fileSize/1024); // 最大值
ui->progressBar->setValue(0); // 当前值
}
else { // 文件信息
qint64 len = file.write(buf);
if(len > 0){ // 接收数据大于0
recvSize += len; // 累加接收大小
qDebug() << len;
}
ui->progressBar->setValue(recvSize/1024); // 更新进度条
if(recvSize == fileSize){ // 文件接收完毕
file.close();
QMessageBox::information(this, "完成", "文件接收完成");
// 给服务器发送 接收文件完成的信息
tcpSocket->write("file done");
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
}
});
}
void Clientwidget::on_pushButton_clicked()
{
// 获取服务器ip和端口
QString ip = ui->lineEdit->text();
quint16 port = ui->lineEdit_2->text().toInt();
// 主动和服务器建立连接
tcpSocket->connectToHost(QHostAddress(ip), port);
}
widget.cpp
#include <QFileDialog>
#include <QDebug>
#include <QFileInfo>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
// 监听套接字
tcpServer = new QTcpServer(this);
// 监听
tcpServer->listen(QHostAddress::AnyIPv4, 8888);
setWindowTitle("服务器 端口8888");
// 一开始两个按钮都不能按 需要建立连接后才可以按下
ui->pushButton->setEnabled(false);
ui->pushButton_2->setEnabled(false);
// 如果客户端成功和服务器连接
// tcpServer 会自动触发 newConnection()
connect(tcpServer, &QTcpServer::newConnection, [=](){
// 取出建立好连接的套接字
tcpSocket = tcpServer->nextPendingConnection();
// 获取对方的ip和端口
QString ip = tcpSocket->peerAddress().toString();
quint16 port = tcpSocket->peerPort();
// qDebug() << port;
QString temp = QString("[%1:%2]:成功连接").arg(ip).arg(port);
ui->textEdit->setText(temp); // 显示到编辑区
// 成功建立连接后,才可以按钮 选择文件
ui->pushButton->setEnabled(true);
connect(tcpSocket, &QTcpSocket::readyRead, [=](){
// 取客户端的信息
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();
});
}
Widget::~Widget()
{
delete ui;
}
void Widget::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();
ui->pushButton->setEnabled(false);
ui->pushButton_2->setEnabled(false);
}
}
// 选择文件按钮
void Widget::on_pushButton_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() << "只读方式打开文件失败";
}
// 提示打开文件的路径
ui->textEdit->append(filePath);
ui->pushButton->setEnabled(false);
ui->pushButton_2->setEnabled(true);
}
else{
qDebug() << "选择文件路径出错";
}
}
// 发送文件按钮
void Widget::on_pushButton_2_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() << "头部信息发送失败";
file.close();
ui->pushButton->setEnabled(true);
ui->pushButton_2->setEnabled(false);
}
}
clientwidget.ui
widget.ui