跨平台应用开发框架(4)----Qt(系统篇)

发布于:2024-12-06 ⋅ 阅读:(31) ⋅ 点赞:(0)

目录

1.Qt事件

1.事件来源

2.事件处理

3.按键事件

1.组合按键

4.鼠标事件

1.鼠标单击事件

2.鼠标释放事件

3.鼠标双击事件

4.鼠标移动事件

5.滚轮事件

5.定时器

1.QTimerEvent类

2.QTimer 类

3.获取系统日期及时间

6.事件分发器

7.事件过滤器

2.Qt文件

1.输入输出设备类

2.文件读写类

3.文件和目录信息类

3.Qt多线程

1.QThread常用API

2.使用线程

 ​编辑

3.线程安全

1.互斥锁

1.QMutex

2. QMutexLocker

3.QReadWriteLocker、QReadLocker、QWriteLocker

2.条件变量

3.信号量

4.Qt网络

1.UDP Socket

1.QUdpSocket

2.QNetworkDatagram 

3.回显服务器

 

4.回显客户端

2.TCP Socket

1.QTcpSocket

2.QTcpServer

3.HTTP Client

1.QNetworkAccessManager

2. QNetworkRequest

 3.QNetworkReply

5.Qt音视频

1.Qt音频

2.Qt视频


1.Qt事件

        在 Qt 中,事件(Event)是对象之间进行通信的一种方式。当用户与应用程序进行交互(如点击鼠标、按下键盘按键)或者系统发生某些状况(如定时器触发、窗口大小改变)时,Qt 会生成相应的事件,并将这些事件发送到相关的对象进行处理。

1.事件来源

  • 用户操作:例如用户在窗口中移动鼠标、点击按钮等操作都会产生事件。当用户点击一个按钮时,Qt 会产生一个鼠标点击事件(QMouseEvent)并发送给按钮对象。
  • 系统触发:像定时器超时(QTimerEvent),当一个QTimer对象的定时时间到达后,会产生定时器事件;还有窗口大小改变事件(QResizeEvent),当用户调整窗口大小或者程序中通过代码改变窗口大小时会触发。

2.事件处理

  • 重写事件处理函数:在 Qt 中,大多数部件类都提供了一系列的事件处理函数,如mousePressEvent(用于处理鼠标按下事件),keyPressEvent(用于处理键盘按键按下事件)等。开发人员可以通过在自定义部件类中重写这些事件处理函数来定义自己的事件处理逻辑。
void MyLabel::mousePressEvent(QMouseEvent *ev)
{
    QString str1=QString("鼠标按下了x=%1,y=%2").arg(ev->x()).arg(ev->y());
    qDebug()<<str1;
}

3.按键事件

        在 Qt 中,按键事件(Key Event)主要用于处理用户通过键盘与应用程序进行交互的情况。当用户按下或释放键盘上的一个键时,Qt 会生成相应的按键事件。这些事件能够让开发者精确地控制应用程序在用户进行键盘操作时的行为。

void Widget::keyPressEvent(QKeyEvent *event)
{
    if(event->key()==Qt::Key_A)
    {
        qDebug()<<"A按键被按下";
    }
}

1.组合按键

        在 Qt 中,组合按键是指同时按下多个按键来触发特定的操作。常见的组合按键包括 “Ctrl + C”(复制)、“Ctrl + V”(粘贴)等。这些组合按键通常涉及一个或多个修饰键(如 Ctrl、Shift、Alt)与其他普通按键一起使用。

void Widget::keyPressEvent(QKeyEvent *event)
{
    if(event->modifiers()==Qt::ControlModifier)
    {
        if(event->key()==Qt::Key_A)
        {
            qDebug()<<"Ctrl+A按键被按下";
        }
    }
}

4.鼠标事件

        在 Qt 中,鼠标事件(MouseEvent)用于处理用户与应用程序通过鼠标进行的交互。当用户移动鼠标、按下或释放鼠标按键、双击鼠标等操作时,Qt 会生成相应的鼠标事件。这些事件能够让开发者精确地控制应用程序在用户进行鼠标操作时的行为。

1.鼠标单击事件

void Widget::mousePressEvent(QMouseEvent *event)
{
    if(event->button()==Qt::LeftButton)
    {
        qDebug()<<"鼠标左键被按下";
    }
}

2.鼠标释放事件

        鼠标释放事件(mouseReleaseEvent)是QMouseEvent中的一种重要事件类型。它在用户松开鼠标按键时被触发。这个事件对于许多操作至关重要,例如完成一次拖放操作后、结束一个按钮的点击动作等。

void Widget::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button()==Qt::LeftButton)
    {
        qDebug()<<"鼠标左键被释放";
    }
}

3.鼠标双击事件

        鼠标双击事件(mouseDoubleClickEvent)是 Qt 中用于处理用户双击鼠标按键操作的事件。它在用户快速连续两次按下并释放同一鼠标按键时触发。这种事件在很多图形用户界面应用中非常有用,例如在文件管理器中,双击文件图标可以打开文件;在文本编辑器中,双击单词可以选中该单词等。

