Qt TCP 网络通信详解(笔记)

本文重点讲解 QTcpSocketQTcpServer 的使用逻辑、信号槽机制与完整实现流程。
适用于聊天程序、文件传输、远程控制等基础 TCP 通信场景。

一、Qt 网络模块简介

Qt 的网络功能集中在模块 QtNetwork 中。

要使用 TCP 功能,必须在 .proCMakeLists.txt 中引入该模块。 CMakeLists.txt 示例

复制代码
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Network)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network)

target_link_libraries(target_name PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Network)

二、核心类说明

Qt 的 TCP 通信基于 QTcpServer (服务端)和 QTcpSocket(客户端/连接端)两大类。

类名 功能
QTcpServer 监听端口、等待客户端连接
QTcpSocket 负责数据传输(客户端与每个连接的会话)
QHostAddress 表示 IP 地址
QNetworkInterface 查询本机网卡地址
QAbstractSocket TCP/UDP 套接字基类

三、通信原理

通信流程如下:

复制代码
┌────────────────┐        ┌───────────────────┐
│   QTcpServer   │        │     QTcpSocket    │
│ (服务端)     │◀──────▶│  (客户端/连接) │
└────────────────┘        └───────────────────┘
        ↑ newConnection()          │
        │                          │
        └── nextPendingConnection()│
                                   │readyRead() -> readAll()
  • 服务端通过 listen() 开启端口监听;

  • 有客户端连接时,会触发 newConnection() 信号;

  • 使用 nextPendingConnection() 获取一个新的 QTcpSocket

  • 客户端使用 connectToHost() 连接服务器;

  • 通信时通过信号 readyRead() 读取数据,通过 write() 发送。


四、服务端实现

widget.h

cpp 复制代码
#ifndef SERVERWIDGET_H
#define SERVERWIDGET_H

#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>

QT_BEGIN_NAMESPACE
namespace Ui {
class ServerWidget;
}
QT_END_NAMESPACE

class ServerWidget : public QWidget
{
    Q_OBJECT

public:
    explicit ServerWidget(QWidget *parent = nullptr);
    ~ServerWidget();

private slots:
    void onNewConnection();   // 客户端连接
    void onReadyRead();       // 客户端发送消息

private:
    Ui::ServerWidget *ui;
    QTcpServer *server;       // 监听对象
    QTcpSocket *socket;       // 通信套接字
};

#endif // SERVERWIDGET_H

widget.cpp

cpp 复制代码
#include "serverwidget.h"
#include "ui_serverwidget.h"
#include <QMessageBox>
#include <QDebug>

ServerWidget::ServerWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::ServerWidget)
    , server(new QTcpServer(this))
{
    ui->setupUi(this);

    // 开启监听
    if (!server->listen(QHostAddress::AnyIPv4, 8000)) {
        QMessageBox::critical(this, "错误", "监听失败:" + server->errorString());
        return;
    }

    connect(server, &QTcpServer::newConnection, this, &ServerWidget::onNewConnection);
    qDebug() << "服务器启动成功,监听端口 8000";
}

ServerWidget::~ServerWidget() { delete ui; }

void ServerWidget::onNewConnection()
{
    socket = server->nextPendingConnection();
    connect(socket, &QTcpSocket::readyRead, this, &ServerWidget::onReadyRead);

    QString ip = socket->peerAddress().toString();
    quint16 port = socket->peerPort();
    ui->logBrowser->append(QString("客户端连接:%1:%2").arg(ip).arg(port));

    socket->write("连接成功,欢迎来到服务器!\n");
}

void ServerWidget::onReadyRead()
{
    QByteArray data = socket->readAll();
    QString msg = QString::fromUtf8(data);
    ui->logBrowser->append("收到客户端:" + msg);

    socket->write("服务器已收到: " + data);
}

五、客户端实现

client.h

cpp 复制代码
#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H

#include <QWidget>
#include <QTcpSocket>

QT_BEGIN_NAMESPACE
namespace Ui {
class ClientWidget;
}
QT_END_NAMESPACE

class ClientWidget : public QWidget
{
    Q_OBJECT

public:
    explicit ClientWidget(QWidget *parent = nullptr);
    ~ClientWidget();

private slots:
    void onConnectClicked();  // 连接服务器
    void onSendClicked();     // 发送消息
    void onReadyRead();       // 接收服务器消息

private:
    Ui::ClientWidget *ui;
    QTcpSocket *socket;
};

#endif // CLIENTWIDGET_H

client.cpp

cpp 复制代码
#include "clientwidget.h"
#include "ui_clientwidget.h"
#include <QHostAddress>
#include <QMessageBox>

