【Qt 面试题】深入剖析QT TCP通讯流程及应用实例

简介: 【Qt 面试题】深入剖析QT TCP通讯流程及应用实例

服务端:(QTcpServer)

       ①创建QTcpServer对象

       ②监听list需要的参数是地址和端口号

       ③当有新的客户端连接成功回发送newConnect信号

       ④在newConnection信号槽函数中,调用nextPendingConnection函数获取新连接QTcpSocket对象

       ⑤连接QTcpSocket对象的readRead信号

       ⑥在readRead信号的槽函数使用read接收数据

       ⑦调用write成员函数发送数据


客户端:(QTcpSocket)

      ①创建QTcpSocket对象

      ②当对象与Server连接成功时会发送connected 信号

      ③调用成员函数connectToHost连接服务器,需要的参数是地址和端口号

      ④connected信号的槽函数开启发送数据

      ⑤使用write发送数据,read接收数据


Qt tcp服务器示例

在这个示例中,我们创建了一个名为TcpServer的类,继承自QTcpServer,重写了incomingConnection()方法来处理新的客户端连接。每个连接都会创建一个ClientHandler对象,ClientHandler继承自QRunnable,处理与客户端的通信。QThreadPool负责管理和调度这些ClientHandler对象。

#include "main.moc" 这一行是在使用Qt的moc(元对象编译器)时生成的一个包含文件。在Qt中,为了实现信号和槽、内省和动态属性等特性,需要用到Qt的元对象系统。moc的作用是在编译时解析含有Q_OBJECT宏的类,为这些类生成一个额外的C++源文件,这个文件包含了元对象信息。

在我们的示例中,TcpServer类包含了Q_OBJECT宏,所以需要使用moc处理。通常情况下,moc会生成一个名为“classname.moc”的文件。这个文件会被自动包含到构建过程中,所以我们不需要手动添加它。但在这个示例中,我们把所有代码都放在了一个文件中,所以需要显式地包含这个moc文件。如果你在一个项目中使用多个文件,你可以将类的声明和实现放在不同的文件中,并且不需要显式地包含moc文件,因为构建系统会自动处理它。

需要注意的是,如果你使用了qmake、CMake或者其他支持Qt的构建系统,它们会自动调用moc并处理这些文件,你不需要手动添加#include "main.moc"。在这个简化示例中,我们显式地包含了moc文件,但在实际项目中,你通常不需要这么做。

#include <QCoreApplication>
#include <QTcpServer>
#include <QTcpSocket>
#include <QThreadPool>
#include <QDebug>
#include <QRunnable>
 
class ClientHandler : public QRunnable
{
public:
    ClientHandler(qintptr socketDescriptor) : m_socketDescriptor(socketDescriptor) {}
 
    void run() override
    {
        QTcpSocket socket;
        if (!socket.setSocketDescriptor(m_socketDescriptor)) {
            qDebug() << "Failed to set socket descriptor.";
            return;
        }
 
        while (socket.state() == QAbstractSocket::ConnectedState) {
            if (socket.waitForReadyRead()) {
                QByteArray data = socket.readAll();
                qDebug() << "Received data:" << data;
                socket.write(data);
            }
        }
    }
 
private:
    qintptr m_socketDescriptor;
};
 
class TcpServer : public QTcpServer
{
    Q_OBJECT
public:
    TcpServer(QObject *parent = nullptr) : QTcpServer(parent) {}
 
protected:
    void incomingConnection(qintptr socketDescriptor) override
    {
        qDebug() << "New connection:" << socketDescriptor;
        auto clientHandler = new ClientHandler(socketDescriptor);
        QThreadPool::globalInstance()->start(clientHandler);
    }
};
 
int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
 
    TcpServer server;
    if (!server.listen(QHostAddress::Any, 12345)) {
        qDebug() << "Failed to start server:" << server.errorString();
        return 1;
    }
    qDebug() << "Server started on port" << server.serverPort();
 
    return app.exec();
}
 
#include "main.moc"

Qt tcp客户端示例

以下是一个简单的Qt环境下的TCP客户端示例,展示了如何使用多线程连接两个TCP服务器并进行交互。