void Widget::mouseDoubleClickEvent(QMouseEvent *event)
{
    if(event->button()==Qt::LeftButton)
    {
        qDebug()<<"鼠标左键被双击";
    }
}

4.鼠标移动事件

        鼠标移动事件(mouseMoveEvent)是 Qt 中用于处理鼠标在部件上移动这一操作的事件。当用户移动鼠标时,只要鼠标光标位于应用程序的相关部件范围内,就会触发该事件。这个事件对于实现诸如鼠标跟踪、拖放操作以及动态绘图等功能非常关键。

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

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

void Widget::mouseMoveEvent(QMouseEvent *event)
{
    qDebug()<<"["<<event->x()<<","<<event->y()<<"]";
}

5.滚轮事件

        在 Qt 中,滚轮事件(QWheelEvent)用于处理鼠标滚轮的操作。当用户滚动鼠标滚轮时,Qt 会生成相应的滚轮事件。这种事件主要用于实现诸如缩放图像、滚动文档内容等功能。

void Widget::wheelEvent(QWheelEvent *event)
{
    static int x=0;
    x+=event->angleDelta().y();
    if(event->angleDelta().y()>0)
    {
        qDebug()<<"滚轮往前"<<x;
    }
    else
    {
        qDebug()<<"滚轮往后"<<x;
    }
}

5.定时器

        在 Qt 中,定时器(Timer)是一种用于在特定时间间隔后触发事件的机制。它允许你在应用程序中实现周期性的任务或者延迟执行某些操作。例如,你可以使用定时器来定期更新用户界面的显示内容、实现动画效果或者检查某些条件是否满足。

1.QTimerEvent类

        QTimerEvent 是 Qt 中用于处理定时器事件的类。当使用startTimer()函数启动一个定时器时,Qt 会在定时器超时时生成一个 QTimerEvent 对象,并将其发送到对应的对象中进行处理。这个类提供了关于定时器事件的基本信息,比如定时器的唯一标识符(timerId),通过这个标识符可以区分不同的定时器事件。

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    timer_id1=startTimer(1000);
    timer_id2=startTimer(2000);
}

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

void Widget::timerEvent(QTimerEvent *event)
{
    if(event->timerId()==timer_id1)
    {
        static int num1=1;
        ui->label->setText(QString::number(num1++));
    }
    if(event->timerId()==timer_id2)
    {
        static int num2=1;
        ui->label_2->setText(QString::number(num2++));
    }
}

2.QTimer 类

        QTimer 是 Qt 提供的一个用于实现定时器功能的高级类。它使得在应用程序中处理定时任务变得更加方便和直观。通过使用 QTimer,你可以轻松地设置定时周期,并且在定时器超时后执行相应的操作,这主要是通过信号和槽机制来实现的。

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QTimer *time=new QTimer(this);
    connect(ui->pushButton,&QPushButton::clicked,[=](){
        time->start(1000);
    });
    connect(time,&QTimer::timeout,[=](){
        static int num=1;
        ui->label->setText(QString::number(num++));
    });
    connect(ui->pushButton_2,&QPushButton::clicked,[=](){
        time->stop();
    });
}

3.获取系统日期及时间

        获取当前日期和时间:在 Qt 中,可以使用QDateTime类来获取系统日期和时间。QDateTime类提供了方便的函数来处理日期和时间相关的操作。

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QTimer *time=new QTimer(this);
    connect(ui->pushButton,&QPushButton::clicked,[=](){
        time->start(1000);
    });
    connect(ui->pushButton_2,&QPushButton::clicked,[=](){
        time->stop();
    });
    connect(time,&QTimer::timeout,this,&Widget::TimeUpDate);
}

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

void Widget::TimeUpDate()
{
    QString str=QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
    ui->label->setText(str);
}

6.事件分发器

        在 Qt 中,事件分发器(Event Dispatcher)是一个关键的机制,用于接收系统生成的各种事件(如鼠标事件、键盘事件、定时器事件等),并将这些事件分发给适当的对象进行处理。它就像是一个交通枢纽,把事件这个 “包裹” 按照一定的规则和路线发送到对应的 “目的地”(即应用程序中的各个部件)。

void Widget::mousePressEvent(QMouseEvent *ev)
{
    if(ev->button()==Qt::LeftButton)
    {
        qDebug()<<"鼠标左键被按下";
    }
}

bool Widget::event(QEvent *event)
{
    if(event->type()==QEvent::MouseButtonPress)
    {
        qDebug()<<"Event中鼠标被按下";
        return true;
    }
    return QWidget::event(event);
}

7.事件过滤器

        在 Qt 中,事件过滤器(Event Filter)是一种强大的机制,用于在事件到达目标对象之前拦截和处理事件。它提供了一种方式,可以让一个对象监控和处理另一个对象(或多个对象)的事件,就像是在事件传递的 “管道” 中安装了一个过滤器,能够对通过的事件进行检查和修改。

void myLabel::mousePressEvent(QMouseEvent *event)
{
    QString str=QString("鼠标按下:x=%1,y=%2").arg(event->x()).arg(event->y());
    qDebug()<<str.toUtf8().data();
}

