Qt 套接字类(QTcpSocket和QUdpSocket)解密:迈向 Qt 网络编程之巅

Qt 套接字类解密:迈向 Qt 网络编程之巅

  • 一、套接字类简介(Introduction to Socket Classes)#
    • 套接字类的作用(Role of Socket Classes)
    • Qt 中常见套接字类概述(Overview of Common Socket Classes in Qt)
  • 二、QTcpSocket(TCP 客户端套接字类)
    • QTcpSocket 的基本用法(Basic Usage of QTcpSocket)
    • 建立连接的示例代码(Example Code for Establishing Connection)
    • 数据读写与信号处理(Data Reading, Writing, and Signal Handling)
  • 三、QTcpServer(TCP 服务器端套接字类)
    • QTcpServer 的基本用法(Basic Usage of QTcpServer)
    • 监听连接和处理客户端请求(Listening for Connections and Handling Client Requests)
    • 创建 TCP 服务器端的示例代码(Example Code for Creating a TCP Server)
  • 四、QUdpSocket(UDP 通信套接字类)
    • QUdpSocket 的基本用法(Basic Usage of QUdpSocket)
    • UDP 通信的数据发送与接收(Data Sending and Receiving in UDP Communication)
    • 实现 UDP 通信的示例代码(Example Code for Implementing UDP Communication)
  • 五、QSslSocket(SSL/TLS 安全套接字类)
    • QSslSocket 的基本用法(Basic Usage of QSslSocket)
    • 配置 SSL/TLS 证书和密钥(Configuring SSL/TLS Certificates and Keys)
    • 实现安全套接字通信的示例代码(Example Code for Implementing Secure Socket Communication)
  • 六、套接字编程注意事项与最佳实践(Socket Programming Considerations and Best Practices)
    • 非阻塞套接字编程(Non-blocking Socket Programming)
    • 错误处理与异常情况(Error Handling and Exceptional Cases)
      • 错误枚举
      • 错误信号
    • 错误处理策略
    • 性能优化与资源管理(Performance Optimization and Resource Management)
  • 七、qt套接字类的底层原理
  • 八、Qt套接字类在不同版本之间的差异(Qt4-Qt6之间的版本)
  • 九、学习 qt 套接字类 的步骤方法
  • 十、结语

一、套接字类简介(Introduction to Socket Classes)#

套接字类的作用(Role of Socket Classes)

套接字类在网络编程中起着至关重要的作用。套接字(Socket)为基于网络的通信提供了一种机制,使得不同设备、不同操作系统上的应用程序可以互相传输数据。套接字类负责建立连接、发送和接收数据、处理错误等任务,以简化网络通信的实现。通过使用套接字类,开发人员可以专注于应用程序的逻辑功能,而无需关心底层网络协议的细节。

Qt 中常见套接字类概述(Overview of Common Socket Classes in Qt)

Qt 提供了一系列套接字类,用于处理不同类型的网络通信。以下是 Qt 中常见的套接字类:

  • QTcpSocket:用于实现 TCP 客户端连接。TCP 是一种面向连接、可靠的传输层协议,可以确保数据在网络中的正确传输。
  • QTcpServer:用于实现 TCP 服务器端。QTcpServer 可以监听客户端连接请求,为每个连接创建一个新的 QTcpSocket。
  • QUdpSocket:用于实现 UDP 通信。UDP 是一种无连接、不可靠的传输层协议,具有较低的延迟和较高的传输速率。
  • QSslSocket:用于实现 SSL/TLS 安全套接字通信。QSslSocket 在 QTcpSocket 的基础上提供了加密和身份验证功能,以保护通信数据的安全性。

本篇博客将详细介绍这些套接字类的使用方法,帮助您迈向 Qt 网络编程之巅。

二、QTcpSocket(TCP 客户端套接字类)

QTcpSocket 的基本用法(Basic Usage of QTcpSocket)

QTcpSocket 类提供了以下主要方法:

  • connectToHost():连接到指定的主机和端口。
  • disconnectFromHost():断开与主机的连接。
  • write():向套接字写入数据。
  • read()readAll():从套接字读取数据。
  • waitForConnected()waitForReadyRead()waitForBytesWritten():等待特定事件发生。

