c/c++语言开发共享Qt多线程实现网络发送文件功能

本文实例为大家分享了qt多线程实现网络发送文件功能的具体代码,供大家参考,具体内容如下客户端给服务器发送文件,服务器进行接收文件的简单操作1. 服务器1. 创建qtcpserver 类的对象qtcps

c/c++开发分享Qt多线程实现网络发送文件功能实例为大家分享了qt多线程实现网络发送文件功能的具体代码,供大家参考,具体内容如下

客户端给服务器发送文件,服务器进行接收文件的简单操作

1. 服务器

1. 创建qtcpserver 类的对象

qtcpserver * server = new qtcpserver(this);

2. 进行监听

bool qtcpserver::listen(const qhostaddress &address = qhostaddress::any, quint16 port = 0)

3. 通过接收 qtcpserver 发出的 newconnection 的信号,进行下一步操作

[signal] void qtcpserver::newconnection()

4. 通过调用  nextpendingconnection 方法获取套接字

// 通过 this->m_server 调用 nextpendconnection  qtcpsocket * socket = server->nextpendingconnection();

5. 接收客户端发来是消息 通过 [signal] void qiodevice::readyread() 信号

6.客户端下线   [signal] void qabstractsocket::disconnected() 信号 表示

创建一个子线程类,继承 qthread ,重写父类的run() 方法

在run方法中,创建文件,接收客户端发的文件写进创建的文件中;

接收文件时,要先获取第一次客户端发来的文件大小;

获取客户端第一次发来的文件大小

// 进行接收数据的时候,需要知道客户端发来的文件的大小  // 先将客户端第一次发来的数据的大小读取出来  static int count = 0;   // 判断是否是客户端第一次发来的数据  static int total = 0;   // 记录文件的大小          if(count == 0)          {              this->m_tcp->read((char*)&total, 4);    // 获取文件大小          }

创建子线程类 并启动子线程

// 创建子线程类对象  myqthread * myqtread = new myqthread;  // 启动子线程  myqtread->start();

服务端代码:

widget.h 主线程头文件

#ifndef widget_h  #define widget_h     #include <qwidget>  #include <qtcpserver>     namespace ui {  class widget;  }     class widget : public qwidget  {      q_object  public:      explicit widget(qwidget *parent = 0);      ~widget();  private slots:      void on_listenbtn_clicked();  private:      // 创建qtcpserver 类的对象      qtcpserver * m_server;  private:      ui::widget *ui;  };     #endif // widget_h

widget.cpp  主线程:

#include "widget.h"  #include "ui_widget.h"     #include "myqthread.h"  #include <qmessagebox>     widget::widget(qwidget *parent) :      qwidget(parent),      ui(new ui::widget)  {      ui->setupui(this);         // 设置端口号      ui->port->settext("8989");      // 利用多线程进行链接服务器      // 1. 需要创建一个线程类的子类 ,让其继承qt中的线程qthread      // 2. 重写父类的run() 方法,在该函数内部编写子线程要处理的具体业务流程      // 3. 在主线程中创建子线程对象,new 一个就可以      // 4. 启动子线程,调用start() 方法      // 实例化qtcpserver 对象      this->m_server = new qtcpserver(this);      // 检验是否接收客户端的连接      connect(this->m_server, &qtcpserver::newconnection, this, [=]()      {          // 获取套接字          qtcpsocket * tcp = this->m_server->nextpendingconnection();          // 创建子线程类对象          myqthread * myqtread = new myqthread(tcp);          // 启动子线程          myqtread->start();          // 获取子线程中发来的客户端端口的消息          connect(myqtread, &myqthread::clientdisconnect, this, [=]()          {              //弹出对话框提示              qmessagebox::warning(this, "警告", "客户端已断开连接...");          });          // 接收接收完客户端的信号          connect(myqtread, &myqthread::overrecveid, this, [=]()          {              //弹出对话框提示              qmessagebox::information(this, "提示", "已接收文客户端发来的数据");              // 关闭套接字              tcp->close();              // 释放              tcp->deletelater();              // 释放线程              myqtread->quit();              myqtread->wait();              myqtread->deletelater();          });      });  }     widget::~widget()  {      delete ui;  }  // 点击监听按钮 进行监听 按钮转到槽的方式  void widget::on_listenbtn_clicked()  {      //获取端口号      unsigned short port = ui->port->text().toushort();      //利用this->m_s 调用listen 进行监听      this->m_server->listen(qhostaddress::any, port);  }

