开源 C++ QT QML 开发(十二)通讯--TCP客户端

文章的目的为了记录使用QT QML开发学习的经历。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。

相关链接:

开源 C++ QT QML 开发(一)基本介绍

开源 C++ QT QML 开发(二)工程结构

开源 C++ QT QML 开发(三)常用控件

开源 C++ QT QML 开发(四)复杂控件--Listview

开源 C++ QT QML 开发(五)复杂控件--Gridview

开源 C++ QT QML 开发(六)自定义控件--波形图

开源 C++ QT QML 开发(七)自定义控件--仪表盘

开源 C++ QT QML 开发(八)自定义控件--圆环

开源 C++ QT QML 开发(九)文件--文本和二进制

开源 C++ QT QML 开发(十)通讯--串口

开源 C++ QT QML 开发(十一)通讯--TCP服务器端

开源 C++ QT QML 开发(十二)通讯--TCP客户端

推荐链接:

开源 C# 快速开发(一)基础知识

开源 C# 快速开发(二)基础控件

开源 C# 快速开发(三)复杂控件

开源 C# 快速开发(四)自定义控件--波形图

开源 C# 快速开发(五)自定义控件--仪表盘

开源 C# 快速开发(六)自定义控件--圆环

开源 C# 快速开发(七)通讯--串口

开源 C# 快速开发(八)通讯--Tcp服务器端

开源 C# 快速开发(九)通讯--Tcp客户端

开源 C# 快速开发(十)通讯--http客户端

开源 C# 快速开发(十一)线程

开源 C# 快速开发(十二)进程监控

开源 C# 快速开发(十三)进程--管道通讯

开源 C# 快速开发(十四)进程--内存映射

开源 C# 快速开发(十五)进程--windows消息

开源 C# 快速开发(十六)数据库--sqlserver增删改查

本章节主要内容是:TCP客户端调试代码,ip和port可设置,数据发送和接收。

1.代码分析

2.所有源码

3.效果演示

一、代码分析

一、头文件分析 (TcpClient.h)

1.1 类声明和属性系统

复制代码
class TcpClient : public QObject
{
    Q_OBJECT
    Q_PROPERTY(bool isConnected READ isConnected NOTIFY connectionChanged)
    Q_PROPERTY(QString statusMessage READ statusMessage NOTIFY statusChanged)
    Q_PROPERTY(QString receivedData READ receivedData NOTIFY dataReceived)

详细分析:

Q_OBJECT:启用Qt的元对象系统,支持信号槽机制

Q_PROPERTY:将C++成员暴露给QML,实现数据绑定

isConnected:只读布尔属性,反映连接状态

statusMessage:只读字符串属性,显示状态信息

receivedData:只读字符串属性,存储接收到的数据

1.2 公共接口函数

复制代码
public:
    explicit TcpClient(QObject *parent = nullptr);

    Q_INVOKABLE void connectToServer(const QString &ip, int port);
    Q_INVOKABLE void disconnectFromHost();
    Q_INVOKABLE void sendMessage(const QString &message);

    bool isConnected() const { return m_connected; }
    QString statusMessage() const { return m_statusMessage; }
    QString receivedData() const { return m_receivedData; }

函数作用:

Q_INVOKABLE:使C++函数可在QML中调用

构造函数:初始化父对象和成员变量

connectToServer:连接到指定IP和端口的服务器

disconnectFromHost:主动断开连接

sendMessage:向服务器发送消息

三个getter函数:返回对应属性的值

1.3 信号声明

复制代码
signals:
    void connectionChanged();
    void statusChanged();
    void dataReceived();

信号作用:

connectionChanged:连接状态改变时发射

statusChanged:状态消息更新时发射

dataReceived:收到新数据时发射

1.4 私有槽函数

复制代码
private slots:
    void onConnected();
    void onDisconnected();
    void onReadyRead();
    void onErrorOccurred(QAbstractSocket::SocketError error);

槽函数功能:

onConnected:处理连接成功事件

onDisconnected:处理连接断开事件

onReadyRead:处理数据可读事件

onErrorOccurred:处理错误事件

二、源文件分析 (TcpClient.cpp)

2.1 构造函数

复制代码
TcpClient::TcpClient(QObject *parent)
    : QObject(parent)
    , m_connected(false)
{
    m_socket = new QTcpSocket(this);

    // 连接信号槽 - 使用Qt5.12兼容的方式
    connect(m_socket, &QTcpSocket::connected, this, &TcpClient::onConnected);
    connect(m_socket, &QTcpSocket::disconnected, this, &TcpClient::onDisconnected);
    connect(m_socket, &QTcpSocket::readyRead, this, &TcpClient::onReadyRead);

    // Qt5.12兼容的错误处理方式
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
    connect(m_socket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::errorOccurred),
            this, &TcpClient::onErrorOccurred);
#else
    connect(m_socket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::error),
            this, &TcpClient::onErrorOccurred);
