Qt实现网络聊天室的示例代码

下面是使用Qt实现网络聊天室的完整攻略。

简介

Qt是一款跨平台的C++开发框架,它提供了丰富的GUI界面开发组件和网络编程组件,可以轻松开发跨平台的图形化应用程序和网络应用程序。

网络编程是Qt框架的一个重要组成部分,Qt提供了QTcpServer、QTcpSocket、QUdpSocket等网络编程组件,这些组件可以方便地实现基于TCP协议和UDP协议的网络通信。

实现网络聊天室的过程大致包含以下几个步骤:

  1. 创建服务器端程序并监听端口
  2. 等待客户端连接,创建对应的套接字(QTcpSocket)
  3. 接收客户端发来的消息,并把消息发送给其他客户端
  4. 创建客户端程序,并连接服务器端
  5. 发送消息给服务器端,接收服务器端转发来的消息

下面是示例代码的具体实现过程。

服务器端代码实现

创建服务器端程序

首先需要创建一个继承自QWidget的服务器端程序,用于显示聊天室的界面,例如窗口、列表框和按钮等。

```cpp
ServerWidget::ServerWidget(QWidget *parent)
    : QWidget(parent)
{
    // 创建控件
    ...
    // 设置控件布局
    ...
    // 创建服务器套接字
    mTcpServer = new QTcpServer(this);
    connect(mTcpServer, &QTcpServer::newConnection, this, &ServerWidget::onNewConnection);
}
```

监听端口

在服务器端程序的构造函数中,创建QTcpServer对象,并连接newConnection信号,以便在有新的客户端连接请求时能及时响应。

```cpp
mTcpServer = new QTcpServer(this);
connect(mTcpServer, &QTcpServer::newConnection, this, &ServerWidget::onNewConnection);
```

在监听端口前,需要判断该端口是否已经被占用,如果已经被占用,则需要释放该端口。在此过程中可以使用QTcpServer::listen()函数来监听端口,并返回监听的结果。

```cpp
bool ServerWidget::startServer()
{
    if (mTcpServer->isListening()) {
        return true;
    }

    if (!mTcpServer->listen(QHostAddress::Any, mPort)) {
        return false;
    }

    return true;
}
```

等待客户端连接

当有客户端请求连接时,QTcpServer会发出newConnection信号,此时服务器端就可以接收连接请求,创建对应的套接字,并开启线程接收客户端的消息。

```cpp
void ServerWidget::onNewConnection()
{
    while (mTcpServer->hasPendingConnections()) {
        // 接收客户端连接请求
        QTcpSocket *tcpSocket = mTcpServer->nextPendingConnection();
        mTcpSocketList.append(tcpSocket);

        // 创建子线程用于接收客户端的消息
        QThread *thread = new QThread;
        ServerThread *worker = new ServerThread(tcpSocket);
        worker->moveToThread(thread);
        connect(thread, &QThread::started, worker, &ServerThread::process);
        connect(tcpSocket, &QTcpSocket::disconnected, worker, &ServerThread::disconnected);
        connect(worker, &ServerThread::finished, thread, &QThread::quit);
        connect(worker, &ServerThread::finished, worker, &ServerThread::deleteLater);
        connect(thread, &QThread::finished, thread, &QThread::deleteLater);
        thread->start();
    }
}
```

接收和转发消息

在服务器端程序的子线程中,可以使用QTcpSocket::readAll()函数来接收客户端发送的消息,并添加到服务器端的消息队列中。然后,服务器端程序需要遍历所有的客户端套接字,将消息转发给所有连接的客户端。

