Qt网络通信,多线程实现UDP通信

Qt使用多线程进行UDP通信

UDP

  1. 由于要使用套接字,所以需要在服务器和客户端的工程文件中都添加QT += core gui network
  2. 使用writeDatagram方法传输数据,readDatagram方法接收数据。QT在调用writeDatagram方法时候会自动发出readyRead信号给接收方监听。

多线程

Qt有两种多线程的方法,其中一种是继承QThread的run函数,另外一种是把一个继承于QObject的类转移到一个Thread里,即使用MoveToThread。
  Qt4.8之前都是使用继承QThread的run这种方法,但是Qt4.8之后,Qt官方建议使用第二种方法。因此本文使用的是第二种方法。
  第二种方法主要就是写一个一个继承于QObject的类,将耗时的工作写在该类的槽函数中。
然后将派生类对象移动到一个QThread中,该线程需要start。最后,通过信号连接派生类的槽函数,并通过信号触发槽函数。(槽函数在子线程中执行)。

不多说,直接上服务器代码

Qt网络通信,多线程实现UDP通信_第1张图片
先把ui界面贴一下,其中label名字叫做label_tosend,按钮名字pushbutton_start。
Qt网络通信,多线程实现UDP通信_第2张图片

以下是派生类的头文件

#ifndef TRAVEL_H
#define TRAVEL_H

#include 
#include 
#include 
#include 

class travel : public QObject
{
     
    Q_OBJECT
public:
    explicit travel(QObject *parent = nullptr);
    ~travel();

signals:
    void sig_ok();
public slots:
    void slot_do(QString msg,int port);
    //主要实现功能的函数,用于传送数据给客户端,其中两个传入参数分别是待传数据和客户端端口号
private:
    QUdpSocket *mudpsocket;
};

#endif // TRAVEL_H
接下来是traval.cpp
#include "travel.h"
#include 
#include 
travel::travel(QObject *parent) : QObject(parent)
{
     
   qDebug()<<"构造了travel";
   mudpsocket=new QUdpSocket(this);//新建一个UDP套接字
}
travel::~travel()
{
     
    qDebug()<<"析构了travel";
}

void travel::slot_do(QString msg,int port)
{
     
  //writeDatagram方法传入4个参数,分别是数据,数据大小,接收端ip,接收端端口
  //如果传输成功,该方法返回传输数据的大小(字节),如果失败返回-1
    int len=mudpsocket->writeDatagram(msg.toUtf8(),msg.length(),QHostAddress::Broadcast,port);
    if(len!=msg.length())
    {
     return;}
    qDebug()<<"开启线程"<<QThread::currentThreadId();//查看槽函数在哪个线程运行
    emit sig_ok();//发出我已经传输完毕的信号
}

然后是服务器udphost.h


```cpp
#ifndef UDPHOST_H
#define UDPHOST_H

#include 
#include "travel.h"
#include 
#include 

QT_BEGIN_NAMESPACE
namespace Ui {
      class UdpHost; }
QT_END_NAMESPACE
class UdpHost : public QWidget
{
     
    Q_OBJECT

public:
    UdpHost(QWidget *parent = nullptr);
    ~UdpHost();
signals:
    void sig_dowork(QString,int);

private slots:
    void on_pushButton_start_clicked();
public slots:
    void slot_finish();

private:
    Ui::UdpHost *ui;
    travel *traveltoclient;
    QThread *thread;
};
#endif // UDPHOST_H
还有他的CPP代码
#include "udphost.h"
#include "ui_udphost.h"
#include 
#include 

UdpHost::UdpHost(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::UdpHost)
{
     
    qDebug()<<"主线程:"<<QThread::currentThreadId();
    ui->setupUi(this);
    traveltoclient=new travel();//创建对象
    thread=new QThread();//创建线程
    traveltoclient->moveToThread(thread);//使用该方法实现多线程,这是QT推荐的
     
    connect(thread,&QThread::finished,traveltoclient,&QObject::deleteLater);
    connect(this,&UdpHost::sig_dowork,traveltoclient,&travel::slot_do);
    //用connect的方式调用do函数,否则多线程报错
    connect(traveltoclient,&travel::sig_ok,this,&UdpHost::slot_finish);
}

UdpHost::~UdpHost()
{
     
    delete ui;
    //关闭子线程
    thread->quit();
    thread->wait();
}


void UdpHost::on_pushButton_start_clicked()
{
     
    thread->start();
    QString msg=ui->label_tosend->text();
    emit sig_dowork(msg,6666);//把数据和端口号作为参数传出去
}
void UdpHost::slot_finish()
{
     
    qDebug()<<"结束"<<QThread::currentThreadId();
}

接下来是客户端的代码

Qt网络通信,多线程实现UDP通信_第3张图片
客户端的ui里就放了一个label用来显示接收到的数据,名字是label_get。
客户端的头文件代码如下:

#ifndef UDPCLIENT_H
#define UDPCLIENT_H

#include 
#include 

QT_BEGIN_NAMESPACE
namespace Ui {
      class udpClient; }
QT_END_NAMESPACE

class udpClient : public QWidget
{
     
    Q_OBJECT

public:
    udpClient(QWidget *parent = nullptr);
    ~udpClient();
public slots:
    void slot_received();//用来处理接收到的数据

private:
    Ui::udpClient *ui;
    QUdpSocket *mudpsocket;
};
#endif // UDPCLIENT_H

接下来是客户端的CPP代码:

#include "udpclient.h"
#include "ui_udpclient.h"
#include 

udpClient::udpClient(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::udpClient)
{
     
    ui->setupUi(this);
    mudpsocket=new QUdpSocket(this);
    mudpsocket->bind(6666);
    connect(mudpsocket,&QUdpSocket::readyRead,this,&udpClient::slot_received);
    //监听readRead信号
}

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

void udpClient::slot_received()
{
     
    while(mudpsocket->hasPendingDatagrams())
    {
     
        QByteArray datagram;
        //为避免数据丢失,在尝试读取之前,调用pendingDatagramSize()确定未决数据报的大小
        datagram.resize(mudpsocket->pendingDatagramSize());
        //读取数据,该方法传入四个参数,后面两个可以为空,分别是数据,数据的最大大小,地址和端口
        mudpsocket->readDatagram(datagram.data(),datagram.size());
        QString msg=datagram.data();
        ui->label_get->setText(msg);//显示收到的数据

    }
}

同时在Qt中运行服务器端和客户端,点击开始按钮,可以看到客户端收到了hello,同时在debug栏里可以看到确实有子线程存在。Qt网络通信,多线程实现UDP通信_第4张图片

你可能感兴趣的:(qt,udp,多线程,socket)