#endif

    m_statusMessage = "未连接";
}

详细分析:

成员初始化:m_connected初始化为false,m_statusMessage设为"未连接"

Socket创建:new QTcpSocket(this),指定父对象实现自动内存管理

信号槽连接:

connected → onConnected:连接建立

disconnected → onDisconnected:连接断开

readyRead → onReadyRead:数据可读

版本兼容处理:针对Qt 5.15前后版本不同的错误信号名称

2.2 connectToServer 函数

复制代码
void TcpClient::connectToServer(const QString &ip, int port)
{
    if (m_connected) {
        m_statusMessage = "已连接,请先断开当前连接";
        emit statusChanged();
        return;
    }

    m_statusMessage = QString("正在连接 %1:%2...").arg(ip).arg(port);
    emit statusChanged();

    m_socket->connectToHost(ip, port);
}

执行流程:

状态检查:如果已连接,设置错误状态并返回

更新状态:显示正在连接的信息

触发状态变更:发射statusChanged信号更新UI

发起连接:调用QTcpSocket::connectToHost异步连接

2.3 disconnectFromHost 函数

复制代码
void TcpClient::disconnectFromHost()
{
    if (m_socket && m_connected) {
        m_socket->disconnectFromHost();
    }
}

特点:

安全性检查:确保socket存在且处于连接状态

优雅断开:disconnectFromHost()会等待数据发送完成

2.4 sendMessage 函数

复制代码
void TcpClient::sendMessage(const QString &message)
{
    if (!m_connected || !m_socket) {
        m_statusMessage = "未连接,无法发送消息";
        emit statusChanged();
        return;
    }

    QByteArray data = message.toUtf8();
    qint64 bytesWritten = m_socket->write(data);

    if (bytesWritten == -1) {
        m_statusMessage = "发送失败: " + m_socket->errorString();
        emit statusChanged();
    } else {
        // 在接收数据显示区域也显示发送的消息
        QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");
        QString sendInfo = QString("[%1] 发送: %2").arg(timestamp).arg(message);
        appendToReceivedData(sendInfo);
        m_statusMessage = "消息发送成功";
        emit statusChanged();
    }
}

详细流程:

连接验证:检查socket和连接状态

编码转换:将QString转换为UTF-8字节数组

数据发送:调用write()方法发送数据

结果处理:

失败:记录错误信息

成功:添加时间戳并显示在接收区,更新状态

2.5 onConnected 槽函数

复制代码
void TcpClient::onConnected()
{
    m_connected = true;
    m_statusMessage = "连接服务器成功";

    QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");
    QString connectInfo = QString("[%1] 已连接到服务器").arg(timestamp);
    appendToReceivedData(connectInfo);

    emit connectionChanged();
    emit statusChanged();
}

处理逻辑:

更新连接状态:m_connected = true

设置成功状态消息

记录连接时间戳到接收数据区

发射状态变更信号更新UI

2.6 onDisconnected 槽函数

复制代码
void TcpClient::onDisconnected()
{
    m_connected = false;
    m_statusMessage = "已断开连接";

    QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");
    QString disconnectInfo = QString("[%1] 与服务器断开连接").arg(timestamp);
    appendToReceivedData(disconnectInfo);

    emit connectionChanged();
    emit statusChanged();
}

