Qt实现UDP多线程数据处理及发送的实例

 

逻辑与运行

程序逻辑图如下:

接收端运行截图如下:

客户端接收数据如下:

客户端用的是串口调试工具:

 

源码

程序结构如下:

源码如下:

data.h

#ifndef DATA_H
#define DATA_H

#include <QObject>
#include <QHostAddress>
#include <QString>
#include <QDebug>

#define SenderListWidget 0
#define ReceviListWidget 1

class PeerIP{
public:
  quint32 IPv4Address;
  quint16 port;

  PeerIP(const quint32 Ip, const quint16 por){

      IPv4Address = Ip;
      port = por;
  }

  friend QDebug operator << (QDebug os, PeerIP peerIP){

      os << "(" << peerIP.IPv4Address << ", " << peerIP.port
         << ")";

      return os;
  }
};


class UDPMsg{

public:
  virtual QString backFunction(const PeerIP *peerIP){

      Q_UNUSED(peerIP)
      return "";
  }

protected:
  UDPMsg(){}
  virtual ~UDPMsg(){}
};

class UDPMsgReciver:public UDPMsg{

public:
  QString backFunction(const PeerIP *peerIP){

      QHostAddress address(peerIP->IPv4Address);
      QString msg = "接收到P:" + address.toString() + " 端口:" + QString::number(peerIP->port) + "发来数据包, 正在处理数据";
      return msg;
  }
};

class UDPMsgSender:public UDPMsg{

public:
  QString backFunction(const PeerIP *peerIP){

      QHostAddress address(peerIP->IPv4Address);
      QString msg = "已发送到IP:" + address.toString() + " 端口:" + QString::number(peerIP->port) + "UDP数据包,准备发送数据";
      return msg;
  }
};

#endif // DATA_H

msgqueue.h

#ifndef MSGQUEUE_H
#define MSGQUEUE_H

#include <QThread>
#include <QList>
#include <QWidget>

class PeerIP;
class UDPMsg;
class Widget;


class MsgQueue: public QThread
{
public:
  enum MsgType{RecvQueue, SendQueue};
  MsgQueue(Widget *widget, MsgType type);
  ~MsgQueue();

  void appendPeerIP(const quint32 ipV4, const quint16 port);
  void stop();

protected:
  void run();

private:
  QList<PeerIP*> m_list;
  MsgType m_type;
  bool m_canExit;
  UDPMsg *m_udpMsg;
  Widget *m_widget;
};

#endif // MSGQUEUE_H

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QList>

QT_BEGIN_HEADER
class QUdpSocket;
QT_END_NAMESPACE

class PeerIP;
class MsgQueue;

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
  Q_OBJECT

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

  void insertMsgInList(const int Type, const QString msg);
  void senderMsg(quint32 ipV4, quint16 port);


protected:
  void canAppendInList(const quint32 ipV4, const quint16 port);
  void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE;

protected slots:
  void readPendingDatagrams();

private:
  Ui::Widget *ui;
  QUdpSocket *m_udpSocket;
  QList<PeerIP*> m_peerIP;

  MsgQueue *m_sender;
  MsgQueue *m_receiv;
};

#endif // WIDGET_H

main.cpp

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
  QApplication a(argc, argv);
  Widget w;
  w.show();

  return a.exec();
}

msgqueue.cpp

#include "msgqueue.h"
#include "data.h"
#include "widget.h"
#include <QDebug>

MsgQueue::MsgQueue(Widget *widget, MsgType type):
  m_canExit(false)
{
  if(type == RecvQueue){

      m_udpMsg = new UDPMsgSender;
  }
  else{

      m_udpMsg = new UDPMsgReciver;
  }
  m_widget = widget;
  m_type = type;
  start();
}

MsgQueue::~MsgQueue()
{
  for(int i = 0; i < m_list.size(); i++){

      delete m_list[i];
  }
}