```cpp
void ServerThread::process()
{
    while (mTcpSocket->state() == QTcpSocket::ConnectedState) {
        if (mTcpSocket->bytesAvailable() > 0) {
            QByteArray byteArray = mTcpSocket->readAll();
            QString message = QString::fromUtf8(byteArray);

            // 将消息添加到服务器端的消息队列中
            mServerWidget->addMessage(message);

            // 遍历所有客户端套接字并转发消息
            foreach (QTcpSocket *tcpSocket, mServerWidget->tcpSocketList()) {
                if (tcpSocket != mTcpSocket) {
                    tcpSocket->write(message.toUtf8());
                }
            }
        }

        mTcpSocket->waitForReadyRead(50);
    }
}
```

客户端代码实现

创建客户端程序

客户端程序的创建和服务器端类似,也需要创建继承自QWidget的类,并实现相应的界面和控制逻辑。

```cpp
ClientWidget::ClientWidget(QWidget *parent)
    : QWidget(parent)
{
    // 创建控件
    ...
    // 设置控件布局
    ...
    // 创建客户端套接字
    mTcpSocket = new QTcpSocket(this);
    connect(mTcpSocket, &QTcpSocket::readyRead, this, &ClientWidget::onReadyRead);
    connect(mTcpSocket, &QTcpSocket::connected, this, &ClientWidget::onConnected);
    connect(mTcpSocket, &QTcpSocket::disconnected, this, &ClientWidget::onDisconnected);
}
```

连接服务器端

在客户端程序中,需要创建QTcpSocket对象,并使用连接函数QTcpSocket::connectToHost()来连接服务器端,连接成功后会发出connected信号。

```cpp
void ClientWidget::onConnectButtonClicked()
{
    if (mTcpSocket->state() == QTcpSocket::ConnectingState) {
        return;
    }

    QString ipAddress = mIpLineEdit->text().trimmed();
    quint16 port = mPortLineEdit->text().trimmed().toUInt();

    mTcpSocket->connectToHost(ipAddress, port);
}
```

发送消息和接收消息

在客户端程序中,可以通过QTcpSocket::write()函数来向服务器端发送消息。发送消息后,服务器端将接收并转发消息给所有的客户端,当前客户端也可以接收服务器端转发来的消息。

```cpp
void ClientWidget::onSendButtonClicked()
{
    QString message = mMessageLineEdit->text().trimmed();
    if (message.isEmpty()) {
        return;
    }

    mTcpSocket->write(message.toUtf8());
    mMessageLineEdit->clear();
}

void ClientWidget::onReadyRead()
{
    QByteArray byteArray = mTcpSocket->readAll();
    QString message = QString::fromUtf8(byteArray);
    mMessageListWidget->addItem(message);
}
```

示例说明

下面是两个使用Qt实现网络聊天室的示例说明。

示例1:实现基于TCP协议的网络聊天室

实现思路

  1. 创建服务器端程序和客户端程序。
  2. 运行服务器端程序,开始监听端口。
  3. 运行客户端程序,连接服务器端。
  4. 在客户端程序中输入消息并发送给服务器端。
  5. 服务器端接收到客户端发送来的消息,并将消息转发给所有连接的客户端。
  6. 所有客户端接收到服务器端转发来的消息。

示例代码

本示例代码主要用到了QTcpServer、QTcpSocket和QThread等网络编程组件和多线程编程。

参考代码:

  1. 基于QTcpServer的聊天室示例
  2. Qt聊天室示例

示例2:实现基于UDP协议的网络聊天室

实现思路

  1. 创建服务器端程序和客户端程序。
  2. 运行服务器端程序,绑定指定端口。
  3. 运行客户端程序,向服务器端发送消息。
  4. 服务器端接收到客户端发送来的消息,并将消息转发给所有连接的客户端。
  5. 所有客户端接收到服务器端转发来的消息。

示例代码

本示例代码主要用到了QUdpSocket等UDP协议网络编程组件。