对称处理:与onConnected类似,但处理断开连接的情况

2.7 onReadyRead 槽函数

复制代码
void TcpClient::onReadyRead()
{
    if (!m_socket) return;

    QByteArray data = m_socket->readAll();
    QString message = QString::fromUtf8(data);

    QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");
    QString receivedInfo = QString("[%1] 接收: %2").arg(timestamp).arg(message);
    appendToReceivedData(receivedInfo);

    m_statusMessage = "收到新消息";
    emit statusChanged();
    emit dataReceived();
}

数据接收流程:

安全性检查:确保socket有效

读取数据:readAll()读取所有可用数据

编码转换:UTF-8字节数组转QString

格式化显示:添加时间戳前缀

更新状态:显示收到新消息,发射数据接收信号

2.8 onErrorOccurred 槽函数

复制代码
void TcpClient::onErrorOccurred(QAbstractSocket::SocketError error)
{
    Q_UNUSED(error)

    m_connected = false;
    m_statusMessage = "连接错误: " + m_socket->errorString();

    QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");
    QString errorInfo = QString("[%1] 错误: %2").arg(timestamp).arg(m_socket->errorString());
    appendToReceivedData(errorInfo);

    emit connectionChanged();
    emit statusChanged();
}

错误处理:

Q_UNUSED(error):避免未使用参数警告

重置连接状态

获取详细的错误描述信息

记录错误日志到接收区

通知UI更新状态

2.9 appendToReceivedData 辅助函数

复制代码
void TcpClient::appendToReceivedData(const QString &message)
{
    m_receivedData.prepend(message + "\n");

    // 限制显示的行数,避免内存占用过大
    QStringList lines = m_receivedData.split('\n');
    if (lines.size() > 1000) { // 最多保留1000行
        lines = lines.mid(0, 1000);
        m_receivedData = lines.join('\n');
    }

    emit dataReceived();
}

内存管理策略:

前置添加:prepend()使最新消息显示在最前面

行数限制:最多保留1000行数据

内存优化:防止长时间运行导致内存无限增长

信号通知:发射dataReceived更新UI显示

三、QML界面分析

3.1 主窗口结构

复制代码
ApplicationWindow {
    id: window
    width: 800
    height: 600
    title: "TCP客户端"
    visible: true

    TcpClient {
        id: client
    }

注册C++类型到QML,创建client实例

3.2 控制面板布局

连接控制部分:

复制代码
TextField {
    id: serverIPField
    text: "127.0.0.1"  // 默认本地回环地址
}
TextField {
    id: portField  
    text: "8080"      // 默认端口
    validator: IntValidator { bottom: 1; top: 65535 }  // 输入验证
}

动态按钮:

复制代码
Button {
    id: connectButton
    text: client.isConnected ? "断开连接" : "连接服务器"  // 状态相关文本
    onClicked: {
        if (client.isConnected) {
            client.disconnectFromHost()
        } else {
            var port = parseInt(portField.text)
            if (port > 0 && port <= 65535) {
                client.connectToServer(serverIPField.text, port)
            }
        }
    }
}

3.3 消息显示区域

复制代码
ScrollView {
    TextArea {
        id: receivedTextArea
        text: client.receivedData  // 绑定到C++属性
        readOnly: true
        wrapMode: TextArea.Wrap
        selectByMouse: true
        font.family: "Courier New"  // 等宽字体,便于对齐
    }
}

四、程序入口分析

4.1 main函数

复制代码
int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    // 注册TCP客户端类型到QML
    qmlRegisterType<TcpClient>("TcpClient", 1, 0, "TcpClient");

    QQmlApplicationEngine engine;
    engine.load(url);

    return app.exec();
}

二、所有源码

.pro文件源码

复制代码
QT += quick quickcontrols2 network

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Refer to the documentation for the
# deprecated API to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
        TcpClient.cpp \
        main.cpp

RESOURCES += qml.qrc

# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =

# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

