qt+TCP文件传输

简述

刚开始学习qt,在学习完网络编程后,觉得还是需要总结一下,毕竟总结才能更加的深刻。

本人第一次在csdn上写博客,想监督一下自己,让自己有一个学习的动力。好了不多说了,

目录

 

目录

简述

一、网络体系结构模型

二、TCP/IP协议

1、TCP/IP介绍

2、TCP/IP结构

3、TCP传输协议

三、socket套接字

1、Socket

2、在linux中C语言的使用流程

3、QT中的使用


 


一、网络体系结构模型

   OSI模型              TCP/IP协议 模型

上图可以看到tcp/ip模型是将osi模型简化,将原来的七层简化成四层,最右边的图是对应四层经常用到的一些协议。

常用的网络协议有:

  • TCP(Transport Control Protocol)传输控制协议
  • IP(Internetworking Protocol)网间协议
  • UDP(User Datagram Protocol)用户数据报协议
  • ICMP(Internet Control Message Protocol)互联网控制信息协议
  • SMTP(Simple Mail Transfer Protocol)简单邮件传输协议
  • SNMP(Simple Network manage Protocol)简单网络管理协议
  • HTTP(Hyper Text Transfer Protocol) 超文本传输协议
  • FTP(File Transfer Protocol)文件传输协议
  • ARP(Address Resolution Protocol)地址解析协议

这些看看就好,要用的时候查一下,下面主要讲一下tcp/ip协议

 

二、TCP/IP协议

1、TCP/IP介绍

  • TCP/IP协议 q 传输控制/网际协议(Transfer Control Protocol/Internet Protocol) 又称作网络通讯协议
  • Internet国际互联网络的基础,RFC793
  • 一组协议,通常称它为TCP/IP协议族 
  • 四个层次:网络接口层、网际层、传输层、应用层

2、TCP/IP结构

3、TCP传输协议

 是一种面向连接的传输层协议,它能提供高可靠性通信(即 数据无误、数据无丢失、数据无失序、数据无重复到达的 通信)
 适用情况:

  • 适合于对传输质量要求较高,以及传输大量数据的通信。
  • 在需要可靠数据传输的场合,通常使用TCP协议
  • MSN/QQ等即时通讯软件的用户登录账户管理相关的功能 通常采用TCP

三、socket套接字

1、Socket

  • 一个编程接口
  • 是一种特殊的文件描述符 (everything in Unix is a file) n
  • 并不仅限于TCP/IP协议 n
  • 面向连接 (Transmission Control Protocol - TCP/IP) n
  • 无连接 (User Datagram Protocol -UDP 和 Inter-network Packet Exchange - IPX)

2、在linux中C语言的使用流程

在这里我就不细讲c/c++中的使用,因为我们有QT这个框架,QT中帮助我们封装了很多socket的库,使用起来很方便。但是我还是要讲一下,在c语言中linux环境下TCP通信息的流程,因为只有知道了底层调用的一些原理,用起框架来才更加的顺手。

常用接口函数:

socket() 创建套接字 

bind() 绑定本机地址和端口 

connect() 建立连接  

listen() 设置监听端口 

accept() 接受TCP连接 

recv(), read(), recvfrom() 数据接收 

send(), write(), sendto() 数据发送 

close(), shutdown() 关闭套接字
在这里不讲这些函数的用法,可以自己查到例子,下面直接给出流程吧

 

从上图大家就可以很清楚的看到服务器和客户端的运行流程,对于客户端的bind哪一步文档上是说可以bind可以不bind,一般我们都不去将客户端bind

在这里我要说一下,对于系统编程中socket套接字都是默认阻塞的,因此accept这个函数会阻塞在哪里一直等到有客户端连接上来,还有读操作也是阻塞状态的。想要解除套接字阻塞,那就需要用到IO模型的知识了这里小伙伴们可以去查一查,非阻塞和阻塞的使用体验完全不一样哦。

 

3、QT中的使用

在大致了解完socket的是怎么回事之后,我们就可以来学习QT中TCP通信的一些简单的应用了。

我们知道tcp通信的流程是

    1)、服务器:申请套接字 -> 绑定套接字 -> 监听套接字 -> 接收连接 -> 开始发送数据接收数据

    2)、客户端:申请套接字 -> 建立连接 -> 发送数据 和 接收数据

而在qt中将,这些操作都被封装成在一个模块中,所以我们就没有这么复杂的操作,大致流程如下

   1)、服务器:

          1、启动服务器,即监听

               mserver.listen(QHostAddress::Any,8080);

          2、连接newConnection这个信号判断是否有客户端连接进来       

              connect(&mserver, &QTcpServer::newConnection, this, &FileRecv::new_client);

          3、创建套接字

              QTcpSocket *msocket = mserver.nextPendingConnection();

   2)、客户端

         1、初始化一个套接字对象

         2、连接connected这个信号判断是否连接成功

         3、对套接字进行读写

 

下面我就一个传输文件的例子来讲解qt中怎么使用tcp通信。

首先我们给qt程序添加模块如下

QT       += core gui network

在传输文件的时候我们要考虑到文件很大一次传过去数据容易丢失,因此我们分多次来传输。首先,我们封装一个文件数据头

文件名,文件大小。先将文件的头信息发送过去,在分多次发送文件的内锅过去。对于接收端来说,我们先接收头信息,在接收文件内容信息。

 