bool myLabel::event(QEvent *e)
{
    if(e->type()==QEvent::MouseButtonPress)
    {
        QMouseEvent *event=static_cast<QMouseEvent *>(e);
        QString str=QString("Event函数中鼠标按下:x=%1,y=%2").arg(event->x()).arg(event->y());
        qDebug()<<str.toUtf8().data();
        return true;
    }
    return QLabel::event(e);
}
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    ui->label->installEventFilter(this);
}

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

bool Widget::eventFilter(QObject *obj, QEvent *e)
{
    if(obj==ui->label)
    {
        if(e->type()==QEvent::MouseButtonPress)
        {
            QMouseEvent *event=static_cast<QMouseEvent *>(e);
            QString str=QString("事件过滤器中鼠标按下:x=%1,y=%2").arg(event->x()).arg(event->y());
            qDebug()<<str.toUtf8().data();
            return true;
        }
    }
    return QWidget::eventFilter(obj,e);
}

2.Qt文件

1.输入输出设备类

        QIODevice 是 Qt 中用于输入 / 输出操作的抽象基类。它为各种输入输出设备(如文件、网络套接字、串口等)提供了统一的接口,使得开发者可以以一种通用的方式来处理不同类型的 I/O 操作。通过继承 QIODevice,具体的设备类(如 QFile、QSocket、QSerialPort 等)可以实现其特定的读写功能,同时保持在高层次上接口的一致性。

2.文件读写类

        QFile 是 Qt 中用于文件操作的类,它继承自 QIODevice。这意味着它可以利用 QIODevice 提供的通用输入 / 输出接口来实现文件的读写等操作。通过 QFile,开发者可以方便地对本地文件系统中的文件进行打开、读取、写入和关闭等操作,支持文本文件和二进制文件。

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    connect(ui->pushButton,&QPushButton::clicked,[=](){
        QString path=QFileDialog::getOpenFileName(this,"打开文件","C:\\Users\\25713\\Desktop");
        ui->lineEdit->setText(path);
        QFile file(path);
        file.open(QIODevice::ReadOnly);
        QString str=file.readAll();
        ui->textEdit->setText(str);
        file.close();
    });
}

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    connect(ui->pushButton,&QPushButton::clicked,[=](){
        QString path=QFileDialog::getOpenFileName(this,"打开文件","C:\\Users\\25713\\Desktop");
        ui->lineEdit->setText(path);
        QFile file(path);
        file.open(QIODevice::Append);
        file.write("这是示例");
        file.close();
    });
}

3.文件和目录信息类

        QFileInfo 是 Qt 中用于获取文件或目录信息的类。它提供了一种方便的方式来查询文件的各种属性,如文件名、文件大小、文件权限、创建时间、最后修改时间等,以及目录的相关属性。这个类不用于文件的实际读写操作(文件读写操作主要通过 QFile 来完成),而是专注于文件系统中文件和目录的元信息获取。

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    connect(ui->pushButton,&QPushButton::clicked,[=](){
        QString path=QFileDialog::getOpenFileName(this,"打开文件","C:\\Users\\25713\\Desktop");
        QFileInfo fileinfo(path);
        qDebug()<<"文件名为:"<<fileinfo.fileName().toUtf8().data();
        qDebug() << "后缀名为:" << fileinfo.suffix().toUtf8().data();
        qDebug() << "文件大小为:" << fileinfo.size();
        qDebug() << "文件路径为:" << fileinfo.path().toUtf8().data();
        qDebug() << "是否为文件:"<< fileinfo.isFile();
        QDateTime time1=fileinfo.fileTime(QFileDevice::FileBirthTime);
        qDebug() << "创建时间为:" << time1.toString("yyyy-MM-dd hh:mm:ss").toUtf8().data();
        QDateTime time2 = fileinfo.lastModified();
        qDebug() << "最后修改时间为:"<< time2.toString("yyyy-MM-dd hh:mm:ss").toUtf8().data();
        qDebug() << "是否为目录:" << fileinfo.isDir();
    });
}

 

3.Qt多线程

        在 Qt 中,多线程(Multithreading)是一种并发编程技术,用于同时执行多个任务流,从而提高应用程序的性能和响应能力。每个线程是一个独立的执行路径,可以在多核处理器上真正并行执行,或者在单核处理器上通过时间片轮转等方式实现并发执行。这使得应用程序能够在执行耗时操作(如文件读取、网络通信、复杂计算等)的同时,保持用户界面的响应性。

1.QThread常用API