此外,QTcpSocket 类还提供了一些重要信号,如:

  • connected():套接字成功连接到主机时发出。
  • disconnected():与主机的连接断开时发出。
  • readyRead():套接字有数据可读时发出。
  • bytesWritten():数据被成功写入套接字时发出。
  • errorOccurred():发生错误时发出。

建立连接的示例代码(Example Code for Establishing Connection)

#include 

QTcpSocket *socket = new QTcpSocket(this);
socket->connectToHost("example.com", 80);
if (socket->waitForConnected(3000)) {
    qDebug() << "Connected!";
} else {
    qDebug() << "Connection failed!";
}

数据读写与信号处理(Data Reading, Writing, and Signal Handling)

// 写入数据
QByteArray data = "Hello, world!";
socket->write(data);

// 读取数据
connect(socket, &QTcpSocket::readyRead, [socket]() {
    QByteArray receivedData = socket->readAll();
    qDebug() << "Received data:" << receivedData;
});

// 处理错误
connect(socket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::errorOccurred), [socket](QAbstractSocket::SocketError socketError) {
    qDebug() << "Error occurred:" << socketError;
});

// 处理连接断开
connect(socket, &QTcpSocket::disconnected, [socket]() {
    qDebug() << "Disconnected!";
});

通过学习上述示例代码,您将能够使用 QTcpSocket 类实现 TCP 客户端的基本功能。

三、QTcpServer(TCP 服务器端套接字类)

QTcpServer 的基本用法(Basic Usage of QTcpServer)

QTcpServer 类用于实现 TCP 服务器端,它可以监听客户端连接请求并为每个连接创建一个新的 QTcpSocket。QTcpServer 类提供了以下主要方法:

  • listen():开始监听指定地址和端口的连接请求。
  • close():停止监听连接请求。
  • hasPendingConnections():检查是否有等待处理的连接请求。
  • nextPendingConnection():获取下一个待处理的连接请求并返回一个 QTcpSocket 实例。

此外,QTcpServer 类还提供了一些重要信号,如:

  • newConnection():当有新的连接请求到达时发出。

监听连接和处理客户端请求(Listening for Connections and Handling Client Requests)

使用 QTcpServer,可以轻松地创建一个 TCP 服务器端来监听客户端连接请求。当客户端连接到服务器时,QTcpServer 会发出 newConnection() 信号。您可以在槽函数中处理这个信号,并通过调用 nextPendingConnection() 获取新连接的 QTcpSocket 实例。

创建 TCP 服务器端的示例代码(Example Code for Creating a TCP Server)

#include 
#include 

// 创建 QTcpServer 实例
QTcpServer *tcpServer = new QTcpServer(this);

// 开始监听连接请求
if (!tcpServer->listen(QHostAddress::Any, 1234)) {
    qDebug() << "Failed to start listening!";
    return;
}

// 处理新连接
connect(tcpServer, &QTcpServer::newConnection, [tcpServer]() {
    QTcpSocket *clientSocket = tcpServer->nextPendingConnection();

    qDebug() << "New connection from" << clientSocket->peerAddress().toString();

    // 处理客户端数据和连接断开
    connect(clientSocket, &QTcpSocket::readyRead, [clientSocket]() {
        QByteArray receivedData = clientSocket->readAll();
        qDebug() << "Received data:" << receivedData;
    });
    connect(clientSocket, &QTcpSocket::disconnected, [clientSocket]() {
        qDebug() << "Client disconnected!";
        clientSocket->deleteLater();
    });
});

通过学习上述示例代码,您将能够使用 QTcpServer 类实现基本的 TCP 服务器端功能。

四、QUdpSocket(UDP 通信套接字类)

QUdpSocket 的基本用法(Basic Usage of QUdpSocket)

QUdpSocket 类用于实现 UDP 通信。与 TCP 通信不同,UDP 是一种无连接、不可靠的传输层协议,具有较低的延迟和较高的传输速率。QUdpSocket 提供了以下主要方法:

  • bind():将套接字绑定到指定的地址和端口,以接收数据。
  • writeDatagram():向指定的地址和端口发送数据。
  • readDatagram():从套接字中读取数据以及数据来源的地址和端口。

此外,QUdpSocket 类还提供了一些重要信号,如:

  • readyRead():当有数据可读时发出。

