Qt网络编程小项目-基于Tcp协议的文件传输项目

  • Post author:
  • Post category:其他



目录


项目描述


Qt下Tcp服务器端和客户端流程:


具体流程:


客户端:


服务器端:


源码:


服务器端:


服务器头文件:


服务器源文件:


服务器端ui


客户端:


客户端头文件:


客户端源文件:


客户端ui:


项目描述


利用Tcp协议实现服务器端和客户端数据的传输,客户端向服务器端传输文件(音频、视频、文本)类似客户端上传文件

Qt下Tcp服务器端和客户端流程:

具体流程:

客户端:

头文件:


#include <QWidget>


#include <QTcpSocket>


#include <QFileDialog>//显示文件对话框


#include <QFileInfo>//获取文件信息


#include <QTimer>


  1. 客户端连接服务器

客户端只需一个接收套接字 tcpSocket = new QTcpSocket(this);

tcpSocket->connectToHost(Ip,port);连接到服务器端

开辟一个QByteArray array内存空间,通过信号与槽connect

  1. 1选择要传输的文件

QString filePath = QFileDialong::getOpenFileName(this);

QFileInfo FileData(filePath);//获取文件信息

filename = FileData.fileName();//获得文件名字

filesize = FileData.size();//获得文件大小 字节

  1. 2文件操作

QFile file创建一个文件描述符,

  1. 3文件发送


文件的发送分为两个部分:

a.先发送一个包含文件信息的字符串类型为” filename**filesize ”

QString head = filename + "**" + QString::number(filename); 
qint64 length = tcpSocket->write(head.toutf8); 
if(length>0)//发送成功 
        myTimer->start(20);//设置一个定时器 防止内容粘包 
else //发送不成功 
        file.close();

b.防止粘包发送成功后设置一个延迟 设置一个定时器myTimer 开始发送文件本身

 myTimer = new QTimer(this); 
connect(myTimer,&QTimer::timeout, this ,[&](){ 
myTimer->stop(); 
qint64 len; 
qint64 sendSize = 0;//已经发送文件大小 
do{ char buf[4*1024] = {0};//一次读取char这么大 
len = 0; 
len = file.read(buf,sizeof(buf));//从file中读取4096放到buf中 
tcpSocket->write(buf,len);//写入 
sendSize += len; ui->progressBar->setValue(sendSize/1024);//设置进度条 }while(len>0); 
if(sendSize == filesize)//发送内存大小和实际文件内存大小相等传输完毕 
{ file.close(); 
tcpSocket->disconnectFromHost();//断开连接 
tcpSocket->close();
 } });

服务器端:

头文件:


#include <QTcpServer>

监听套接字


#include <QTcpSocket>

通信套接字


QTcpServer *tcpserver;

监听套接字对象


QTcpSocket *clientConnection = nullptr;

通信套接字对象

1. 监听对象开辟空间


tcpserver = new QTcpServer(this);

调用listen()监听 这里使用的是本地主机127.0.0.1的Ip地址


tcpserver ->listen(QHostAddress::LocalHost,ui->lineEdit->text().toInt());

2.连接客户端 接受文件

  • 采用信号与槽的方式

connect(tcpserver,&QTcpServer::newConnection,this,[&](){


clientConnection = tcpserver->nextPendingConnection();

clientConnection->write(“Welcome to connect to the server!”);//连接成功向客户端发送成功连接字样

//接收端

connect(clientConnection, QTcpSocket::readyRead,this,[&](){


QByteArray array = clientConnection->readAll();

if(headInfo){ //第一次读出的信息应该是head文件信息

headInfo = false;

recvSize = 0;

filename = QString(array).section(“**”,0,0); //分割出需要的信息

filesize = QString(array).section(“**”,1,1).toInt();

file.setFileName(filename);

file.open(QIODevice::WriteOnly);//发送端只读打开

//设置进度条

ui->progressBar->setMinimum(0);

ui->progressBar->setMaximum(filesize/1024);

ui->progressBar->setValue(0);//初始为0

}

else{//这里收到的文件是文件本身

qint64 length = file.write(array);

if(length >0)

recvSize += length;

ui->progressBar->setValue(recvSize/1024);

if(recvSize == filesize)

{


//文件接受完毕

QMessageBox::information(this,”完成”,”文件接受完成”);

file.close();

}

}

});

} );

源码:

服务器端:

服务器头文件:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QFileDialog>
#include <QFile>
#include <QMessageBox>


namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget *ui;
    QTcpServer *tcpserver;//监听服务器端套接字
    QTcpSocket *clientConnection = nullptr;//通信套接字

    bool headInfo = true;
    QString filename;
    qint64 filesize;
    qint64 recvSize;//收到文件的大小
    QFile file;
};