下面直接添加代码 server :

#ifndef FILERECV_H
#define FILERECV_H

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

namespace Ui {
class FileRecv;
}

class FileRecv : public QWidget
{
    Q_OBJECT

public:
    explicit FileRecv(QWidget *parent = nullptr);
    ~FileRecv();
protected slots:
    void read_data();
    void new_client();
private:
    Ui::FileRecv *ui;
    QTcpServer mserver;
    QFile file;
    QString filename;
    quint64 filesize;
    quint64 recvsize;
};

#endif // FILERECV_H
#include "filerecv.h"
#include "ui_filerecv.h"
#include <QDataStream>
FileRecv::FileRecv(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::FileRecv)
{
    ui->setupUi(this);
    //关联客户端连接信号
    connect(&mserver, &QTcpServer::newConnection, this, &FileRecv::new_client);
    //启动服务器
    mserver.listen(QHostAddress::Any,8080);
}

FileRecv::~FileRecv()
{
    delete ui;
}
void FileRecv::new_client()
{
    //创建与客户端通信的套接字
    QTcpSocket *msocket = mserver.nextPendingConnection();
    //关联读数据信号readyRead
    connect(msocket, &QTcpSocket::readyRead, this, &FileRecv::read_data);
    filesize = 0;
    recvsize = 0;
}

void FileRecv::read_data()
{
    QTcpSocket *msocket = dynamic_cast<QTcpSocket*>(sender());
    if(filesize == 0) //表达第一次读取数据--读文件信息
    {
        QByteArray array = msocket->readAll();
        QDataStream stream(&array, QIODevice::ReadOnly);//把套接字与数据流绑定
        stream>>filesize>>filename;//获取文件大小, 文件名

        //设置进度条最大值
        ui->progressBar->setMaximum(filesize);

        //打开文件
        file.setFileName(filename);
        file.open(QIODevice::WriteOnly);

        //显示进度条
        this->show();
    }

    //读文件内容
    if(recvsize <  filesize)
    {
        //读取一段写一段
        QByteArray array = msocket->readAll();
        file.write(array);
        recvsize += array.size();
        //更新进度条
        ui->progressBar->setValue(recvsize);
    }

    if(recvsize == filesize)
    {
        //读完,关闭文件
        file.close();
        //关闭套接字
        msocket->disconnectFromHost();
        //隐藏进度条
        this->hide();
    }
}

界面,添加一个进度条

客户端:

界面

//client.h

#ifndef FILESEND_H
#define FILESEND_H

#include <QWidget>
#include <QTcpSocket>
#include <QFile>


namespace Ui {
class FileSend;
}

class FileSend : public QWidget
{
    Q_OBJECT

public:
    explicit FileSend(QWidget *parent = nullptr);
    ~FileSend();
private slots:
    void on_selectBt_clicked();
    void on_sendBt_clicked();
    void send_file_head();
    void send_file_text();
private:
    Ui::FileSend *ui;
    QTcpSocket msocket;
    QFile file;
    QString filename;
    quint64 filesize;
    quint64 sendsize;
};

#endif // FILESEND_H
//client.cpp

#include "filesend.h"
#include "ui_filesend.h"
#include <QFileDialog>
#include <QFileInfo>
#include <QDataStream>

FileSend::FileSend(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::FileSend)
{
    ui->setupUi(this);
    //当客户端连接成功会发送connected信号, 当客户端掉线会发送disconnected信号
    connect(&msocket, &QTcpSocket::connected, this, &FileSend::send_file_head);

    //当套接字发送完毕会发送一个信号bytesWritten
    connect(&msocket, &QTcpSocket::bytesWritten, this, &FileSend::send_file_text);

}

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

void FileSend::on_selectBt_clicked()
{
    //通过文件对话框获取文件路径
    QString filepath = QFileDialog::getOpenFileName(this);
    ui->fileEdit->setText(filepath);
}

void FileSend::on_sendBt_clicked()
{
    //连接服务器
    msocket.connectToHost(ui->ipedit->text(), ui->portedit->text().toUShort());

    //发送文件信息
    qDebug()<<"connect";

    //初始化
    filesize = 0;
    sendsize = 0;
}

//发送文件头信息
void FileSend::send_file_head()
{
    //发送文件名,文件大小
    QFileInfo info(ui->fileEdit->text());//文件信息对象
    filename = info.fileName();
    filesize = info.size();

    QByteArray array; //空间
    //把array与数据流绑定
    QDataStream stream(&array, QIODevice::WriteOnly);
    stream<<filesize<<filename;

    //设置进度条最大值
    ui->progressBar->setMaximum(filesize);

    //打开文件准备读取数据发送
    file.setFileName(ui->fileEdit->text());
    file.open(QIODevice::ReadOnly);

    //发送
    msocket.write(array);
}

void FileSend::send_file_text()
{
    if(sendsize < filesize)
    {
        QByteArray array = file.read(1024*10);//读取一段内容
        msocket.write(array);//发送一段内容
        sendsize += array.size();
        //设置进度条
        ui->progressBar->setValue(sendsize);
    }
    if(sendsize == filesize)
    {
        file.close();//关闭文件
    }
}

 

  • 9
    点赞
  • 89
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值