在这个示例中,我们创建了一个名为TcpClient的类,继承自QObject。我们还创建了一个名为DataProcessor的类,同样继承自QObject。TcpClient类包含了一个QTcpSocket对象,用于连接服务器和发送/接收数据。当连接建立后,TcpClient会在一个while循环中等待服务器发送数据。每当有数据到达时,TcpClient会发出一个processData()信号,这个信号会被连接到DataProcessor类的processData()槽函数中进行处理。处理完成后,DataProcessor会发出一个sendData()信号,这个信号会被连接到TcpClient的onSendData()槽函数中,将数据发送回服务器。

在main()函数中,我们创建了两个TcpClient对象,并将它们移动到不同的线程中。每个线程都会连接一个不同的服务器,并在连接建立后发送数据。我们还创建了一个DataProcessor对象,并将它移动到另一个线程中。DataProcessor会处理收到的数据并将处理后的数据发送回TcpClient,然后TcpClient将处理后的数据发送回服务器。这个过程中,DataProcessor和TcpClient是在不同的线程中运行的,因此我们使用了信号和槽来实现跨线程通信。

需要注意的是,这个示例中的DataProcessor类只是一个简单的例子,它把收到的数据转换为大写字母并返回。在实际应用中,你可以将DataProcessor替换为一个更复杂的类,用于处理实际的业务逻辑。此外,这个示例中的TcpClient类仅支持单向通信,即只有服务器向客户端发送数据。如果你需要双向通信,你需要修改TcpClient类以便它可以接收来自服务器的数据,并在必要时发送回复。

 

#include <QCoreApplication>
#include <QThread>
#include <QTcpSocket>
#include <QDebug>
#include <QMutex>
 
class DataProcessor : public QObject
{
    Q_OBJECT
public slots:
    QByteArray processData(const QByteArray &data)
    {
        qDebug() << "Processing data:" << data;
        QByteArray processedData = data.toUpper();
        return processedData;
    }
};
 
class TcpClient : public QObject
{
    Q_OBJECT
 
public:
    TcpClient(const QString &host, int port, QObject *parent = nullptr)
        : QObject(parent), m_host(host), m_port(port), m_socket(nullptr) {}
 
public slots:
    void connectToServer()
    {
        m_socket = new QTcpSocket();
        m_socket->connectToHost(m_host, m_port);
 
        if (m_socket->waitForConnected()) {
            qDebug() << "Connected to server:" << m_host << m_port;
            sendData("Hello, server!");
 
            while (m_socket->state() == QAbstractSocket::ConnectedState) {
                if (m_socket->waitForReadyRead()) {
                    QByteArray data = m_socket->readAll();
                    qDebug() << "Received data:" << data;
 
                    QByteArray processedData = processData(data);
                    sendData(processedData);
                }
            }
        } else {
            qDebug() << "Failed to connect to server:" << m_host << m_port;
        }
 
        m_socket->deleteLater();
    }
 
signals:
    QByteArray processData(const QByteArray &data);
    void sendData(const QByteArray &data);
 
private slots:
    void onSendData(const QByteArray &data)
    {
        if (m_socket && m_socket->state() == QAbstractSocket::ConnectedState) {
            m_socket->write(data);
        }
    }
 
private:
    QString m_host;
    int m_port;
    QTcpSocket *m_socket;
};
 
int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
 
    QThread dataProcessorThread;
    DataProcessor dataProcessor;
    dataProcessor.moveToThread(&dataProcessorThread);
    dataProcessorThread.start();
 
    QThread client1Thread;
    TcpClient client1("localhost", 12345);
    client1.moveToThread(&client1Thread);
    QObject::connect(&client1, &TcpClient::processData, &dataProcessor, &DataProcessor::processData);
    QObject::connect(&client1, &TcpClient::sendData, &client1, &TcpClient::onSendData);
    QObject::connect(&client1Thread, &QThread::started, &client1, &TcpClient::connectToServer);
    client1Thread.start();
 
    QThread client2Thread;
    TcpClient client2("localhost", 12346);
    client2.moveToThread(&client2Thread);
    QObject::connect(&client2, &TcpClient::processData, &dataProcessor, &DataProcessor::processData);
    QObject::connect(&client2, &TcpClient::sendData, &client2, &TcpClient::onSendData);
    QObject::connect(&client2Thread, &QThread::started, &client2, &TcpClient::connectToServer);
    client2Thread.start();
 
    QObject::connect(&app, &QCoreApplication::aboutToQuit, [&](){
    client1Thread.quit();
    client1Thread.wait();
    client2Thread.quit();
    client2Thread.wait();
    dataProcessorThread.quit();
    dataProcessorThread.wait();
});
 