API 功能描述
start() 启动线程。调用此函数后,线程开始执行run函数中的代码逻辑。如果线程已经在运行,则不会重复启动。
run() 线程的入口点函数,需要在自定义的QThread子类中重写。这个函数包含了线程要执行的具体任务代码。
quit() 请求线程的事件循环退出。这会使得线程在执行完当前事件循环中的任务后正常结束。需要注意的是,它不会立即停止线程,而是等待合适的时机。
wait() 阻塞当前线程,直到被调用的线程(一般是this线程,即自身)完成执行。可以传入一个超时时间(以毫秒为单位)作为参数,若超过该时间线程还未结束,则函数返回。
setPriority(Priority priority) 设置线程的优先级。Priority是一个枚举类型,包括IdlePriority(最低优先级,线程仅在系统空闲时运行)、LowestPriorityLowPriorityNormalPriority(默认优先级)、HighPriorityHighestPriorityTimeCriticalPriority(最高优先级,用于对时间非常敏感的任务)。
priority() 获取线程的当前优先级,返回一个Priority枚举类型的值,表示线程当前的优先级。
isRunning() 检查线程是否正在运行。如果线程已经启动并且run函数尚未执行完毕,则返回true;否则返回false
isFinished() 检查线程是否已经结束。当线程的run函数执行完毕后,该函数返回true;如果线程还在运行,则返回false
currentThread() 这是一个静态函数,用于返回当前正在执行的线程对象的指针。在多线程编程中,可以用于确定某段代码是在哪个线程中执行的。
sleep(unsigned long secs) 这是一个静态函数,使当前线程暂停执行指定的秒数。在暂停期间,线程不占用 CPU 资源。注意,这可能会影响应用程序的响应性,因此在使用时要谨慎。
msleep(unsigned long msecs) sleep类似,但是暂停的时间单位是毫秒。可以用于在需要更精细的时间控制的场景下,让线程短暂休眠。
usleep(unsigned long usecs) 使当前线程暂停执行指定的微秒数。这是更精细的时间控制,用于需要非常短暂的线程暂停的情况。
exec() 启动线程的事件循环。通常在run函数中调用,用于处理线程相关的事件。当线程需要使用信号槽机制并且需要处理异步事件时,这个函数很有用。

2.使用线程

 

#ifndef TIMETHREAD_H
#define TIMETHREAD_H

#include <QThread>

class TimeThread : public QThread
{
    Q_OBJECT
public:
    TimeThread();
    void run();
signals:
    void sendTime(QString Time);
};

#endif // TIMETHREAD_H
#include "timethread.h"
#include <QTime>
#include <QDebug>
TimeThread::TimeThread() {}
void TimeThread::run()
{
    while(1)
    {
        QString time=QTime::currentTime().toString("hh:mm:ss");
        qDebug()<<time;
        emit sendTime(time);
        sleep(1);
    }
}
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <timethread.h>

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
private slots:
    void on_btn_clicked();
    void showTime(QString Time);
private:
    Ui::Widget *ui;
    TimeThread t;
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QDateTime>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    connect(&t,&TimeThread::sendTime,this,&Widget::showTime);
}

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

void Widget::on_btn_clicked()
{
    t.start();
}

void Widget::showTime(QString Time)
{
    ui->label->setText(Time);
}

3.线程安全

        在 Qt 中,线程安全(Thread - Safety)是指在多线程环境下,多个线程访问共享资源(如数据、对象等)时不会导致数据不一致、程序崩溃或其他不可预测的行为。当多个线程同时读写共享资源时,如果没有适当的保护机制,就可能出现问题。例如,一个线程正在读取共享数据,而另一个线程同时修改了这些数据,可能会导致读取到错误或不一致的数据。

1.互斥锁

        在 Qt 中,QMutex互斥锁)是一种用于实现线程同步的基本工具。它用于保护共享资源,确保在同一时刻只有一个线程能够访问被保护的资源。互斥锁就像是一个房间的门,一次只能允许一个人(线程)进入房间(访问共享资源),当一个线程获取了互斥锁后,其他线程如果也想获取这个互斥锁,就会被阻塞,直到持有互斥锁的线程释放它。

1.QMutex
QMutex mutex;
mutex.lock(); //上锁
//访问共享资源
//...
mutex.unlock(); //解锁
2. QMutexLocker

        QMutexLocker是 Qt 提供的一个方便的类,用于简化互斥量(QMutex)的使用。它采用了 RAII(Resource Acquisition Is Initialization)机制,确保在对象生命周期内互斥量被正确锁定,并在对象销毁时自动解锁互斥量,这样可以有效避免因忘记解锁互斥量而导致的死锁等问题。

QMutex mutex;
{
 QMutexLocker locker(&mutex); //在作⽤域内⾃动上锁
} //在作⽤域结束时⾃动解锁
3.QReadWriteLocker、QReadLocker、QWriteLocker

        QReadWriteLocker是一种用于多线程环境下对共享资源进行读写操作的同步工具。它的设计目的是在多个线程同时读取共享资源和单个线程写入共享资源时提供高效的并发控制。与互斥锁( QMutex)不同,互斥锁在任何时候都只允许一个线程访问共享资源,而读写锁允许同时有多个线程读取共享资源,但在写入时仍然是互斥的,即同一时间只允许一个线程进行写入操作。

QReadWriteLock rwLock;
//在读操作中使⽤读锁
{
 QReadLocker locker(&rwLock); //在作⽤域内⾃动上读锁
 
 //读取共享资源
 //...
 
} //在作⽤域结束时⾃动解读锁
//在写操作中使⽤写锁
{
 QWriteLocker locker(&rwLock); //在作⽤域内⾃动上写锁
 
 //修改共享资源
 //...
 
} //在作⽤域结束时⾃动解写锁

