Qt Socket 编程:从零开始搭建服务端与客户端

发布于:2025-08-15 ⋅ 阅读:(13) ⋅ 点赞:(0)

Qt Socket 编程:从零开始搭建服务端与客户端

引言

在网络编程中,Socket 通信 是实现计算机网络中进程间通信的关键技术。Qt 提供了非常便利的类来帮助我们实现网络通信,特别是 QTcpServerQTcpSocket,它们为基于 TCP 协议的客户端与服务端通信提供了很好的支持。

通过这篇博客,我们将通过一个简单的例子,逐步搭建 Qt 服务端客户端,并详细讲解各个函数、参数的使用,帮助你掌握 Qt Socket 编程


一、基础概念

在进行 Socket 通信之前,我们需要了解两个基本的概念:TCP 客户端TCP 服务端

1. TCP 服务端
  • 服务端的职责是:监听客户端连接,并且处理来自客户端的数据请求。
  • 服务端使用 QTcpServer 类来监听客户端的连接请求。
2. TCP 客户端
  • 客户端的职责是:连接到服务端,发送数据并接收服务端返回的数据。
  • 客户端使用 QTcpSocket 类来进行连接、发送数据和接收数据。

二、如何搭建服务端

2.1 服务端类设计

我们首先从 服务端 开始。服务端的主要任务是监听指定的端口,接收客户端的连接请求,并与每个连接的客户端进行数据交换。

2.2 创建服务端类

服务端类需要使用 QTcpServer 来启动服务并监听端口;同时,使用 QTcpSocket 来与每个连接的客户端进行数据通信。

Server.h — 服务端头文件
#ifndef SERVER_H
#define SERVER_H

#include <QTcpServer>
#include <QTcpSocket>
#include <QList>
#include <QObject>

class Server : public QObject
{
    Q_OBJECT

public:
    static Server* getInstance();  // 获取单例实例
    void startServer();  // 启动服务器,开始监听客户端连接

private slots:
    void onNewConnection();  // 处理新连接
    void onReadyRead();  // 读取客户端数据
    void onDisconnected();  // 处理客户端断开连接

private:
    Server(QObject *parent = nullptr);  // 构造函数私有化,防止外部实例化
    Server(const Server&) = delete;  // 禁止拷贝构造
    Server& operator=(const Server&) = delete;  // 禁止赋值操作

    static Server* instance;  // 静态成员变量,用于存储单例实例

    QTcpServer server;  // 用于监听客户端连接
    QList<QTcpSocket*> clientSockets;  // 存储客户端连接的列表
};

#endif // SERVER_H
2.3 构造函数和 getInstance()

服务端使用 单例模式,确保只存在一个 Server 实例。这样我们可以方便地在应用中访问服务端实例。

  • Server(QObject *parent = nullptr):构造函数私有化,防止外部直接实例化服务端对象。
  • getInstance():静态方法,确保 Server 类只有一个实例。如果实例不存在,就创建它。
2.4 startServer() 方法

startServer() 方法启动 QTcpServer,并开始监听客户端连接。

void Server::startServer()
{
    if (!server.listen(QHostAddress::Any, 5555)) {
        qCritical() << "Server failed to start:" << server.errorString();
    } else {
        qDebug() << "Server started on port 5555";
    }
}
  • listen(QHostAddress::Any, 5555)listen() 方法使服务端开始监听来自 任意网络地址 的连接请求,并指定端口号 5555
  • QHostAddress::Any:表示服务器可以监听本地计算机上的所有网络接口(包括本地回环地址 127.0.0.1 和网络地址 0.0.0.0)。
  • server.errorString():如果监听失败,输出错误信息。
2.5 处理新连接 onNewConnection()

当有客户端连接时,QTcpServer 会发出 newConnection() 信号,我们通过信号和槽机制来处理这个信号。