void MsgQueue::appendPeerIP(const quint32 ipV4, const quint16 port)
{
  PeerIP *peerIp = new PeerIP(ipV4, port);
  m_list.append(peerIp);
}

void MsgQueue::stop()
{
  m_canExit = true;
}

void MsgQueue::run()
{
  while(!m_canExit){

      for(int i = 0; i < m_list.size(); i++){

          QString msg = m_udpMsg->backFunction(m_list[i]);
          m_widget->insertMsgInList(m_type, msg);

          if(m_type == RecvQueue){

              //这里可以写后端处理
          }
          else{

              m_widget->senderMsg(m_list[i]->IPv4Address, m_list[i]->port);
          }
      }
      msleep(1000);
  }
}

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include "data.h"
#include "msgqueue.h"
#include <QUdpSocket>
#include <QNetworkDatagram>
#include <QHostAddress>
#include <QDebug>
#include <QEventLoop>
#include <QTimer>


Widget::Widget(QWidget *parent) :
  QWidget(parent),
  ui(new Ui::Widget)
{
  ui->setupUi(this);

  this->setWindowTitle("CSDN IT1995");

  m_udpSocket = new QUdpSocket(this);

  if(!m_udpSocket->bind(7755)){

      qDebug() << "bind failed! The assert will be triggred!";
      Q_ASSERT(!"bind failed!");
  }

  m_sender = new MsgQueue(this, MsgQueue::SendQueue);
  m_receiv = new MsgQueue(this, MsgQueue::RecvQueue);

  connect(m_udpSocket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
}

Widget::~Widget()
{
  delete ui;
  delete m_sender;
  delete m_receiv;
  for(int i = 0; i < m_peerIP.size(); i++){

      delete m_peerIP[i];
  }
}

void Widget::insertMsgInList(const int Type, const QString msg)
{
  if(Type == SenderListWidget){

      ui->senderListWidget->insertItem(0, msg);
  }
  else{

      ui->receiverListWidget->insertItem(0, msg);
  }
}

void Widget::senderMsg(quint32 ipV4, quint16 port)
{
  QHostAddress address(ipV4);
  m_udpSocket->writeDatagram(QByteArray("I am fine, fuck you!"), address, port);
}

void Widget::canAppendInList(const quint32 ipV4, const quint16 port)
{
  for(int i = 0; i < m_peerIP.size(); i++){

      if(m_peerIP[i]->IPv4Address == ipV4 && m_peerIP[i]->port == port){

          qDebug() << "client in list";
          return;
      }
  }
  PeerIP *peerIP = new PeerIP(ipV4, port);
  m_peerIP.append(peerIP);
  m_sender->appendPeerIP(ipV4, port);
  m_receiv->appendPeerIP(ipV4, port);
}

void Widget::closeEvent(QCloseEvent *event)
{
  Q_UNUSED(event)
  m_sender->stop();
  m_receiv->stop();

  QEventLoop loop;
  QTimer::singleShot(1000, &loop, SLOT(quit()));
  loop.exec();
  this->close();
}

void Widget::readPendingDatagrams()
{
  while(m_udpSocket->hasPendingDatagrams()){


      QHostAddress srcAddress;
      quint16 nSrcPort;
      QByteArray datagram;
      datagram.resize(m_udpSocket->pendingDatagramSize());
      m_udpSocket->readDatagram(datagram.data(), datagram.size(), &srcAddress, &nSrcPort);;
      canAppendInList(srcAddress.toIPv4Address(), nSrcPort);
  }
}

关于Qt实现UDP多线程数据处理及发送的简单实例的文章就介绍至此,更多相关Qt UDP多线程发送内容请搜索编程宝库以前的文章,希望大家多多支持编程宝库

 模板由于模板元编程需要以面向对象为基础,所以如有疑问之处可以先补充一点C++面向对象的知识:C++面向对象这一篇就够了泛型初步由于C++是静态强类型语言,所以变量一经创建,则类型不得更改。如果我们希望创建一 ...