ClientWidget::ClientWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::ClientWidget)
    , socket(new QTcpSocket(this))
{
    ui->setupUi(this);

    connect(socket, &QTcpSocket::readyRead, this, &ClientWidget::onReadyRead);
    connect(ui->btnConnect, &QPushButton::clicked, this, &ClientWidget::onConnectClicked);
    connect(ui->btnSend, &QPushButton::clicked, this, &ClientWidget::onSendClicked);
}

ClientWidget::~ClientWidget() { delete ui; }

void ClientWidget::onConnectClicked()
{
    QString ip = ui->ipEdit->text();
    quint16 port = ui->portEdit->text().toUShort();

    socket->connectToHost(QHostAddress(ip), port);
    if (socket->waitForConnected(2000)) {
        QMessageBox::information(this, "成功", "连接服务器成功!");
    } else {
        QMessageBox::critical(this, "失败", "连接超时");
    }
}

void ClientWidget::onSendClicked()
{
    QString msg = ui->msgEdit->text();
    socket->write(msg.toUtf8());
    ui->msgEdit->clear();
}

void ClientWidget::onReadyRead()
{
    QByteArray data = socket->readAll();
    ui->recvBrowser->append("服务器:" + QString::fromUtf8(data));
}

六、常用信号槽总结

信号 含义
QTcpServer::newConnection() 当有新的客户端连接时触发
QTcpSocket::readyRead() 当有数据可读时触发
QTcpSocket::connected() 连接成功后触发
QTcpSocket::disconnected() 连接断开时触发
QTcpSocket::errorOccurred() 网络错误时触发

七、常见问题与技巧

问题 原因 解决办法
客户端连接不上 监听 IP/端口错误、防火墙拦截 使用 127.0.0.1 测试
readyRead() 不触发 服务器未 connect() 信号槽 检查 connect 语句
中文乱码 字符编码不一致 使用 QString::fromUtf8() 转换
多客户端管理 每个连接都创建独立 QTcpSocket 存入 QList<QTcpSocket*>
UI 卡顿 长时间操作在主线程中执行 QThreadQTimer::singleShot()

八、消息交互逻辑总结

复制代码
[客户端] connectToHost() → 发送连接请求
       ↓
[服务端] newConnection() → 获取 socket
       ↓
[服务端] readyRead() → 接收消息并反馈
       ↓
[客户端] readyRead() → 显示服务器返回

Qt 的网络模块基于 事件循环,通信全程异步进行,不会阻塞 UI。

九、快速调试建议

  1. 本地测试使用:

    复制代码
    IP: 127.0.0.1
    Port: 8000
  2. 服务端启动 → 客户端再连接;

  3. 若连接失败,可使用命令:

    复制代码
    netstat -ano | find "8000"

    确认端口监听是否成功;

  4. 建议开启 Qt 的调试输出:

    复制代码
    qDebug() << socket->state();

十、总结

功能 使用类 触发信号 典型函数
监听连接 QTcpServer newConnection() listen()
获取连接 QTcpServer --- nextPendingConnection()
连接服务器 QTcpSocket connected() connectToHost()
发送消息 QTcpSocket --- write()
接收消息 QTcpSocket readyRead() readAll()

总结一句话
QTcpServer 管理连接,QTcpSocket 管理通信。

Qt 的 TCP 模型是"信号槽 + 异步事件循环",

不需要多线程,也能高效、优雅地完成网络交互。

相关推荐
charlie1145141913 小时前
2D 计算机图形学基础速建——1
笔记·学习·教程·计算机图形学·基础
im_AMBER3 小时前
React 07
前端·笔记·学习·react.js·前端框架
9ilk3 小时前
【仿RabbitMQ的发布订阅式消息队列】--- 介绍
linux·笔记·分布式·后端·rabbitmq
B站计算机毕业设计之家3 小时前
深度学习:YOLOv8人体行为动作识别检测系统 行为识别检测识系统 act-dataset数据集 pyqt5 机器学习✅
人工智能·python·深度学习·qt·yolo·机器学习·计算机视觉
无聊的小坏坏4 小时前
从零开始:C++ 线程池 TCP 服务器实战(续篇)
服务器·c++·tcp/ip
开开心心就好4 小时前
Word转PDF工具,免费生成图片型文档
前端·网络·笔记·pdf·word·powerpoint·excel
想不明白的过度思考者6 小时前
TCP三次握手与四次挥手通俗理解
网络·网络协议·tcp/ip
讲师-汪春波10 小时前
[运维]宝塔 Apache环境使用CDN获取访客真实IP方法
运维·tcp/ip·apache·cdn
im_AMBER11 小时前
Leetcode 38
笔记·学习·算法·leetcode