2.条件变量

        在 Qt 中,条件变量(QWaitCondtion)是一种用于线程间同步的机制。它允许一个或多个线程等待某个特定条件满足后再继续执行。条件变量通常与互斥量(如QMutex)配合使用,以实现更复杂的多线程同步模式,如生产者 - 消费者模型。

QMutex mutex;
QWaitCondition condition;
//在等待线程中
mutex.lock();
//检查条件是否满⾜,若不满⾜则等待
while (!conditionFullfilled()) 
{
 condition.wait(&mutex); //等待条件满⾜并释放锁
}
//条件满⾜后继续执⾏
//...
mutex.unlock();
//在改变条件的线程中
mutex.lock();
//改变条件
changeCondition();
condition.wakeAll(); //唤醒等待的线程
mutex.unlock();

3.信号量

        在 Qt 中,信号量(QSemaphore)是一种用于线程同步和资源管理的机制。它维护了一个内部计数器,用于控制对共享资源的访问数量。信号量就像是一个资源池的门禁系统,计数器的值代表了当前可用资源的数量,线程通过获取(acquire)和释放(release)操作来改变这个计数器的值,从而控制对资源的访问。

Semaphore semaphore(2); //同时允许两个线程访问共享资源
//在需要访问共享资源的线程中
semaphore.acquire(); //尝试获取信号量,若已满则阻塞
//访问共享资源
//...
semaphore.release(); //释放信号量

4.Qt网络

1.UDP Socket

1.QUdpSocket

方法 描述
bind() 用于将 UDP 套接字绑定到指定的地址和端口,这样套接字就可以在该端口上接收数据。例如:udpSocket.bind(QHostAddress::LocalHost, 12345);。它有多种重载形式,可以根据不同的需求指定绑定方式,如只绑定端口(使用默认地址)或者使用特定的网络接口绑定等。
writeDatagram() 用于发送 UDP 数据报。需要传入要发送的数据(QByteArray类型)、目标主机地址(QHostAddress类型)和目标端口(quint16类型)。例如:QByteArray data = "Hello, UDP"; QHostAddress address("127.0.0.1"); quint16 port = 8080; udpSocket.writeDatagram(data, address, port);。也有其他重载形式,如可以指定发送数据的字节数等。
readDatagram() 用于从套接字接收 UDP 数据报。需要传入一个QByteArray类型的缓冲区用于存储接收的数据,还可以传入变量指针来获取发送方的主机地址和端口信息。例如:QByteArray buffer; QHostAddress senderAddress; quint16 senderPort; udpSocket.readDatagram(buffer.data(), buffer.size(), &senderAddress, &senderPort);
hasPendingDatagrams() 用于检查套接字是否有等待读取的数据报。如果有数据报等待读取,则返回true,否则返回false。在readyRead信号的槽函数中,通常可以先使用这个函数来判断是否真的有数据需要读取,例如:if (udpSocket.hasPendingDatagrams()) {... }
pendingDatagramSize() 返回第一个等待读取的数据报的大小(以字节为单位)。这在分配接收缓冲区的大小时很有用,例如可以根据这个大小来确保接收缓冲区能够容纳完整的数据报,避免数据丢失。
joinMulticastGroup() 用于将 UDP 套接字加入到一个多播组中,使得套接字能够接收发往该多播组的 UDP 数据报。需要传入一个多播组的QHostAddress,例如:udpSocket.joinMulticastGroup(QHostAddress("224.0.0.1"));。这在实现多播通信(如视频流的多播发送和接收)时很有用。
leaveMulticastGroup() joinMulticastGroup相反,用于将套接字从一个多播组中移除,这样套接字就不再接收发往该多播组的数据报。
setSocketOption() 用于设置 UDP 套接字的各种选项,如设置套接字的缓冲区大小、设置是否允许广播等。例如,可以设置广播选项:udpSocket.setSocketOption(QAbstractSocket::Broadcast, true);,这样就允许套接字发送广播数据报。
socketOption() 用于获取 UDP 套接字的特定选项的值,例如获取当前的广播选项设置等。

2.QNetworkDatagram 