myqthread.h 子线程头文件

#ifndef myqthread_h  #define myqthread_h     //#include <qobject>     #include <qtcpsocket>  #include <qthread>     class myqthread : public qthread  {      q_object  public:      explicit myqthread(qtcpsocket *tcp, qobject *parent = nullptr);         // 2.重写qthread 类中的受保护成员 run() 方法  protected:      void run();     public:      // 自定义套接字对象 记录主线程传进的套接字对象 tcp      qtcpsocket * m_tcp;     signals:      // 自定义信号 将服务器接收完客户端发来的数据 告诉主线程      void overrecveid();      // 自定义信号 将客户端断开连接 告诉主线程      void clientdisconnect();     public slots:  };     #endif // myqthread_h

myqthread.cpp 子线程文件

#include "myqthread.h"     #include <qfile>     myqthread::myqthread(qtcpsocket *tcp, qobject *parent) : qthread(parent)  {      this->m_tcp = tcp;  }  // 2.重写qthread 类中的受保护成员 run() 方法  void myqthread::run()  {      // 1.创建文件 打开文件      qfile * file = new qfile("recv.txt");      file->open(qfile::writeonly);   // 以只写的方式打开文件      // 2.检验是否进行读写      connect(this->m_tcp, &qtcpsocket::readyread, this, [=]()      {          // 进行接收数据的时候,需要知道客户端发来的文件的大小          // 先将客户端第一次发来的数据的大小读取出来          static int count = 0;   // 判断是否是客户端第一次发来的数据          static int total = 0;   // 记录文件的大小          if(count == 0)          {              this->m_tcp->read((char*)&total, 4);    // 获取文件大小          }          // 将剩下的数据全部读取出来          // 获取客户端发来的数据          qbytearray recvclient = this->m_tcp->readall(); // 全部接收          // 将读取的数据的量记录到count中          count += recvclient.size();          // 将数据写进文件中          file->write(recvclient);          // 判断服务器是否把客户端发来的数据全部读取完          if(count == total)          {              // 关闭套接字              this->m_tcp->close();              // 释放套接字              this->m_tcp->deletelater();              // 关闭文件              file->close();              file->deletelater();              // 自定义一个信号 告诉主线程文件 已接收完毕              emit overrecveid();          }      });      // 3.检验客户端是否断开连接      connect(m_tcp, &qtcpsocket::disconnected, this, [=]()      {          // 将客户端断开连接 发送给主线程          emit this->clientdisconnect();      });      // 调用 exec 进入事件循环 阻塞      exec();  }

Qt多线程实现网络发送文件功能

2.客户端

1. 绑定 ip 和 端口号

[virtual] void qabstractsocket::connecttohost(const qstring &hostname, quint16 port, openmode openmode = readwrite, networklayerprotocol protocol = anyipprotocol)

2. 连接服务器

[signal] void qabstractsocket::connected()

3. 通过套接字 调用 write方法发送消息给服务器

qint64 qiodevice::write(const char *data, qint64 maxsize)

4. 断开连接

[signal] void qabstractsocket::disconnected()

利用多线程实现 选择文件 发送文件                          

利用第二种多线程的方法                                