HEADERS += \
    TcpClient.h

TcpClient.h文件源码

复制代码
#ifndef TCPCLIENT_H
#define TCPCLIENT_H

#include <QObject>
#include <QTcpSocket>
#include <QTimer>
#include <QDateTime>

class TcpClient : public QObject
{
    Q_OBJECT
    Q_PROPERTY(bool isConnected READ isConnected NOTIFY connectionChanged)
    Q_PROPERTY(QString statusMessage READ statusMessage NOTIFY statusChanged)
    Q_PROPERTY(QString receivedData READ receivedData NOTIFY dataReceived)

public:
    explicit TcpClient(QObject *parent = nullptr);

    Q_INVOKABLE void connectToServer(const QString &ip, int port);
    Q_INVOKABLE void disconnectFromHost();
    Q_INVOKABLE void sendMessage(const QString &message);

    bool isConnected() const { return m_connected; }
    QString statusMessage() const { return m_statusMessage; }
    QString receivedData() const { return m_receivedData; }

signals:
    void connectionChanged();
    void statusChanged();
    void dataReceived();

private slots:
    void onConnected();
    void onDisconnected();
    void onReadyRead();
    void onErrorOccurred(QAbstractSocket::SocketError error);

private:
    void appendToReceivedData(const QString &message);

    QTcpSocket *m_socket;
    QString m_statusMessage;
    QString m_receivedData;
    bool m_connected;
};

#endif // TCPCLIENT_H

TcpClient.cpp文件源码

复制代码
#include "TcpClient.h"
#include <QHostAddress>

TcpClient::TcpClient(QObject *parent)
    : QObject(parent)
    , m_connected(false)
{
    m_socket = new QTcpSocket(this);

    // 连接信号槽 - 使用Qt5.12兼容的方式
    connect(m_socket, &QTcpSocket::connected, this, &TcpClient::onConnected);
    connect(m_socket, &QTcpSocket::disconnected, this, &TcpClient::onDisconnected);
    connect(m_socket, &QTcpSocket::readyRead, this, &TcpClient::onReadyRead);

    // Qt5.12兼容的错误处理方式
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
    connect(m_socket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::errorOccurred),
            this, &TcpClient::onErrorOccurred);
#else
    connect(m_socket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::error),
            this, &TcpClient::onErrorOccurred);
#endif

    m_statusMessage = "未连接";
}

void TcpClient::connectToServer(const QString &ip, int port)
{
    if (m_connected) {
        m_statusMessage = "已连接,请先断开当前连接";
        emit statusChanged();
        return;
    }

    m_statusMessage = QString("正在连接 %1:%2...").arg(ip).arg(port);
    emit statusChanged();

    m_socket->connectToHost(ip, port);
}

void TcpClient::disconnectFromHost()
{
    if (m_socket && m_connected) {
        m_socket->disconnectFromHost();
    }
}

void TcpClient::sendMessage(const QString &message)
{
    if (!m_connected || !m_socket) {
        m_statusMessage = "未连接,无法发送消息";
        emit statusChanged();
        return;
    }

    QByteArray data = message.toUtf8();
    qint64 bytesWritten = m_socket->write(data);

    if (bytesWritten == -1) {
        m_statusMessage = "发送失败: " + m_socket->errorString();
        emit statusChanged();
    } else {
        // 在接收数据显示区域也显示发送的消息
        QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");
        QString sendInfo = QString("[%1] 发送: %2").arg(timestamp).arg(message);
        appendToReceivedData(sendInfo);
        m_statusMessage = "消息发送成功";
        emit statusChanged();
    }
}

void TcpClient::onConnected()
{
    m_connected = true;
    m_statusMessage = "连接服务器成功";

    QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");
    QString connectInfo = QString("[%1] 已连接到服务器").arg(timestamp);
    appendToReceivedData(connectInfo);

    emit connectionChanged();
    emit statusChanged();
}