参考代码:

  1. UDPSocket实现聊天室

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Qt实现网络聊天室的示例代码 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • javamap遍历、排序 根据value获取key

    javamap遍历、排序 根据value获取key 在Java中,Map是一种非常有用的数据结构,它可以通过键值对的方式存储数据。在实际开发中,Map经常被用于处理各种复杂的数据结构。本文将探讨如何遍历Map,如何按照value值进行排序以及如何通过value获取key。 遍历Map 遍历Map通常有两种方式:使用Iterator和使用foreach。其中,…

    其他 2023年3月29日
    00
  • 详解axios中封装使用、拦截特定请求、判断所有请求加载完毕)

    详解 axios 中封装使用、拦截特定请求、判断所有请求加载完毕 封装 Axios Axios 是一款基于 Promise 的 HTTP 请求库,让我们在浏览器端和 Node.js 中发起 HTTP 请求变得非常容易。但是,为了更好的使用和维护,我们需要对 Axios 进行封装。 我们可以将 Axios 封装成一个单独的模块,该模块会创建一个新的 Axios…

    other 2023年6月25日
    00
  • oracle常用函数整理

    以下是Oracle常用函数整理的完整攻略,包括两个示例说明。 Oracle常用函数整理 Oracle是一种常用的关系型数据库管理系统,提供了许多内置函数,用于处理和操作数据。以下是一些常用的Oracle函数。 字符串函数 CONCAT函数 CONCAT函数用于将两个或多个字符串连接在一起。 示例: SELECT CONCAT(‘Hello’, ‘World’…

    other 2023年5月6日
    00
  • 如何在iOS中高效的加载图片详解

    如何在iOS中高效的加载图片详解 为什么需要高效加载图片? 在iOS应用中,我们通常会使用图片作为应用的重要元素。然而,加载图片是一个很耗费时间和资源的过程。如果不进行优化,可能会导致应用性能下降,出现卡顿或者卡死等问题。因此,我们需要使用一些技巧和工具来高效地加载图片。 高效加载图片的技巧 1. 图片压缩 对于超过屏幕显示大小的图片,我们需要进行压缩处理。…

    other 2023年6月25日
    00
  • SpringBoot中YAML配置文件实例详解

    SpringBoot中YAML配置文件实例详解 YAML(Yet Another Markup Language)是一种轻量级的平面数据序列化格式,易于人类阅读和编写。 YAML文件使用悬空缩进的空格来指示层次结构,这对于记录配置文件和简化复杂的数据结构非常方便。 在Spring Boot中,我们可以使用YAML配置文件来配置应用程序。配置文件可以放在不同的…

    other 2023年6月25日
    00
  • Android自定义DataTimePicker实例代码(日期选择器)

    下面我给你详细讲解“Android自定义DataTimePicker实例代码(日期选择器)”的完整攻略。首先,我们来看一下这个自定义DataTimePicker实例的代码: 1. 导入依赖项 dependencies { implementation ‘com.wdullaer:materialdatetimepicker:4.2.3’ } 2. 添加控件到…

    other 2023年6月25日
    00
  • 如何隐藏/显示文件扩展名?

    当你在计算机上查看文件时,默认情况下,文件的扩展名是可见的。然而,你可以通过以下方法隐藏或显示文件扩展名: 在Windows上隐藏/显示文件扩展名: 打开文件资源管理器(Windows资源管理器)。 点击顶部菜单栏中的“查看”选项卡。 在“查看”选项卡中,找到“文件名扩展名”复选框。 如果复选框未选中,则文件扩展名将被隐藏。 如果复选框被选中,则文件扩展名将…

    other 2023年8月5日
    00
  • android之计时器(Chronometer)的使用以及常用的方法

    Android之计时器(Chronometer)的使用以及常用的方法 简介 Chronometer 是 Android 中的一个计时器控件,它可以用于显示和管理时间的计时。本攻略将详细介绍如何在 Android 应用中使用 Chronometer 控件,并提供一些常用的方法示例。 步骤 步骤 1: 在布局文件中添加 Chronometer 控件 首先,在你的…

    other 2023年8月21日
    00
合作推广
合作推广
分享本页
返回顶部