1.创建一个新的类,让这个类从qobject中派生                  
2.在这个新的类中添加一个公有的成员函数,函数体是我们要子线程中执行的业务逻辑    
3.在主线程中创建一个qthread对象,这个就是子线程的对象            
4.在主线程中创建一个工作类的对象                          
5.将工作类对象移动到子线程对象中,需要调用qobject类提供的movethread
6.启动子线程,调用start() 这个线程启动了,当时移动到线程中的对象并没有工作
7.调用工作类的对象函数,让这个函数开始执行,这个时候是在移动到那个子线程中运行的。       

客户端代码: 

mythread.h 任务类头文件

#ifndef mythread_h  #define mythread_h     #include <qobject>  #include <qtcpsocket>     class mythread : public qobject  {      q_object  public:      explicit mythread(qobject *parent = nullptr);         // 连接服务器      void connecttoserver(unsigned short port, qstring ip);      // 发送文件      void sendfile(qstring path);     private:      // 创建qtcpsocket 类的对象      qtcpsocket * m_socket;     signals:      // 自定义一个信息 告诉主线程 成功连接到服务器      void connectok();         // 自定义一个信号 告诉主线程服务器已断开连接      void gameover();         // 自定义一个信号 将获取的百分比发送给主线程      void sendpercent(int);     public slots:  };     #endif // mythread_h

mythread.cpp 任务类文件

#include "mythread.h"     #include <qfileinfo>  #include <qmessagebox>     mythread::mythread(qobject *parent) : qobject(parent)  {     }  // 连接服务器  void mythread::connecttoserver(unsigned short port, qstring ip)  {      // 实例化socket类的对象      this->m_socket = new qtcpsocket(this);      // 尝试与服务器取得连接 绑定ip 和端口号      this->m_socket->connecttohost(ip, port);      // 检验是否成功与服务器取等连接      connect(this->m_socket, &qtcpsocket::connected, this, [=]()      {          emit this->connectok(); // 自定义一个信号 告诉主线程 成功连接上服务器      });      // 检验服务器是否断开连接      connect(this->m_socket, &qtcpsocket::disconnected, this, [=]()      {          this->m_socket->close();    // 关闭套接字          emit this->gameover();      // 发送信号 告诉主线程 服务器已断开连接      });  }  // 发送文件  void mythread::sendfile(qstring path)  {      // 1.获取文件大小      qfileinfo info(path);      int filesize = info.size();      // 2.打开文件      qfile file(path);      bool ret = file.open(qfile::readonly);      if(!ret)      {          qmessagebox::warning(null, "警告", "打开文件失败");          return; // 退出函数      }      // 判断什么时候读完文件      while(!file.atend())      {          // 第一次发送文件的时候 将文件的大小发送给服务器          // 定义一个标记 当标记为0时, 表示第一次发送文件          static int num = 0;          if(num == 0)          {              this->m_socket->write((char*)&filesize, 4); // 将文件大小发送给服务器          }          // 在循环体中 每次读取一行          qbytearray line = file.readline();          // 每次发送一次数据,就将发送的数据的量记录下来 用于更新进度条          num += line.size();          // 基于num值 计算百分比          int percent = (num*100/filesize);          // 将百分比发送给主线程          emit this->sendpercent(percent);          // 将读取的数据通过套接字对象发送给服务器          this->m_socket->write(line);      }  }

widget.h 主线程头文件

#ifndef widget_h  #define widget_h     #include <qwidget>     namespace ui {  class widget;  }     class widget : public qwidget  {      q_object     public:      explicit widget(qwidget *parent = 0);      ~widget();     signals:      // 自定义一个信号 告诉子线程进行链接服务器      void telltoconnect(unsigned short port, qstring ip);      // 自定义一个信号 将选中的文件路径发送给任务类      void sendtofile(qstring);     private slots:      void on_connectbtn_clicked();         void on_selectbtn_clicked();         void on_sendbtn_clicked();     private:      qstring m_path;  private:      ui::widget *ui;  };     #endif // widget_h

widget.cpp

