既然是要实现远程实时通信,那么就需要用到网络协议。我们需要用到TCP/IP协议,不过Q提供了标准库QTcpSocket,我们只需要能够使用这个库就行了。这个标准库将远程连接通信功能封装的很好,详情可以查看QTcpSocket的文档,在Qt里面的帮助选项就可以查到。
该聊天室的功能也很简单,可以实现多个客户之间的实时通信。我们需要用到一个服务器,来监听客户端发出的消息,并将消息转发给所有的客户。服务器可以上阿里云或腾讯云去租用,没有服务器的话可以实现本地不同进程间的相互通信。
首先我们来编写服务端的逻辑代码。因为是运用的Qt,需要在服务器上安装好,我这里使用的是Qt5。同时还需要会在服务器上配置.pro文件,生成Makefile文件等,如果这些不会的话请参考我的另一篇文章在远程非桌面版Ubuntu中使用Qt5构建Hello World项目-CSDN博客
服务端完整代码
基本的Qt知识我不介绍,仅介绍sender()函数,以下程序我创建了ChatServer类。
- 
sender(): 这是一个 Qt 的宏或函数(取决于具体实现),它返回当前正在处理信号的对象指针。当一个槽函数被调用时,sender()会返回触发该槽函数的信号的发送者对象。 - 
qobject_cast<QTcpSocket*>:qobject_cast是 Qt 提供的一个类型转换函数,用于在 Qt 的对象模型中进行安全的向下类型转换。它类似于 C++ 的dynamic_cast,但在 Qt 对象模型中更加安全和高效。qobject_cast用于将一个QObject指针(或其派生类的指针)转换为另一个派生类的指针,这里转换成QTcpSocket指针。#include <QCoreApplication>
#include <QTcpServer>
#include <QTcpSocket>
#include <QList>
#include <QDebug>
#include <QObject>
class ChatServer : public QObject
{
Q_OBJECT
public:
explicit ChatServer(QObject *parent = nullptr);private slots:
void newConnection();
void readyRead();private:
//QTcpSoket对象,代表服务端
QTcpServer *server;//QTcpSoket类型的数组,保存的是客户端的对象 QList<QTcpSocket*> clients;};
ChatServer::ChatServer(QObject *parent) : QObject(parent)
{
server = new QTcpServer(this);//&ChatServer::newConnection,这是我们自己写的成员函数 connect(server, &QTcpServer::newConnection, this, &ChatServer::newConnection); //允许来自任何IP的主机连接,监听1234端口 if (server->listen(QHostAddress::Any, 1234)) { qDebug() << "Server started on port 1234"; } else { qDebug() << "Server could not start"; }}
void ChatServer::newConnection()
{
//将客户端发送请求的QTcpSoket对象添加到数组
QTcpSocket *client = server->nextPendingConnection();
clients.append(client);
connect(client, &QTcpSocket::readyRead, this, &ChatServer::readyRead);
}void ChatServer::readyRead()
{
QTcpSocket client = qobject_cast<QTcpSocket>(sender());
if (client) {
while (client->canReadLine()) {
QString message = QString::fromUtf8(client->readLine()).trimmed();
foreach (QTcpSocket *otherClient, clients) {
//if (otherClient != client){
otherClient->write(message.toUtf8());
otherClient->write("\n");
//}
}
}
}
}int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);ChatServer server; return a.exec();}
#include "main.moc"
 - 