void TcpClient::onDisconnected()
{
    m_connected = false;
    m_statusMessage = "已断开连接";

    QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");
    QString disconnectInfo = QString("[%1] 与服务器断开连接").arg(timestamp);
    appendToReceivedData(disconnectInfo);

    emit connectionChanged();
    emit statusChanged();
}

void TcpClient::onReadyRead()
{
    if (!m_socket) return;

    QByteArray data = m_socket->readAll();
    QString message = QString::fromUtf8(data);

    QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");
    QString receivedInfo = QString("[%1] 接收: %2").arg(timestamp).arg(message);
    appendToReceivedData(receivedInfo);

    m_statusMessage = "收到新消息";
    emit statusChanged();
    emit dataReceived();
}

void TcpClient::onErrorOccurred(QAbstractSocket::SocketError error)
{
    Q_UNUSED(error)

    m_connected = false;
    m_statusMessage = "连接错误: " + m_socket->errorString();

    QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");
    QString errorInfo = QString("[%1] 错误: %2").arg(timestamp).arg(m_socket->errorString());
    appendToReceivedData(errorInfo);

    emit connectionChanged();
    emit statusChanged();
}

void TcpClient::appendToReceivedData(const QString &message)
{
    m_receivedData.prepend(message + "\n");

    // 限制显示的行数,避免内存占用过大
    QStringList lines = m_receivedData.split('\n');
    if (lines.size() > 1000) { // 最多保留1000行
        lines = lines.mid(0, 1000);
        m_receivedData = lines.join('\n');
    }

    emit dataReceived();
}

main.qml文件源码

复制代码
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import TcpClient 1.0