UDP 通信的数据发送与接收(Data Sending and Receiving in UDP Communication)

使用 QUdpSocket,您可以轻松地实现 UDP 通信。发送数据时,您需要调用 writeDatagram() 并指定目标地址和端口。接收数据时,您需要先调用 bind() 绑定套接字,然后在 readyRead() 信号的槽函数中调用 readDatagram() 读取数据。

实现 UDP 通信的示例代码(Example Code for Implementing UDP Communication)

#include 

// 创建并绑定 UDP 套接字
QUdpSocket *udpSocket = new QUdpSocket(this);
udpSocket->bind(QHostAddress::Any, 1234);

// 发送数据
QByteArray data = "Hello, world!";
QHostAddress destAddress = QHostAddress("192.168.1.100");
quint16 destPort = 5678;
udpSocket->writeDatagram(data, destAddress, destPort);

// 接收数据
connect(udpSocket, &QUdpSocket::readyRead, [udpSocket]() {
    QByteArray receivedData;
    QHostAddress senderAddress;
    quint16 senderPort;

    while (udpSocket->hasPendingDatagrams()) {
        receivedData.resize(udpSocket->pendingDatagramSize());
        udpSocket->readDatagram(receivedData.data(), receivedData.size(), &senderAddress, &senderPort);
        qDebug() << "Received data:" << receivedData << "from" << senderAddress.toString() << senderPort;
    }
});

通过学习上述示例代码,您将能够使用 QUdpSocket 类实现基本的 UDP 通信功能。

五、QSslSocket(SSL/TLS 安全套接字类)

QSslSocket 的基本用法(Basic Usage of QSslSocket)

QSslSocket 类用于实现 SSL/TLS 安全套接字通信。它继承自 QTcpSocket,因此具有相同的接口,但增加了对 SSL/TLS 加密和证书验证的支持。QSslSocket 类提供了以下主要方法:

  • setLocalCertificate():设置服务器端的本地证书。
  • setPrivateKey():设置服务器端的私钥。
  • setCaCertificates():设置客户端用于验证服务器证书的根证书。
  • startServerEncryption():开始服务器端的 SSL/TLS 握手。
  • startClientEncryption():开始客户端的 SSL/TLS 握手。

此外,QSslSocket 类还提供了一些重要信号,如:

  • encrypted():当 SSL/TLS 握手完成且连接已加密时发出。
  • sslErrors():当发生 SSL 错误时发出。

配置 SSL/TLS 证书和密钥(Configuring SSL/TLS Certificates and Keys)

在使用 QSslSocket 进行安全通信之前,您需要配置 SSL/TLS 证书和密钥。通常,服务器端需要设置本地证书和私钥,客户端需要设置根证书。

您可以使用 OpenSSL 工具生成证书和密钥,或从认证机构获取它们。

实现安全套接字通信的示例代码(Example Code for Implementing Secure Socket Communication)

#include 
#include 
#include 

// 创建 QSslSocket 实例
QSslSocket *sslSocket = new QSslSocket(this);