void ChatServer::readyRead(): 这是ChatServer类中的一个槽函数,当客户端发送数据并且数据到达服务器时,readyRead信号会被触发,从而调用这个槽函数。 - 
QTcpSocket *client = qobject_cast<QTcpSocket*>(sender());: 这里使用sender()获取发送信号的对象指针,并将其转换为QTcpSocket类型的指针。sender()返回的是触发槽函数的对象,通常是发出readyRead信号的QTcpSocket对象。 - 
if (client) { ... }: 检查client是否有效(即不为nullptr)。如果转换成功,则继续执行后续代码。 - 
while (client->canReadLine()) { ... }: 这个循环会一直运行,直到从客户端读取完所有可用数据行。canReadLine()方法检查当前是否有完整的一行数据可读。 - 
QString message = QString::fromUtf8(client->readLine()).trimmed();: 这行代码从client中读取一行数据,并将其转换为QString类型。trimmed()方法用于去除字符串两端的空白字符(如空格、换行符等)。 - 
foreach (QTcpSocket *otherClient, clients) { ... }: 这是一个基于范围的 for 循环,遍历clients列表中的所有QTcpSocket对象。clients是一个包含所有连接到服务器的客户端套接字对象的列表。 - 
if (otherClient != client) { ... }: 检查当前客户端是否是发送消息的客户端。如果是,则不发送消息给自己。(注意这一段代码被我注释掉了,这样会将消息发给自己) - 
otherClient->write(message.toUtf8());: 将消息以 UTF-8 编码方式写回到otherClient中。 - 
otherClient->write("\n");: 写入一个换行符,以确保每个消息单独成行。 
客户端完整代码
代码需要分成mainwindow.h,mainwindow.cpp和main.cpp三个文件。同时需要自己在界面文件创建一个名为sendButton的QPushButton的按钮,一个名为messageLineEdit的QLineEdit的文本输入框,一个名为ChatTextEdit的QTextEdit聊天框。
mainwindow.h
        #ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTcpSocket>
#include <QHostAddress>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
private slots:
    void on_sendButton_clicked();
    void readyRead();
private:
    Ui::MainWindow *ui;
    QTcpSocket *socket;
};
#endif // MAINWINDOW_H
        mainwindow.cpp
        #include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // 初始化 TCP 套接字
    socket = new QTcpSocket(this);
    //改为自己的服务器主机名
    QString host = '114.132.169.5';
    socket->connectToHost(QHostAddress(host), 1234); 
    // 连接数据读取信号
    connect(socket, &QTcpSocket::readyRead, this, &MainWindow::readyRead);
    // 连接发送按钮点击信号
    connect(ui->sendButton, &QPushButton::clicked, this, &MainWindow::on_sendButton_clicked);
}
MainWindow::~MainWindow()
{
    delete ui;
    delete socket;
}
void MainWindow::on_sendButton_clicked()
{
    // 获取输入的文本
    QString message = ui->messageLineEdit->text();
    // 发送消息到服务器
    socket->write(message.toUtf8());
    socket->write("\n"); // 发送一个换行符表示消息结束
    // 清空输入框
    ui->messageLineEdit->clear();
}
void MainWindow::readyRead()
{
    // 读取服务器发送的消息
    while (socket->canReadLine()) {
        QString message = QString::fromUtf8(socket->readLine()).trimmed();
        // 将消息添加到聊天记录
        ui->chatTextEdit->append(message);
    }
}
        main.cpp
        #include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
        手动创建 .pro 文件
创建一个名为 chat_server.pro 的文件,并在其中添加以下内容:
QT += core
QT -= gui
CONFIG += c++11
TARGET = chat_server
TEMPLATE = app
SOURCES += main.cpp
        这个 .pro 文件配置了项目的基本设置:
- 使用 Qt Core 模块。
 - 不使用 Qt GUI 模块。
 - 启用 C++11 特性。
 - 目标文件名为 
chat_server。 - 项目模板为应用程序。
 - 包含一个源文件 
main.cpp。 
在项目目录中运行以下命令来生成 Makefile:
qmake
        qmake 会读取 .pro 文件并生成相应的 Makefile。
使用 make 命令编译项目:
make
        这将生成可执行文件 chat_server 在当前目录中。
使用 ./ 运算符运行生成的可执行文件:
./chat_server
        服务端和客户端都部署完了之后就可以开始测试运行了,先运行服务端的程序,手动创建.pro文件并编译,运行生成的可执行文件(它会一直监听来自客户端的请求)。然后再运行客户端的程序,期间不要关闭服务端的程序。如果有什么问题,欢迎私信我,可能还有些细节需要注意,不懂得找我就好了。