ApplicationWindow {
    id: window
    width: 800
    height: 600
    title: "TCP客户端"
    visible: true

    TcpClient {
        id: client
    }

    // TCP客户端控制区域
    Rectangle {
        id: controlPanel
        width: parent.width
        height: 180
        color: "#f0f0f0"
        border.color: "#cccccc"

        ColumnLayout {
            anchors.fill: parent
            anchors.margins: 10

            // 连接设置行
            RowLayout {
                Layout.fillWidth: true

                Label {
                    text: "服务器IP:"
                }

                TextField {
                    id: serverIPField
                    Layout.preferredWidth: 200
                    text: "127.0.0.1"
                    placeholderText: "输入服务器IP地址"
                }

                Label {
                    text: "端口号:"
                }

                TextField {
                    id: portField
                    Layout.preferredWidth: 100
                    text: "8080"
                    validator: IntValidator { bottom: 1; top: 65535 }
                    placeholderText: "输入端口号"
                }

                Button {
                    id: connectButton
                    text: client.isConnected ? "断开连接" : "连接服务器"
                    onClicked: {
                        if (client.isConnected) {
                            client.disconnectFromHost()
                        } else {
                            var port = parseInt(portField.text)
                            if (port > 0 && port <= 65535) {
                                client.connectToServer(serverIPField.text, port)
                            } else {
                                statusLabel.text = "端口号无效"
                            }
                        }
                    }
                    background: Rectangle {
                        color: client.isConnected ? "#e74c3c" : "#2ecc71"
                        radius: 4
                    }
                    contentItem: Text {
                        text: connectButton.text
                        color: "white"
                        horizontalAlignment: Text.AlignHCenter
                        verticalAlignment: Text.AlignVCenter
                        font.bold: true
                    }
                }
            }

            // 状态显示行
            RowLayout {
                Layout.fillWidth: true

                Label {
                    id: statusLabel
                    text: client.statusMessage
                    Layout.fillWidth: true
                    color: client.isConnected ? "#27ae60" : "#e74c3c"
                    font.bold: true
                    wrapMode: Text.Wrap
                }

                Label {
                    text: "连接状态: " + (client.isConnected ? "已连接" : "未连接")
                    color: client.isConnected ? "#2980b9" : "#95a5a6"
                    font.bold: true
                }
            }

            // 消息发送行
            RowLayout {
                Layout.fillWidth: true

                TextField {
                    id: messageField
                    Layout.fillWidth: true
                    placeholderText: "输入要发送的消息..."
                    enabled: client.isConnected
                    onAccepted: sendButton.clicked()
                }

                Button {
                    id: sendButton
                    text: "发送消息"
                    enabled: client.isConnected && messageField.text.trim() !== ""
                    onClicked: {
                        if (messageField.text.trim() !== "") {
                            client.sendMessage(messageField.text)
                            messageField.clear()
                        }
                    }
                    background: Rectangle {
                        color: sendButton.enabled ? "#9b59b6" : "#bdc3c7"
                        radius: 4
                    }
                    contentItem: Text {
                        text: sendButton.text
                        color: "white"
                        horizontalAlignment: Text.AlignHCenter
                        verticalAlignment: Text.AlignVCenter
                    }
                }
            }

            // 控制按钮行
            RowLayout {
                Layout.fillWidth: true

                Button {
                    text: "清空日志"
                    onClicked: {
                        // 由于receivedData是只读的,需要在C++端添加清空方法
                        // 这里暂时通过重新创建对象来清空
                        client.sendMessage("") // 触发更新
                    }
                    background: Rectangle {
                        color: "#f39c12"
                        radius: 4
                    }
                    contentItem: Text {
                        text: "清空日志"
                        color: "white"
                        horizontalAlignment: Text.AlignHCenter
                        verticalAlignment: Text.AlignVCenter
                    }
                }

                Button {
                    text: "测试消息"
                    enabled: client.isConnected
                    onClicked: {
                        client.sendMessage("Hello from TCP Client!")
                    }
                    background: Rectangle {
                        color: "#3498db"
                        radius: 4
                    }
                    contentItem: Text {
                        text: "测试消息"
                        color: "white"
                        horizontalAlignment: Text.AlignHCenter
                        verticalAlignment: Text.AlignVCenter
                    }
                }

                Item {
                    Layout.fillWidth: true
                }

                Label {
                    text: "服务器: " + (client.isConnected ?
                          serverIPField.text + ":" + portField.text : "未连接")
                    color: "#8e44ad"
                    font.bold: true
                }
            }
        }
    }

    // 消息显示区域
    Rectangle {
        anchors {
            top: controlPanel.bottom
            bottom: parent.bottom
            left: parent.left
            right: parent.right
        }
        color: "white"
        border.color: "#dee2e6"

        ScrollView {
            anchors.fill: parent
            anchors.margins: 5

            TextArea {
                id: receivedTextArea
                text: client.receivedData
                readOnly: true
                wrapMode: TextArea.Wrap
                selectByMouse: true
                font.family: "Courier New"
                font.pixelSize: 12
                background: null
            }
        }
    }
}

main.cpp文件源码

复制代码
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "TcpClient.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    // 注册TCP客户端
    qmlRegisterType<TcpClient>("TcpClient", 1, 0, "TcpClient");

    QQmlApplicationEngine engine;

    // 设置应用程序信息
    app.setApplicationName("TCP客户端");
    app.setApplicationVersion("1.0");

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);

    engine.load(url);

    return app.exec();
}

三、效果演示

打开网络调试助手进行测试,设置ip和port,测试发送和接收。

相关推荐
进击的圆儿5 小时前
【学习笔记05】C++11新特性学习总结(下)
c++·笔记·学习
Jayden_Ruan5 小时前
C++十进制转二进制
数据结构·c++·算法
算家计算5 小时前
蚂蚁开源万亿参数大模型Ling-1T:多项能力全球领先
人工智能·开源·资讯
nnnnichijou5 小时前
Qt Quick 3D-机械臂模型显示与交互
qt·3d·交互
说私域6 小时前
技术指数变革下的组织适应性研究:基于定制开发开源AI智能名片S2B2C商城小程序的实践观察
人工智能·小程序·开源
小何好运暴富开心幸福6 小时前
C++之日期类的实现
开发语言·c++·git·bash
老赵的博客6 小时前
c++ 是静态编译语言
开发语言·c++
lixinnnn.7 小时前
贪心:火烧赤壁
数据结构·c++·算法
Predestination王瀞潞7 小时前
类的多态(Num020)
开发语言·c++