// 配置 SSL/TLS 证书和密钥(服务器端示例)
QFile certFile(":/certs/server.crt");
QFile keyFile(":/certs/server.key");
certFile.open(QIODevice::ReadOnly);
keyFile.open(QIODevice::ReadOnly);
QSslCertificate certificate(&certFile, QSsl::Pem);
QSslKey privateKey(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
sslSocket->setLocalCertificate(certificate);
sslSocket->setPrivateKey(privateKey);

// 配置根证书(客户端示例)
QFile caFile(":/certs/ca.crt");
caFile.open(QIODevice::ReadOnly);
QSslCertificate caCertificate(&caFile, QSsl::Pem);
sslSocket->setCaCertificates(QList<QSslCertificate>() << caCertificate);

// 开始 SSL/TLS 握手
sslSocket->connectToHostEncrypted("example.com", 1234);

// 处理加密和 SSL 错误
connect(sslSocket, &QSslSocket::encrypted, []() {
    qDebug() << "Connection encrypted!";
});
connect(sslSocket, &QSslSocket::sslErrors, [](const QList<QSslError> &errors) {
    qDebug() << "SSL errors occurred:";
    for (const QSslError &error : errors) {
        qDebug() << "  -" << error.errorString();
       }
   });

   // 读写数据(与 QTcpSocket 相同)
   connect(sslSocket, &QSslSocket::readyRead, [sslSocket]() {
       QByteArray receivedData = sslSocket->readAll();
       qDebug() << "Received data:" << receivedData;
   });
   QByteArray dataToSend = "Hello, world!";
   sslSocket->write(dataToSend);

通过学习上述示例代码,您将能够使用 QSslSocket 类实现基本的 SSL/TLS 安全套接字通信功能。请注意,根据您的应用程序需求,您可能需要对证书和密钥的配置进行相应的调整。

六、套接字编程注意事项与最佳实践(Socket Programming Considerations and Best Practices)

非阻塞套接字编程(Non-blocking Socket Programming)

使用 Qt 的套接字类进行网络编程时,建议采用非阻塞模式。这意味着不会因为等待网络操作(如连接、发送和接收数据)而导致应用程序界面冻结。Qt 通过信号和槽机制实现了这一功能,使得您可以在不阻塞应用程序的情况下处理网络事件。因此,请确保正确使用信号和槽来处理套接字类的网络事件。

错误处理与异常情况(Error Handling and Exceptional Cases)

在网络编程过程中,可能会遇到各种错误和异常情况。因此,建议在编写套接字相关代码时,充分考虑错误处理和异常情况。例如:

  • 检查套接字是否已连接,避免在未连接状态下发送或接收数据。
  • 使用 QAbstractSocket::errorOccurred() 信号捕获套接字错误,并进行适当处理。
  • 处理网络延迟和超时情况,避免因等待过长时间而导致应用程序失去响应。
  • 当需要读取或发送大量数据时,考虑分块传输以避免内存问题。

为了帮助我们识别和处理这些错误,Qt 提供了一些错误处理机制。

错误枚举

Qt 的套接字类(如 QTcpSocket、QUdpSocket 和 QSslSocket)都继承自 QAbstractSocket 类。QAbstractSocket 类定义了一个错误枚举(QAbstractSocket::SocketError),用于表示可能出现的错误类型。一些常见的错误类型包括:

  • QAbstractSocket::ConnectionRefusedError:连接被拒绝
  • QAbstractSocket::RemoteHostClosedError:远程主机关闭了连接
  • QAbstractSocket::HostNotFoundError:找不到主机
  • QAbstractSocket::SocketTimeoutError:套接字操作超时
  • QAbstractSocket::NetworkError:出现网络错误
  • QAbstractSocket::SslHandshakeFailedError:SSL 握手失败(仅适用于 QSslSocket)

错误信号

Qt 套接字类在出现错误时会发出 errorOccurred() 信号。我们可以将此信号与自定义的槽函数连接,以便在出现错误时采取相应的操作。

以下是一个简单的示例,展示了如何处理 QTcpSocket 的错误:

#include 
#include 
#include 

class MyTcpClient : public QObject {
    Q_OBJECT
public:
    explicit MyTcpClient(QObject *parent = nullptr) : QObject(parent) {
        socket = new QTcpSocket(this);
        connect(socket, &QTcpSocket::connected, this, &MyTcpClient::onConnected);
        connect(socket, &QTcpSocket::errorOccurred, this, &MyTcpClient::onErrorOccurred);
        socket->connectToHost("example.com", 80);
    }

private slots:
    void onConnected() {
        qDebug() << "Connected to the server.";
    }

    void onErrorOccurred(QAbstractSocket::SocketError socketError) {
        qDebug() << "Error occurred:" << socket->errorString();
    }

private:
    QTcpSocket *socket;
};

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);
    MyTcpClient client;
    return app.exec();
}

#include "main.moc"

在此示例中,我们将 QTcpSocket 的 errorOccurred() 信号连接到自定义的 onErrorOccurred() 槽函数。当出现错误时,我们输出一个包含错误描述的调试消息。

错误处理策略

在处理套接字错误时,应根据错误类型和具体情况采取适当的策略。一些常见的错误处理策略包括:

  • 对于连接被拒绝或找不到主机等错误,可能需要检查服务器地址和端口设置是否正确,或者稍后重试。
  • 对于网络错误,可以提示用户检查网络连接,并在网络恢复后重试。
  • 对于 SSL 握手失败等安全相关错误,应提醒用户可能存在安全风险,并终止连接。