方法 描述
data() 返回数据报中的数据部分,即实际的有效载荷(QByteArray类型)。例如,如果收到一个QNetworkDatagram对象datagram,可以通过datagram.data()获取其中的数据内容。这对于解析和处理接收到的数据很有用,比如在一个 UDP 服务器中,接收到数据报后,可以使用这个方法获取数据并根据协议进行解析。
senderAddress() 返回数据报发送者的 IP 地址(QHostAddress类型)。这在需要知道数据来源的应用场景中很重要,比如在网络安全监控或者基于源地址的过滤等应用中,可以通过这个方法获取发送者的 IP 地址进行后续操作。
senderPort() 返回数据报发送者的端口号(quint16类型)。结合senderAddress,可以完整地确定数据报的发送源,用于建立与发送方的通信或者记录发送源信息等。
destinationAddress() 返回数据报的目标 IP 地址(QHostAddress类型)。在转发数据报或者检查数据报是否被正确路由等场景中会用到这个方法。
destinationPort() 返回数据报的目标端口号(quint16类型)。用于验证数据报是否按照预期发送到了正确的端口。
size() 返回整个数据报的大小(包括头部和数据部分,以字节为单位)。这对于统计网络流量、分配缓冲区等操作可能会有用。
isValid() 检查数据报是否有效。如果数据报的格式正确、地址和端口信息合理等,则返回true,否则返回false。在处理接收到的数据报时,先检查其有效性是一个良好的习惯,可以避免处理错误或非法的数据报导致程序异常。
setData() 用于设置数据报的数据部分。可以传入一个QByteArray类型的数据来更新数据报中的内容。这在需要修改数据报内容后再发送(如添加头部信息、修改数据等)的场景中会用到。
setSenderAddress() 用于设置数据报发送者的 IP 地址。在构建自定义的数据报(如模拟其他主机发送数据报)或者修改发送源信息(在合法的场景下)时可以使用这个方法。
setSenderPort() 用于设置数据报发送者的端口号。和setSenderAddress一起用于完整地设置数据报的发送源信息。
setDestinationAddress() 用于设置数据报的目标 IP 地址。用于指定数据报要发送到的目标主机。
setDestinationPort() 用于设置数据报的目标端口号。确保数据报能够发送到正确的目标端口。

3.回显服务器

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QUdpSocket>

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    void processRequest();
    QString process(const QString& request);
private:
    Ui::Widget *ui;
    QUdpSocket* socket;
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QUdpSocket>
#include <QMessageBox>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setWindowTitle("服务器");
    socket=new QUdpSocket(this);
    connect(socket,&QUdpSocket::readyRead,this,&Widget::processRequest);
    bool ret=socket->bind(QHostAddress::Any,9090);
    if(!ret)
    {
        QMessageBox::critical(nullptr,"服务器启动出错",socket->errorString());
        return;
    }
}

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

void Widget::processRequest()
{
    const QNetworkDatagram& requestDatagram = socket->receiveDatagram();
    QString request = requestDatagram.data();
    const QString& response = process(request);
    QNetworkDatagram responseDatagram(response.toUtf8(),
    requestDatagram.senderAddress(), requestDatagram.senderPort());
    socket->writeDatagram(responseDatagram);
    QString log = "[" + requestDatagram.senderAddress().toString() + ":" +
                  QString::number(requestDatagram.senderPort())
                  + "] req: " + request + ", resp: " + response;
    ui->listWidget->addItem(log);
}

QString Widget::process(const QString& request)
{
    return request;
}

4.回显客户端

void Widget::on_pushButton_clicked()
{
 // 1. 获取到输⼊框的内容
 const QString& text = ui->lineEdit->text();
 // 2. 构造请求数据
 QNetworkDatagram requestDatagram(text.toUtf8(), QHostAddress(SERVER_IP), 
SERVER_PORT);
 // 3. 发送请求
 socket->writeDatagram(requestDatagram);
 // 4. 消息添加到列表框中
 ui->listWidget->addItem("客⼾端说: " + text);
 // 5. 清空输⼊框
 ui->lineEdit->setText("");
}
connect(socket, &QUdpSocket::readyRead, this, [=]() {
 const QNetworkDatagram responseDatagram = socket->receiveDatagram();
 QString response = responseDatagram.data();
 ui->listWidget->addItem(QString("服务器说: ") + response);
});

2.TCP Socket

1.QTcpSocket

方法 描述
connectToHost() 用于建立与指定主机和端口的 TCP 连接。可以传入主机名(如"example.com")或 IP 地址(如"192.168.1.1")和端口号(如8080)作为参数。例如:QTcpSocket socket; socket.connectToHost("127.0.0.1", 8888);
waitForConnected() 这是一个阻塞式方法,用于等待 TCP 连接建立。可以传入一个超时时间(以毫秒为单位),如果在超时时间内成功建立连接,则返回true,否则返回false。例如:if (socket.waitForConnected(5000)) {... }
write() 用于向已连接的 TCP 服务器发送数据。接受一个QByteArray类型的数据作为参数,表示要发送的数据内容。例如:QByteArray data = "Hello, Server"; socket.write(data);
read() 从 TCP 套接字读取指定字节数的数据。需要传入一个参数,表示要读取的字节数,返回一个QByteArray类型的数据,包含读取到的内容。例如:QByteArray buffer = socket.read(1024);
readAll() 读取套接字中所有当前可用的数据,返回一个QByteArray类型的数据。例如:QByteArray allData = socket.readAll();
bytesAvailable() 返回套接字中当前可供读取的数据字节数。可以用于在readyRead信号的槽函数中,判断是否有足够的数据可供读取。例如:if (socket.bytesAvailable() > 0) {... }
disconnectFromHost() 用于关闭与 TCP 服务器的连接。可以选择立即关闭或者等待所有未发送的数据发送完成后再关闭。例如:socket.disconnectFromHost();
state() 返回套接字的当前状态,返回值是QAbstractSocket::SocketState枚举类型,包括QAbstractSocket::UnconnectedState(未连接)、QAbstractSocket::HostLookupState(正在查找主机)、QAbstractSocket::ConnectingState(正在连接)等状态。可以用于检查套接字的连接状态。例如:if (socket.state() == QAbstractSocket::ConnectedState) {... }
setSocketOption() 用于设置套接字的各种选项,如KeepAlive选项(用于保持 TCP 连接的活跃状态)等。例如:socket.setSocketOption(QAbstractSocket::KeepAlive, 1);
socketOption() 用于获取套接字已经设置的某个选项的值,与setSocketOption相对应。例如:int keepAliveOption = socket.socketOption(QAbstractSocket::KeepAlive);