void Server::onNewConnection()
{
    QTcpSocket *clientSocket = server.nextPendingConnection();
    connect(clientSocket, &QTcpSocket::readyRead, this, &Server::onReadyRead);
    connect(clientSocket, &QTcpSocket::disconnected, this, &Server::onDisconnected);
    clientSockets.append(clientSocket);
    qDebug() << "New client connected";
}
  • server.nextPendingConnection():返回一个新的 QTcpSocket 对象,表示与客户端的连接。
  • readyRead 信号:当客户端有数据发送过来时,触发 readyRead() 信号,调用 onReadyRead() 函数来处理数据。
  • disconnected 信号:当客户端断开连接时,触发 disconnected() 信号,调用 onDisconnected() 来处理断开。
2.6 读取客户端数据 onReadyRead()

onReadyRead() 槽函数处理客户端发送来的数据。

void Server::onReadyRead()
{
    QTcpSocket *clientSocket = qobject_cast<QTcpSocket *>(sender());
    if (clientSocket) {
        QByteArray data = clientSocket->readAll();  // 读取客户端发送的所有数据
        qDebug() << "Received from client:" << data;
        clientSocket->write(data);  // 回显数据
    }
}
  • readAll():读取客户端发送的所有数据。
  • write():回显数据,将接收到的数据发送回客户端。
2.7 处理客户端断开连接 onDisconnected()

当客户端断开连接时,我们需要清理该连接。

void Server::onDisconnected()
{
    QTcpSocket *clientSocket = qobject_cast<QTcpSocket *>(sender());
    if (clientSocket) {
        clientSockets.removeAll(clientSocket);  // 从列表中移除断开的客户端
        clientSocket->deleteLater();  // 删除客户端连接
        qDebug() << "Client disconnected";
    }
}
  • removeAll(clientSocket):从 clientSockets 列表中移除断开的客户端。
  • deleteLater():删除客户端连接对象,释放内存。

三、搭建 TCP 客户端

客户端的任务是连接到服务端,发送数据并接收服务端的响应。客户端使用 QTcpSocket 来实现。

3.1 创建客户端类

客户端类将通过 QTcpSocket 连接到服务端,发送数据,并接收服务端的响应。

Client.h — 客户端头文件
#ifndef CLIENT_H
#define CLIENT_H

#include <QTcpSocket>
#include <QHostAddress>
#include <QObject>

class Client : public QObject
{
    Q_OBJECT

public:
    Client(QObject *parent = nullptr);

private slots:
    void onConnected();  // 成功连接到服务端
    void onReadyRead();  // 读取服务器响应的数据

private:
    QTcpSocket socket;  // 客户端的套接字
};

#endif // CLIENT_H
3.2 客户端连接服务端

客户端通过 connectToHost() 连接到服务端,端口号为 5555

#include "Client.h"
#include <QDebug>

Client::Client(QObject *parent) : QObject(parent)
{
    // 连接到服务端
    socket.connectToHost(QHostAddress::LocalHost, 5555);

    connect(&socket, &QTcpSocket::connected, this, &Client::onConnected);
    connect(&socket, &QTcpSocket::readyRead, this, &Client::onReadyRead);
}

void Client::onConnected()
{
    qDebug() << "Connected to server";
    socket.write("Hello Server!");  // 向服务器发送数据
}

void Client::onReadyRead()
{
    QByteArray data = socket.readAll();  // 读取服务器返回的数据
    qDebug() << "Received from server: " << data;
}
3.3 解释每个函数和参数
  • socket.connectToHost(QHostAddress::LocalHost, 5555):连接到本地服务端,QHostAddress::LocalHost 表示连接到本地机器。
  • connected() 信号:连接成功后触发,调用 onConnected() 发送数据到服务端。
  • readyRead() 信号:服务端发送数据时触发,客户端接收并输出数据。

四、总结

在这篇博客中,我们学习了如何使用 Qt 的 Socket 编程 来实现 TCP 客户端与服务端通信。我们搭建了一个简单的服务端和客户端,介绍了如何使用 QTcpServer 来监听连接,使用 QTcpSocket 来发送和接收数据。

  • QTcpServer:用于服务端监听连接并接受客户端的连接请求。
  • QTcpSocket:用于客户端与服务端之间的通信。
  • 信号与槽机制:通过 readyRead()newConnection()disconnected() 等信号与槽来处理数据传输和连接管理。

网站公告

今日签到

点亮在社区的每一天
去签到