#endif // WIDGET_H

服务器源文件:

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    setWindowTitle("服务器");
    ui->lineEdit->setText("8080");//初始端口号值

    tcpserver = new QTcpServer(this);

}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_pushButton_clicked()
{


    tcpserver ->listen(QHostAddress::LocalHost,ui->lineEdit->text().toInt());//(LocalHost本机环回地址)

    connect(tcpserver,&QTcpServer::newConnection,this,[&](){
        clientConnection = tcpserver->nextPendingConnection();
        clientConnection->write("Welcome to connect to the server!");

        //接收端
        connect(clientConnection, QTcpSocket::readyRead,this,[&](){
            QByteArray array = clientConnection->readAll();
            if(headInfo){ //第一次读出的信息应该是head文件信息
                 headInfo = false;
                 

                 recvSize = 0;
                 filename = QString(array).section("**",0,0); //分割出需要的信息
                 filesize = QString(array).section("**",1,1).toInt();

                 file.setFileName(filename);
                 file.open(QIODevice::WriteOnly);//发送端只读打开

                 //设置进度条
                 ui->progressBar->setMinimum(0);
                 ui->progressBar->setMaximum(filesize/1024);
                 ui->progressBar->setValue(0);//初始为0
            }
            else{//这里收到的文件是文件本身
                qint64 length = file.write(array);
                if(length >0)
                    recvSize += length;
                 ui->progressBar->setValue(recvSize/1024);
                 if(recvSize == filesize)
                 {
                     //文件接受完毕
                     QMessageBox::information(this,"完成","文件接受完成");
                     file.close();
                 }

            }
        });
    } );
    ui->pushButton->setEnabled(false);
}

服务器端ui

客户端:

客户端头文件:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QFileDialog>//显示文件对话框
#include <QFileInfo>//获取文件信息
#include <QTimer>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private slots:
    void on_pushButton_clicked();

    void on_pushButton_2_clicked();

    void on_pushButton_3_clicked();

private:
    Ui::Widget *ui;
    QTcpSocket *tcpSocket; //客户端只需要一个接受套接字
    QString filename;
    qint64 filesize;
    QFile file;     //文件描述符
    QTimer *myTimer; //定时器
};

#endif // WIDGET_H

客户端源文件:

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    setWindowTitle("客户端");

    tcpSocket = new QTcpSocket(this);

    connect(tcpSocket, &QTcpSocket::readyRead,this,[&](){
        QByteArray array = tcpSocket->readAll();
        qDebug()<<"服务器: "<<array;
    });

    myTimer = new QTimer(this);
    connect(myTimer,&QTimer::timeout, this ,[&](){
        myTimer->stop();

        qint64 len;
        qint64 sendSize = 0;//已经发送文件大小

        do{
            char buf[4*1024] = {0};//一次读取char这么大
            len = 0;
            len = file.read(buf,sizeof(buf));
            tcpSocket->write(buf,len);
            sendSize += len;
            ui->progressBar->setValue(sendSize/1024);
        }while(len>0);
        if(sendSize == filesize )
        {
            file.close();
            tcpSocket->disconnectFromHost();//断开连接
            tcpSocket->close();
        }
    });

}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_pushButton_clicked()//连接按钮
{
    //连接服务器
    tcpSocket->connectToHost(ui->lineEdit->text(),ui->lineEdit_2->text().toInt());
}

void Widget::on_pushButton_2_clicked()//打开按钮
{
   QString filePath =  QFileDialog::getOpenFileName(this);

   //发送文件时先发送一个文件名字和文件大小,如果两端文件大小相同说明发送完毕
   QFileInfo FileData(filePath);//获取文件信息
   filename = FileData.fileName();//获得文件名字
   filesize = FileData.size();//获得文件大小

   qDebug()<<"文件名:"<<filename;
   qDebug()<<"文件大小:"<<filesize;

    if(!filePath.isEmpty())
    {
        ui->label_3->setText(filePath);//显示文件名字
        file.setFileName(filePath);
        file.open(QIODevice::ReadOnly);//发送端只读打开
    }

    //设置进度条
    ui->progressBar->setMinimum(0);
    ui->progressBar->setMaximum(filesize/1024);
    ui->progressBar->setValue(0);//初始为0
}

void Widget::on_pushButton_3_clicked()
{
   //头信息
  QString head = filename + "**" + QString::number(filesize);  //强制类型转换成字符串
  //发送head文件
  qint64 length = tcpSocket->write(head.toUtf8());
  if(length>0)//发送成功
      myTimer->start(20);//设置一个定时器 防止内容粘包

  else        //发送不成功
      file.close();
}

客户端ui:



版权声明:本文为super8ayan原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。