2.QTcpServer

方法 描述
listen() 开始监听指定的主机地址和端口,等待客户端的连接请求。可以传入QHostAddress类型的主机地址(如QHostAddress::Any表示监听所有网络接口)和端口号作为参数。例如:QTcpServer server; server.listen(QHostAddress::Any, 8080);
isListening() 检查服务器是否正在监听客户端连接。如果服务器正在监听,则返回true,否则返回false。例如:if (server.isListening()) {... }
nextPendingConnection() 当有客户端连接请求被接受时,返回一个新的QTcpSocket对象,用于与该客户端进行通信。例如:QTcpSocket* socket = server.nextPendingConnection();
close() 关闭服务器监听,停止接受新的客户端连接。例如:server.close();
newConnection() 这是一个信号,当有新的客户端连接到服务器时发射。可以连接这个信号到一个自定义的槽函数,在槽函数中处理新的客户端连接。例如:connect(&server, &QTcpServer::newConnection, this, &MyClass::onNewConnection);
setMaxPendingConnections() 设置服务器允许的最大挂起连接数(即等待处理的客户端连接请求数量)。例如:server.setMaxPendingConnections(100);
maxPendingConnections() 获取服务器允许的最大挂起连接数。例如:int maxPending = server.maxPendingConnections();
serverAddress() 返回服务器正在监听的主机地址(QHostAddress类型)。例如:QHostAddress serverAddr = server.serverAddress();
serverPort() 返回服务器正在监听的端口号。例如:quint16 serverPort = server.serverPort();

3.HTTP Client

        在 Qt 中,QNetworkAccessManager是用于进行网络访问操作的核心类,它为 HTTP(以及其他协议)客户端提供了高层次的接口。可以使用它来发送 HTTP 请求并处理服务器返回的响应。, QNetworkRequest类用于构建请求信息,包括请求的 URL、头部信息等。QNetworkReply类则用于接收和处理服务器返回的响应数据。

1.QNetworkAccessManager

方法 / 信号 用法描述
get(QNetworkRequest request) 发送一个 HTTP GET 请求。需要传入一个QNetworkRequest对象,用于指定请求的 URL 等信息。返回一个QNetworkReply对象,用于处理服务器响应。例如:QNetworkAccessManager manager; QNetworkRequest request(QUrl("http://example.com/api/data")); QNetworkReply *reply = manager.get(request);
post(QNetworkRequest request, QByteArray data) 发送一个 HTTP POST 请求。接受一个QNetworkRequest对象和一个QByteArray类型的数据作为参数,数据是要发送到服务器的数据内容。返回QNetworkReply对象用于处理响应。例如:QByteArray postData = "param1=value1&param2=value2"; QNetworkRequest request(QUrl("http://example.com/api/submit")); QNetworkReply *reply = manager.post(request, postData);
put(QNetworkRequest request, QByteArray data) 发送 HTTP PUT 请求,用于更新服务器资源。参数和post类似,一个是请求对象,一个是要更新的数据。例如:QNetworkAccessManager manager; QNetworkRequest request(QUrl("http://example.com/api/update")); QByteArray updateData = "new_value"; QNetworkReply *reply = manager.put(request, updateData);
deleteResource(QNetworkRequest request) 发送 HTTP DELETE 请求,用于删除服务器资源。只需要传入QNetworkRequest对象,用于指定要删除资源的 URL。例如:QNetworkRequest request(QUrl("http://example.com/api/delete_item")); QNetworkAccessManager manager; manager.deleteResource(request);
finished(QNetworkReply *reply)(信号) 当一个网络请求完成(无论成功与否)时发射此信号。可以连接这个信号到一个槽函数,在槽函数中处理QNetworkReply对象,获取响应数据或错误信息。例如:connect(&manager, &QNetworkAccessManager::finished, this, &MyClass::onRequestFinished);
encrypted(QNetworkReply *reply)(信号) 当一个请求的连接被加密(例如,从 HTTP 转换到 HTTPS)时发射此信号。可以用于处理加密相关的情况,如更新安全配置等。
authenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator)(信号) 当服务器请求身份验证时发射此信号。在槽函数中可以设置QAuthenticator对象的用户名和密码来进行身份验证。例如:connect(&manager, &QNetworkAccessManager::authenticationRequired, this, &MyClass::onAuthenticationRequired);

