【Qt初入江湖】Qt QUdpSocket 底层架构、原理详细描述

鱼弦:CSDN内容合伙人、CSDN新星导师、51CTO(Top红人+专家博主) 、github开源爱好者(go-zero源码二次开发、游戏后端架构 https://github.com/Peakchen)

Qt QUdpSocket是一个用于实现UDP协议的客户端和服务器端的类,它可以发送和接收数据报(Datagram),提供了丰富的方法和信号来发送和接收数据。QUdpSocket的底层架构由以下几个部分组成:

  1. QUdpSocketPrivate

QUdpSocketPrivate是QUdpSocket的私有类,它负责QUdpSocket的底层实现。QUdpSocketPrivate包含了一个QAbstractSocketEngine类型的成员变量,用于管理底层的套接字通信。在QUdpSocket的构造函数中,会创建一个QUdpSocketPrivate对象,并将其作为QUdpSocket的私有数据。

  1. QAbstractSocketEngine

QAbstractSocketEngine是一个抽象类,它定义了QUdpSocket底层套接字通信的接口。具体的套接字通信实现由各个平台的QAbstractSocketEngine子类来实现。在QUdpSocketPrivate中,会创建一个具体的QAbstractSocketEngine子类对象,用于实现QUdpSocket的底层套接字通信。

  1. QSocketNotifier

QSocketNotifier是一个Qt中用于通知文件描述符状态变化的类,它可以监视文件描述符的读写状态,并在状态发生变化时发送信号通知应用程序。在QUdpSocketPrivate中,会使用QSocketNotifier来监听底层套接字通信的读写状态,并在状态发生变化时发送信号通知QUdpSocket。

下面是 QUdpSocket 的基本实现架构图:

+-------------------+
|      QUdpSocket    |
+-------------------+
| - socketDescriptor|
+-------------------+
          /_\
           |
           | 继承
           |
+-------------------+
|      QAbstractSocket |
+-------------------+
| - socketState     |
| - socketError     |
| - readBuffer      |
| - writeBuffer     |
| - readNotifier    |
| - writeNotifier   |
| - exceptionNotifier|
+-------------------+
          /_\
           |
           | 继承
           |
+-------------------+
|       QObject     |
+-------------------+

可以看出,QUdpSocket 继承自 QAbstractSocket 和 QObject 两个类,其中 QAbstractSocket 提供了基本的套接字操作(如连接、断开连接、发送数据等),而 QObject 则提供了对象的基本功能(如信号和槽、对象名称等)。

在 QUdpSocket 类中,socketDescriptor 属性表示底层使用的套接字描述符,它是一个整数值。QUdpSocket 的构造函数中会通过 socket() 函数创建一个新的套接字,并将其与 socketDescriptor 属性关联起来。QUdpSocket 的 bind() 函数会调用底层的 bind() 函数来将套接字绑定到指定的本地地址和端口上。

QUdpSocket 通过 readNotifier 和 writeNotifier 成员变量来监听套接字的可读和可写事件,当套接字有数据可读或可以写入数据时,就会触发相应的信号(如 readyRead 和 bytesWritten 信号)来通知应用程序。当套接字出现错误时,socketError 信号会被触发,应用程序可以通过该信号来处理错误。

在QUdpSocket中,我们可以使用以下方法来实现UDP客户端和服务器端的通信:

  1. bind()

bind()方法用于将QUdpSocket绑定到指定的IP地址和端口号,使其能够接收来自该IP地址和端口号的数据报。它接受一个QHostAddress类型的参数,表示要绑定的IP地址,以及一个整数参数,表示要绑定的端口号。例如:

QUdpSocket socket;
socket.bind(QHostAddress::Any, 1234);
  1. writeDatagram()

writeDatagram()方法用于向指定的IP地址和端口号发送数据报。它接受一个字节数组作为参数,表示要发送的数据,以及一个QHostAddress类型的参数,表示要发送到的IP地址,以及一个整数参数,表示要发送到的端口号。例如:

QUdpSocket socket;
QByteArray data("Hello, world!");
socket.writeDatagram(data, QHostAddress::Broadcast, 1234);
  1. readDatagram()

readDatagram()方法用于从QUdpSocket接收数据报。它接受两个引用参数,一个是QByteArray类型的引用,表示接收到的数据,另一个是QHostAddress类型的引用,表示发送方的IP地址,以及一个整数引用,表示发送方的端口号。例如:

QUdpSocket socket;
QByteArray buffer;
QHostAddress sender;
quint16 senderPort;
socket.readDatagram(buffer.data(), buffer.size(), &sender, &senderPort);
  1. close()

close()方法用于关闭套接字,它不接受任何参数。例如:

QUdpSocket socket;
socket.close();
  1. error()

error()方法用于获取套接字的错误代码,它返回一个QAbstractSocket::SocketError枚举类型的值。例如:

QUdpSocket socket;
socket.bind(QHostAddress::Any, 1234);
if (socket.waitForReadyRead(5000)) {
    QByteArray buffer;
    QHostAddress sender;
    quint16 senderPort;
    socket.readDatagram(buffer.data(), buffer.size(), &sender, &senderPort);
    qDebug() << "Received datagram from" << sender.toString() << ":" << senderPort;
} else {
    qDebug() << "Error:" << socket.error();
}

以上是QUdpSocket类的主要方法,除此之外还有许多其他方法和信号,可以根据实际需求来使用。下面是一个简单的示例代码,演示了如何使用QUdpSocket实现UDP客户端和服务器端的通信。

UDP服务器端代码:

#include <QtCore>
#include <QtNetwork>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QUdpSocket socket;
    socket.bind(QHostAddress::Any, 1234);

    QObject::connect(&socket, &QUdpSocket::readyRead, [&socket](){
        QByteArray buffer;
        buffer.resize(socket.pendingDatagramSize());

        QHostAddress sender;
        quint16 senderPort;

        socket.readDatagram(buffer.data(), buffer.size(), &sender, &senderPort);

        qDebug() << "Received datagram from" << sender.toString() << ":" << senderPort;
        qDebug() << "Data:" << buffer;
    });

    return app.exec();
}

UDP客户端代码:

#include <QtCore>
#include <QtNetwork>

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    QUdpSocket socket;

    QByteArray data("Hello, world!");
    socket.writeDatagram(data, QHostAddress::LocalHost, 1234);

    return app.exec();
}

在上面的示例中,UDP服务器端使用bind()方法将QUdpSocket绑定到本地IP地址和端口号1234,然后使用readyRead()信号监听数据的到达。当有数据到达时,会使用readDatagram()方法接收数据,并输出发送方的IP地址和端口号,以及接收到的数据。

UDP客户端使用writeDatagram()方法向本地IP地址发送数据报,目标端口号为1234。

UDP是一种无连接的协议,因此在使用QUdpSocket发送和接收数据时,不需要建立连接。每次发送和接收数据都是独立的操作,不会受到之前或之后的数据的影响。

猜你喜欢

转载自blog.csdn.net/feng1790291543/article/details/131806963