性能优化与资源管理(Performance Optimization and Resource Management)

网络编程时,需要关注性能优化和资源管理。以下是一些有助于提高性能和管理资源的建议:

  • 使用缓冲区减少频繁的磁盘访问。例如,可以使用 QBufferQByteArray 将数据暂存在内存中,然后一次性写入磁盘。
  • 在合适的时机关闭套接字,以释放网络资源。例如,当与客户端的交互结束时,服务器端应关闭连接。
  • 使用线程池处理大量的并发连接,避免为每个连接创建一个新线程。这可以通过 QThreadPool 类实现。
  • 在可能的情况下,使用数据压缩以减少网络传输时间和带宽消耗。

遵循这些注意事项和最佳实践,将有助于您编写更高效、健壮和可维护的套接字编程代码。

七、qt套接字类的底层原理

Qt 套接字类为网络编程提供了跨平台的高层抽象,实际上是对操作系统提供的底层套接字系统调用的封装。了解 Qt 套接字类是如何与操作系统层面的套接字系统调用进行交互的,将有助于我们更好地理解网络编程的底层原理。

  1. 套接字创建

    在底层,套接字是操作系统提供的一种通信资源。当我们创建一个 Qt 套接字对象(如 QTcpSocket、QUdpSocket)时,实际上 Qt 会调用操作系统的 socket() 系统调用来创建一个新的套接字。

  2. 套接字类型和协议

    Qt 套接字类封装了 TCP 和 UDP 协议。在底层,这对应着创建套接字时指定的套接字类型和协议。对于 TCP,套接字类型为 SOCK_STREAM,而对于 UDP,则为 SOCK_DGRAM。在创建套接字时,Qt 会将这些参数传递给操作系统的 socket() 系统调用。

  3. 绑定和监听

    对于 QTcpServer(TCP 服务器端套接字类),需要绑定到一个端口并开始监听。在底层,这涉及到操作系统的 bind()listen() 系统调用。首先,Qt 会调用 bind() 函数将套接字与指定的 IP 地址和端口绑定;然后,调用 listen() 函数使套接字处于监听状态,以接受客户端的连接请求。

  4. 连接和接受连接

    对于 QTcpSocket(TCP 客户端套接字类),需要连接到服务器。这对应于操作系统的 connect() 系统调用。QTcpServer(TCP 服务器端套接字类)在接受客户端连接时,需要调用操作系统的 accept() 系统调用。

  5. 数据读写

    数据的读写是网络编程的核心。Qt 套接字类提供了非阻塞的数据读写方法。在底层,Qt 使用操作系统的 send()recv()(对于 TCP)或 sendto()recvfrom()(对于 UDP)系统调用进行数据传输。Qt 的信号和槽机制使得我们可以在不阻塞应用程序的情况下处理数据读写事件。

  6. 关闭套接字

    在通信结束时,应关闭套接字以释放网络资源。Qt 套接字类的析构函数会负责这一工作。在底层,这对应着操作系统的 close() 系统调用。

八、Qt套接字类在不同版本之间的差异(Qt4-Qt6之间的版本)

从 Qt4 到 Qt6,Qt 的网络模块已经发生了一些变化。以下概述了 Qt4、Qt5 和 Qt6 之间的主要差异:

  1. Qt4 到 Qt5 的变化
    • QSsl(Qt Secure Socket Layer)模块在 Qt5 中得到了改进。Qt5 中引入了新的 QSslSocket::sslLibraryBuildVersionString() 和 QSslSocket::sslLibraryBuildVersionNumber() 函数,用于获取构建时 SSL 库的版本信息。
    • Qt5 中移除了对 IPv6 作用域 ID 的支持,因为这个特性在实际应用中用得较少。
    • Qt5 优化了 QUdpSocket 对 IPv6 的支持。在 Qt5 中,QUdpSocket 可以同时监听 IPv4 和 IPv6 地址。
  2. Qt5 到 Qt6 的变化
    • Qt6 中移除了对 QSslCipher 和 QSslKey 的支持。这些类在 Qt5 中已经被标记为过时,因为它们与现代密码学标准不兼容。
    • Qt6 中引入了 QNetworkInformation 类,用于获取网络接口的信息。这个新类取代了在 Qt5 中已过时的 QNetworkInterface::interfaceFromXXX 系列函数。
    • Qt6 中移除了 QHostInfo 类的一些过时方法,如 QHostInfo::localHostName()。取而代之的是使用 QNetworkInformation::hostName() 函数。
    • Qt6 中对 QSslSocket 类进行了一些 API 调整。例如,QSslSocket::setLocalCertificate() 和 QSslSocket::setPrivateKey() 方法的参数类型从 QString 更改为 QSslCertificate 和 QSslKey。