2. QNetworkRequest

方法 用法描述
setUrl(QUrl url) 设置请求的 URL。例如:QNetworkRequest request; request.setUrl(QUrl("http://example.com/api"));
url() const 获取请求的 URL。例如:QUrl requestUrl = request.url();
setRawHeader(const QByteArray &headerName, const QByteArray &headerValue) 设置请求的原始头部信息。可以用于设置自定义头部或者一些非标准的协议头部。例如:request.setRawHeader("Custom - Header", "Value");
rawHeader(const QByteArray &headerName) const 获取指定原始头部名称的头部信息。返回一个QByteArray类型的值。例如:QByteArray customHeaderValue = request.rawHeader("Custom - Header");
setAttribute(QNetworkRequest::Attribute code, const QVariant &value) 设置请求的属性。QNetworkRequest::Attribute是一个枚举类型,包括如CacheLoadControlAttribute(控制缓存加载)、FollowRedirectsAttribute(是否跟随重定向)等属性。例如:request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
attribute(QNetworkRequest::Attribute code) const 获取请求的指定属性的值。例如:QVariant cacheAttribute = request.attribute(QNetworkRequest::CacheLoadControlAttribute);
setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value) 设置已知的请求头部信息,QNetworkRequest::KnownHeaders是一个枚举类型,包括ContentTypeHeader(内容类型头部)、UserAgentHeader(用户代理头部)等。例如:request.setHeader(QNetworkRequest::UserAgentHeader, "MyQtClient/1.0");
header(QNetworkRequest::KnownHeaders header) const 获取已知头部信息的值。例如:QVariant contentType = request.header(QNetworkRequest::ContentTypeHeader);

 3.QNetworkReply

方法 / 信号 用法描述
readAll() 读取服务器返回的全部数据,返回一个QByteArray类型的数据。例如:QByteArray responseData = reply->readAll();
bytesAvailable() 返回当前可供读取的字节数。可以用于在读取数据前判断是否有足够的数据。例如:if (reply->bytesAvailable() > 0) {... }
error() 返回一个QNetworkReply::NetworkError枚举类型的值,表示请求过程中是否出现错误。例如:if (reply->error() == QNetworkReply::NoError) {... }
errorString() 返回一个包含错误描述的字符串。当error返回非NoError时,可以使用这个方法获取详细的错误信息。例如:qDebug() << "Error: " << reply->errorString();
attribute(QNetworkRequest::Attribute code) const 获取响应的属性。和QNetworkRequestattribute方法类似,不过这里是获取响应的属性。例如:int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
header(QNetworkRequest::KnownHeaders header) const 获取响应的已知头部信息的值。例如:QVariant contentType = reply->header(QNetworkRequest::ContentTypeHeader);
rawHeader(const QByteArray &headerName) const 获取原始响应头部信息。例如:QByteArray serverHeader = reply->rawHeader("Server");
finished()(信号) 当回复接收完成时发射此信号。和QNetworkAccessManagerfinished信号相关联,不过这个信号是在QNetworkReply层面的。可以用于在接收完回复后进行最后的处理,如关闭连接等。
readyRead()(信号) 当有新的数据可供读取时发射此信号。可以连接这个信号到一个槽函数,在槽函数中及时读取新到达的数据。例如:connect(reply, &QNetworkReply::readyRead, this, &MyClass::onReadyRead);
void Widget::on_pushButton_clicked()
{
    // 1. 获取到输入框中的 URL, 构造 QUrl 对象
    QUrl url(ui->lineEdit->text());
    // 2. 构造 HTTP 请求对象
    QNetworkRequest request(url);
    // 3. 发送 GET 请求
    QNetworkReply* response = manager->get(request);
    // 4. 通过信号槽来处理响应
    connect(response, &QNetworkReply::finished, this, [=]() {
        if (response->error() == QNetworkReply::NoError) {
            // 响应正确
            QString html(response->readAll());
            ui->plainTextEdit->setPlainText(html);
            // qDebug() << html;
        } else {
            // 响应出错
            ui->plainTextEdit->setPlainText(response->errorString());
        }
        response->deleteLater();
    });
}

 

5.Qt音视频

1.Qt音频

        QSound 是 Qt 中用于简单音频播放的类。它提供了一种便捷的方式来播放没有复杂音频处理需求的音频文件,通常是一些短音效,如系统提示音、按钮点击音效等。与 QAudioOutput 等类相比,QSound 的使用更加简单直接,不需要设置复杂的音频格式等参数,但功能也相对有限。

Widget::Widget(QWidget *parent)
 : QWidget(parent)
 , ui(new Ui::Widget)
{
 ui->setupUi(this);
 //实例化对象
 QSound *sound = new QSound(":/1.wav",this);
 connect(ui->btn,&QPushButton::clicked,[=](){
 sound->play(); //播放
 });
}

2.Qt视频

        QVideoWidget是 Qt 用于显示视频内容的部件。它提供了一个可视化的区域,可以将视频帧渲染并显示出来。这个部件通常与QMediaPlayer或其他视频播放源结合使用,以实现视频播放功能。