return app.exec();
 
}
 
#include "main.moc"


目录
相关文章
|
5月前
|
网络协议 容器
【qt】 TCP编程小项目
【qt】 TCP编程小项目
95 0
|
3月前
|
消息中间件 测试技术 数据库
吊打面试官!应用间交互如何设计?
【10月更文挑战第18天】设计应用间交互需从明确需求、选择合适方式、设计协议与数据格式、考虑安全性和权限管理、进行性能优化和测试五个方面入手。明确功能和用户需求,选择接口调用、消息队列、数据库共享或文件交换等方式,确保交互高效、安全、可靠。展示这些能力将在面试中脱颖而出。
|
5月前
|
JavaScript
【Vue面试题十四】、说说你对vue的mixin的理解,有什么应用场景?
这篇文章详细介绍了Vue中`mixin`的概念、应用场景和源码分析,解释了`mixin`如何用于代码复用、功能模块化,并通过实际代码示例展示了在Vue组件中局部混入和全局混入的使用方式。
【Vue面试题十四】、说说你对vue的mixin的理解,有什么应用场景?
|
2月前
|
架构师 数据库
大厂面试高频:数据库乐观锁的实现原理、以及应用场景
数据库乐观锁是必知必会的技术栈,也是大厂面试高频,十分重要,本文解析数据库乐观锁。关注【mikechen的互联网架构】,10年+BAT架构经验分享。
大厂面试高频:数据库乐观锁的实现原理、以及应用场景
|
5月前
|
网络协议
【qt】TCP客户端信息的接受和发送
【qt】TCP客户端信息的接受和发送
38 0
|
5月前
|
网络协议
【qt】TCP客户端如何断开连接?
【qt】TCP客户端如何断开连接?
81 0
|
2月前
|
缓存 负载均衡 网络协议
面试:TCP、UDP如何解决丢包问题
TCP、UDP如何解决丢包问题。TCP:基于数据块传输/数据分片、对失序数据包重新排序以及去重、流量控制(滑动窗口)、拥塞控制、自主重传ARQ;UDP:程序执行后马上开始监听、控制报文大小、每个分割块的长度小于MTU
|
2月前
|
网络协议 算法 网络性能优化
计算机网络常见面试题(一):TCP/IP五层模型、TCP三次握手、四次挥手,TCP传输可靠性保障、ARQ协议
计算机网络常见面试题(一):TCP/IP五层模型、应用层常见的协议、TCP与UDP的区别,TCP三次握手、四次挥手,TCP传输可靠性保障、ARQ协议、ARP协议
|
5月前
|
JavaScript 前端开发
【Vue面试题二十一】、Vue中的过滤器了解吗?过滤器的应用场景有哪些?
这篇文章介绍了Vue中的过滤器,包括过滤器的定义、使用方式、串联使用以及在Vue 3中的废弃情况,并探讨了过滤器在文本格式化、单位转换等场景下的应用,同时分析了过滤器在Vue模板编译阶段的工作原理。
【Vue面试题二十一】、Vue中的过滤器了解吗?过滤器的应用场景有哪些?
|
5月前
|
JavaScript 程序员 数据安全/隐私保护
【Vue面试题二十】、你有写过自定义指令吗?自定义指令的应用场景有哪些?
这篇文章详细介绍了Vue中的自定义指令,包括指令系统的概念、如何实现自定义指令的全局和局部注册,以及自定义指令的钩子函数。文章还提供了几个自定义指令的应用场景示例,如表单防止重复提交、图片懒加载和一键复制功能,展示了自定义指令的灵活性和强大功能。
【Vue面试题二十】、你有写过自定义指令吗?自定义指令的应用场景有哪些?

热门文章

最新文章

推荐镜像

更多