总之,从 Qt4 到 Qt6,Qt 的网络模块在不断发展和改进。虽然有一些 API 变化,但基本的套接字编程概念和方法仍然保持一致。在迁移到新版本时,需要关注相关的 API 变动,以确保代码的兼容性和稳定性。

九、学习 qt 套接字类 的步骤方法

学习 Qt 套接字类的步骤方法:

  1. 学习基本的网络编程概念

    在开始学习 Qt 套接字类之前,首先要了解基本的网络编程概念,如 IP 地址、端口号、TCP 和 UDP 协议等。这将帮助你更好地理解 Qt 套接字类的功能和用途。

  2. 熟悉 Qt 套接字类及其 API

    了解 Qt 提供的各种套接字类,如 QTcpSocket、QTcpServer、QUdpSocket 和 QSslSocket。阅读官方文档,了解这些类的功能、属性、方法和信号。

  3. 学习套接字类的基本用法

    通过阅读教程和示例代码,学习如何使用 Qt 套接字类进行基本的网络编程。例如,学习如何使用 QTcpSocket 和 QTcpServer 实现一个简单的 TCP 客户端/服务器应用,或使用 QUdpSocket 实现 UDP 通信。

  4. 掌握错误处理和异常情况

    了解 Qt 套接字类可能出现的错误和异常情况,学习如何使用信号和槽处理这些错误。同时,要注意资源管理和性能优化,确保网络应用的稳定性和效率。

  5. 学习高级主题和特性

    在掌握基本用法后,可以学习一些高级主题和特性,如非阻塞套接字编程、多线程网络编程、SSL/TLS 安全通信等。

  6. 实践和实验

    通过实际项目和练习来巩固学习成果。尝试编写不同类型的网络应用,例如聊天程序、文件传输工具或网络爬虫。在实践中遇到问题时,可以查阅文档、教程和社区资源寻求解决方案。

  7. 关注 Qt 版本更新和新特性

    随着 Qt 版本的更新,套接字类可能会有一些变化和新特性。关注 Qt 的版本更新,了解新版本中的改进和新增功能,以便在需要时升级或优化网络应用。

十、结语

在本博客中,我们深入探讨了 Qt 套接字类及其在网络编程中的应用。从心理学的角度来看,学习和掌握这些知识对于开发者具有以下积极影响:

  1. 增强自信心:通过学习 Qt 套接字类及其相关概念,开发者将更加熟练地运用这些知识解决实际问题。这将增强他们在网络编程领域的自信心,从而提高工作效率和创新能力。
  2. 增进团队协作:掌握 Qt 套接字类的使用方法和最佳实践,有助于开发者在团队项目中更好地协作。良好的团队协作将提高项目成功率和团队成员的工作满意度。
  3. 提高学习动力:深入了解 Qt 套接字类及其底层原理,可以激发开发者对网络编程的兴趣和好奇心。这将有助于他们保持持续学习的动力,不断扩展知识领域和技能水平。
  4. 培养解决问题的能力:在学习过程中,开发者需要面对各种问题和挑战。通过实际操作和实践,他们将逐渐培养出解决问题的能力和应对复杂场景的策略。这些能力对于个人职业发展和生活中的问题解决都具有积极意义。
  5. 降低焦虑和压力:掌握 Qt 套接字类及其应用,可以帮助开发者在面对网络编程问题时更加从容和自信。这将降低他们在工作中的焦虑和压力,从而提高生活质量和工作幸福感。

总之,通过学习和实践 Qt 套接字类,开发者将在心理层面获得更多积极的影响。这些影响将有助于他们在职业生涯和个人生活中取得更好的成果。

你可能感兴趣的:(Qt应用开发,-,探索Qt的魅力与实践,c++,qt,开发语言,设计模式,c语言)