#include "widget.h"  #include "ui_widget.h"     #include <qfiledialog>  #include <qmessagebox>  #include <qthread>  #include "mythread.h"     widget::widget(qwidget *parent) :      qwidget(parent),      ui(new ui::widget)  {      ui->setupui(this);         // 利用多线程实现 选择文件 发送文件      // 利用第二种多线程的方法      // 1.创建一个新的类,让这个类从qobject中派生      // 2.在这个新的类中添加一个公有的成员函数,函数体是我们要子线程中执行的业务逻辑      // 3.在主线程中创建一个qthread对象,这个就是子线程的对象      // 4.在主线程中创建一个工作类的对象      // 5.将工作类对象移动到子线程对象中,需要调用qobject类提供的movethread方法      // 6.启动子线程,调用start() 这个线程启动了,当时移动到线程中的对象并没有工作      // 7.调用工作类的对象函数,让这个函数开始执行,这个时候是在移动到那个子线程中运行的。         // 1.创建qthread对象      qthread *t = new qthread;      // 2.创建任务类的对象      mythread * working = new mythread;      // 3.将任务类对象移动到子线程中      working->movetothread(t);      // 启动子线程      t->start();      // 4.设置ip 端口号      ui->ip_lineeide->settext("127.0.0.1");      ui->port_lineedit->settext("8989");      // 5.设置进度条      ui->progressbar->setrange(0, 100);  // 进度条的范围      ui->progressbar->setvalue(0);       // 初始化为0      // 6.更新进度条 通过连接任务类发来的信号 实现      connect(working, &mythread::sendpercent, ui->progressbar, &qprogressbar::setvalue);      // 7.接收任务类发来的成功连接到服务器 信号      connect(working, &mythread::connectok, this, [=]()      {          qmessagebox::information(this, "提示", "成功连接到服务器");          // 将文件按钮设置成不可用状态          ui->sendbtn->setdisabled(false);      });      // 8.连接任务类发来的断开连接的信号      connect(working, &mythread::gameover, this, [=]()      {          qmessagebox::warning(this, "警告", "服务器已断开连接");          //释放支援          t->quit();          t->wait();          t->deletelater();          working->deletelater();          // 将文件按钮设置成可用状态          ui->sendbtn->setdisabled(true);      });      // 7.将信号和工作类对象中的任务函数连接      connect(this, &widget::telltoconnect, working, &mythread::connecttoserver);      // 8.将文件路径发给任务函数      connect(this, &widget::sendtofile, working, &mythread::sendfile);      // 9.将发送文件按钮设置成可用状态      ui->sendbtn->setdisabled(true);  }     widget::~widget()  {      delete ui;  }  // 连接服务器  void widget::on_connectbtn_clicked()  {      // 获取ip 和 端口号      qstring ip = ui->ip_lineeide->text();      unsigned short port = ui->port_lineedit->text().toshort();      // 将ip 和 端口号 发送取出      emit this->telltoconnect(port, ip);      // 将发送文件按钮设置成不可用状态      ui->sendbtn->setdisabled(false);  }  // 选中文件  void widget::on_selectbtn_clicked()  {      m_path = qfiledialog::getopenfilename();  // 打开文件选择对话框      // 判断选中的对话框不能为空      if(m_path.isempty())          qmessagebox::warning(this, "警告", "选中要发送的文件不能为空");      // 将选中的文件路径显示到单行编辑框中      ui->filepath_lineedit->settext(m_path);  }  // 发送文件  void widget::on_sendbtn_clicked()  {      // 将选中的文件路径发送给任务类      emit this->sendtofile(m_path);  }

程序运行结果:

Qt多线程实现网络发送文件功能

以上就是c/c++开发分享Qt多线程实现网络发送文件功能的全部内容,希望对大家的学习有所帮助,也希望大家多多支持<计算机技术网(www.ctvol.com)!!>。

需要了解更多c/c++开发分享Qt多线程实现网络发送文件功能,都可以关注C/C++技术分享栏目—计算机技术网(www.ctvol.com)!

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/c-cdevelopment/1236992.html

(0)
上一篇 2022年9月7日
下一篇 2022年9月7日

精彩推荐