RK3568使用QT搭建TCP服务器和客户端

news/2025/2/1 10:22:26 标签: qt, tcp/ip, 服务器, 嵌入式, linux, RK3568

文章目录

  • 一、让RK3568开发板先连接上wifi
  • 二、客户端代码
      • 1. `widget.h` 文件
      • 2. `widget.cpp` 文件
      • **详细讲解**
        • 1. **`Widget` 类构造函数 (`Widget::Widget`)**
        • 2. **UI 布局 (`setupUI`)**
        • 3. **连接按钮的槽函数 (`onConnectClicked`)**
        • 4. **发送消息按钮的槽函数 (`onSendMessageClicked`)**
        • 5. **接收数据的槽函数 (`onDataReceived`)**
      • 总结
  • 三、服务器代码
      • `widget.h` (服务器端头文件)
      • `widget.cpp` (服务器端实现)
      • **详细讲解**
        • 1. **`Widget` 类构造函数 (`Widget::Widget`)**
        • 2. **UI 布局 (`setupUI`)**
        • 3. **启动服务器 (`onStartServerClicked`)**
        • 4. **处理新的客户端连接 (`onNewConnection`)**
        • 5. **发送消息到客户端 (`onSendMessageClicked`)**
        • 6. **接收客户端数据 (`onDataReceived`)**
      • 总结


RK3568wifi_7">一、让RK3568开发板先连接上wifi

在这里插入图片描述
测试是否可以ping通百度:

在这里插入图片描述

二、客户端代码

1. widget.h 文件

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpSocket>  // 用于TCP连接
#include <QPushButton> // 按钮控件
#include <QTextEdit>   // 文本显示控件
#include <QLineEdit>   // 单行文本输入框
#include <QVBoxLayout> // 垂直布局管理器

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr); // 构造函数
    ~Widget(); // 析构函数

private slots:
    void onConnectClicked();         // 连接到服务器的槽函数
    void onSendMessageClicked();     // 发送消息到服务器的槽函数
    void onDataReceived();           // 处理接收到的数据的槽函数

private:
    QTcpSocket *socket;              // 客户端连接对象
    QTextEdit *logTextEdit;          // 用于显示日志信息的文本框
    QLineEdit *messageInput;         // 输入消息的文本框
    QPushButton *connectButton;      // 连接服务器按钮
    QPushButton *sendButton;         // 发送消息按钮
    void setupUI();                  // 设置UI布局的函数
};

#endif // WIDGET_H

2. widget.cpp 文件

#include "widget.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGuiApplication>
#include <QScreen>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    socket(new QTcpSocket(this)) // 初始化socket对象
{
    setupUI(); // 设置UI界面

    // 连接按钮的点击信号与槽函数
    connect(connectButton, &QPushButton::clicked, this, &Widget::onConnectClicked);

    // 连接发送按钮的点击信号与槽函数
    connect(sendButton, &QPushButton::clicked, this, &Widget::onSendMessageClicked);

    // 连接接收到数据的信号与槽函数
    connect(socket, &QTcpSocket::readyRead, this, &Widget::onDataReceived);
}

Widget::~Widget()
{
    delete socket; // 销毁socket对象
}

// 设置UI布局
void Widget::setupUI()
{
    // 获取所有屏幕的信息,来设置窗口为当前屏幕的尺寸
    QList <QScreen *> list_screen = QGuiApplication::screens();

    // 设置窗口尺寸为第一个屏幕的宽度和高度
    this->resize(list_screen.at(0)->geometry().width(),
                 list_screen.at(0)->geometry().height());

    // 主垂直布局
    QVBoxLayout *mainLayout = new QVBoxLayout(this);

    // 创建日志显示框,设置为只读
    logTextEdit = new QTextEdit(this);
    logTextEdit->setReadOnly(true);
    mainLayout->addWidget(logTextEdit); // 添加到布局中

    // 输入框和发送按钮的水平布局
    QHBoxLayout *inputLayout = new QHBoxLayout;
    messageInput = new QLineEdit(this); // 创建输入框
    inputLayout->addWidget(messageInput); // 将输入框添加到布局中

    sendButton = new QPushButton("Send", this); // 创建发送按钮
    inputLayout->addWidget(sendButton); // 将发送按钮添加到布局中
    mainLayout->addLayout(inputLayout); // 将输入框和发送按钮的布局添加到主布局中

    // 连接服务器按钮
    connectButton = new QPushButton("Connect to Server", this); 
    mainLayout->addWidget(connectButton); // 添加到主布局中

    // 设置整个布局
    setLayout(mainLayout);
}

// 点击连接按钮时的槽函数
void Widget::onConnectClicked()
{
    // 尝试连接到指定IP和端口的服务器
    socket->connectToHost("192.168.0.165", 12345);  
    if (socket->waitForConnected()) {
        logTextEdit->append("Connected to server!");  // 成功连接后显示日志
    } else {
        logTextEdit->append("Failed to connect to server!");  // 连接失败时显示日志
    }
}

// 点击发送按钮时的槽函数
void Widget::onSendMessageClicked()
{
    QString message = messageInput->text(); // 获取输入框中的消息
    if (!message.isEmpty()) {
        socket->write(message.toUtf8()); // 将消息转换为UTF-8字节流并发送
        logTextEdit->append("Sent: " + message); // 显示已发送的消息
    }
}

// 处理接收到的消息的槽函数
void Widget::onDataReceived()
{
    QByteArray data = socket->readAll(); // 读取服务器发来的数据
    logTextEdit->append("Received from server: " + data); // 显示收到的消息
}

详细讲解

1. Widget 类构造函数 (Widget::Widget)
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    socket(new QTcpSocket(this)) // 初始化socket对象
{
    setupUI(); // 设置UI界面
}
  • 在构造函数中,首先通过 socket(new QTcpSocket(this)) 创建一个 QTcpSocket 对象,该对象用于客户端和服务器之间的 TCP 通信。
  • 调用 setupUI() 函数来设置界面。
2. UI 布局 (setupUI)
void Widget::setupUI()
{
    // 获取所有屏幕的信息,来设置窗口为当前屏幕的尺寸
    QList <QScreen *> list_screen = QGuiApplication::screens();
    this->resize(list_screen.at(0)->geometry().width(),
                 list_screen.at(0)->geometry().height());
    ...
}
  • 使用 QGuiApplication::screens() 获取当前系统的所有屏幕信息,并设置窗口尺寸为第一个屏幕的分辨率(宽度和高度)。
  • 使用 QVBoxLayout 创建一个垂直布局 (mainLayout),将日志框和按钮按顺序添加到这个布局中。
  • 通过 QHBoxLayout 组织输入框和发送按钮,输入框允许用户输入消息,点击 “Send” 按钮后,消息会被发送到服务器
3. 连接按钮的槽函数 (onConnectClicked)
void Widget::onConnectClicked()
{
    socket->connectToHost("192.168.0.165", 12345);  // 连接到本地 TCP 服务器
    if (socket->waitForConnected()) {
        logTextEdit->append("Connected to server!");  // 成功连接后显示日志
    } else {
        logTextEdit->append("Failed to connect to server!");  // 连接失败时显示日志
    }
}
  • connectToHost("192.168.0.165", 12345) 尝试连接到指定 IP 地址和端口的服务器
  • 如果连接成功,通过 waitForConnected() 确认连接,然后在日志框中显示 "Connected to server!"
  • 如果连接失败,则显示 "Failed to connect to server!"
4. 发送消息按钮的槽函数 (onSendMessageClicked)
void Widget::onSendMessageClicked()
{
    QString message = messageInput->text(); // 获取输入框中的消息
    if (!message.isEmpty()) {
        socket->write(message.toUtf8()); // 将消息转换为UTF-8字节流并发送
        logTextEdit->append("Sent: " + message); // 显示已发送的消息
    }
}
  • 获取输入框中的消息,并通过 QTcpSocket::write() 将消息以 UTF-8 编码发送到服务器
  • 在日志框中显示 "Sent: " 和用户输入的消息。
5. 接收数据的槽函数 (onDataReceived)
void Widget::onDataReceived()
{
    QByteArray data = socket->readAll(); // 读取服务器发来的数据
    logTextEdit->append("Received from server: " + data); // 显示收到的消息
}
  • 通过 QTcpSocket::readyRead 信号,检测到服务器发送数据时,调用此槽函数。
  • 使用 socket->readAll() 读取服务器发送的数据,并在日志框中显示 "Received from server: " 和接收到的内容。

总结

  • 本程序创建了一个简单的 TCP 客户端,能够连接到服务器并与其进行数据交互。
  • 窗口界面包含:显示日志的文本框、输入消息的文本框、连接服务器的按钮和发送消息的按钮。
  • 程序使用 QTcpSocket 类实现与服务器的连接和数据传输,能够实时显示连接状态、发送的消息和接收到的消息。

三、服务器代码

widget.h (服务器端头文件)

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>     // 用于TCP服务器
#include <QTcpSocket>     // 用于客户端连接
#include <QPushButton>    // 按钮控件
#include <QTextEdit>      // 文本显示控件
#include <QLineEdit>      // 单行文本输入框
#include <QVBoxLayout>    // 垂直布局管理器

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr); // 构造函数
    ~Widget(); // 析构函数

private slots:
    void onStartServerClicked();   // 启动服务器按钮的槽函数
    void onSendMessageClicked();   // 发送消息到客户端的槽函数
    void onNewConnection();       // 处理新的客户端连接
    void onDataReceived();         // 处理接收到的数据

private:
    QTcpServer *server;           // 服务器对象
    QTcpSocket *clientSocket;     // 客户端连接对象
    QTextEdit *logTextEdit;       // 用于显示日志信息的文本框
    QLineEdit *messageInput;      // 输入消息的文本框
    QPushButton *startServerButton; // 启动服务器按钮
    QPushButton *sendButton;      // 发送消息按钮
    void setupUI();               // 设置UI布局的函数
};

#endif // WIDGET_H

widget.cpp (服务器端实现)

#include "widget.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGuiApplication>
#include <QScreen>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    server(new QTcpServer(this)) // 创建一个 TCP 服务器对象
{
    setupUI(); // 设置UI界面

    // 连接启动服务器按钮的点击信号与槽函数
    connect(startServerButton, &QPushButton::clicked, this, &Widget::onStartServerClicked);

    // 连接发送按钮的点击信号与槽函数
    connect(sendButton, &QPushButton::clicked, this, &Widget::onSendMessageClicked);

    // 连接新客户端连接的信号与槽函数
    connect(server, &QTcpServer::newConnection, this, &Widget::onNewConnection);
}

Widget::~Widget()
{
    delete server; // 销毁 TCP 服务器对象
}

// 设置UI布局
void Widget::setupUI()
{
    // 获取所有屏幕的信息,来设置窗口为当前屏幕的尺寸
    QList <QScreen *> list_screen = QGuiApplication::screens();

    // 设置窗口尺寸为第一个屏幕的宽度和高度
    this->resize(list_screen.at(0)->geometry().width(),
                 list_screen.at(0)->geometry().height());

    // 主垂直布局
    QVBoxLayout *mainLayout = new QVBoxLayout(this);

    // 创建日志显示框,设置为只读
    logTextEdit = new QTextEdit(this);
    logTextEdit->setReadOnly(true);
    mainLayout->addWidget(logTextEdit); // 添加到布局中

    // 输入框和发送按钮的水平布局
    QHBoxLayout *inputLayout = new QHBoxLayout;
    messageInput = new QLineEdit(this); // 创建输入框
    inputLayout->addWidget(messageInput); // 将输入框添加到布局中

    sendButton = new QPushButton("Send", this); // 创建发送按钮
    inputLayout->addWidget(sendButton); // 将发送按钮添加到布局中
    mainLayout->addLayout(inputLayout); // 将输入框和发送按钮的布局添加到主布局中

    // 启动服务器按钮
    startServerButton = new QPushButton("Start Server", this);
    mainLayout->addWidget(startServerButton); // 添加到主布局中

    // 设置整个布局
    setLayout(mainLayout);
}

// 点击启动服务器按钮时的槽函数
void Widget::onStartServerClicked()
{
    if (server->listen(QHostAddress::Any, 12345)) { // 在任意网络接口的12345端口上监听
        logTextEdit->append("Server started, waiting for connections...");
    } else {
        logTextEdit->append("Failed to start server.");
    }
}

// 点击发送按钮时的槽函数
void Widget::onSendMessageClicked()
{
    QString message = messageInput->text(); // 获取输入框中的消息
    if (clientSocket && !message.isEmpty()) {
        clientSocket->write(message.toUtf8()); // 将消息转换为UTF-8字节流并发送到客户端
        logTextEdit->append("Sent: " + message); // 显示已发送的消息
    }
}

// 处理新连接的槽函数
void Widget::onNewConnection()
{
    clientSocket = server->nextPendingConnection(); // 获取新的客户端连接
    logTextEdit->append("New client connected.");

    // 连接客户端的数据接收信号与槽函数
    connect(clientSocket, &QTcpSocket::readyRead, this, &Widget::onDataReceived);

    // 连接客户端断开连接的信号与槽函数
    connect(clientSocket, &QTcpSocket::disconnected, clientSocket, &QTcpSocket::deleteLater);
}

// 处理接收到的数据的槽函数
void Widget::onDataReceived()
{
    if (clientSocket) {
        QByteArray data = clientSocket->readAll(); // 读取客户端发来的数据
        logTextEdit->append("Received from client: " + data); // 显示接收到的消息
    }
}

详细讲解

1. Widget 类构造函数 (Widget::Widget)
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    server(new QTcpServer(this)) // 创建一个 TCP 服务器对象
{
    setupUI(); // 设置UI界面
}
  • 创建 QTcpServer 对象 server,该对象将用于在指定端口上监听客户端的连接。
2. UI 布局 (setupUI)
void Widget::setupUI()
{
    QList <QScreen *> list_screen = QGuiApplication::screens();
    this->resize(list_screen.at(0)->geometry().width(),
                 list_screen.at(0)->geometry().height());
    ...
}
  • 和客户端一样,获取当前屏幕的尺寸并将窗口设置为最大化。
  • 使用 QVBoxLayout 创建垂直布局 mainLayout,并添加用于显示日志的 QTextEdit 控件。
  • 创建一个水平布局 inputLayout,包含一个输入框和一个发送按钮。
  • 创建并添加一个 “Start Server” 按钮,用于启动服务器
3. 启动服务器 (onStartServerClicked)
void Widget::onStartServerClicked()
{
    if (server->listen(QHostAddress::Any, 12345)) { // 在任意网络接口的12345端口上监听
        logTextEdit->append("Server started, waiting for connections...");
    } else {
        logTextEdit->append("Failed to start server.");
    }
}
  • listen() 函数用于启动服务器并在 12345 端口上监听客户端的连接。如果成功,输出 “Server started” 日志,否则输出错误日志。
4. 处理新的客户端连接 (onNewConnection)
void Widget::onNewConnection()
{
    clientSocket = server->nextPendingConnection(); // 获取新的客户端连接
    logTextEdit->append("New client connected.");
    ...
}
  • 使用 nextPendingConnection() 获取新的客户端连接,并通过 clientSocket 进行数据交互。
  • 在此槽函数中连接客户端的 readyRead 信号(接收到数据时)和 disconnected 信号(客户端断开连接时)。
5. 发送消息到客户端 (onSendMessageClicked)
void Widget::onSendMessageClicked()
{
    QString message = messageInput->text(); // 获取输入框中的消息
    if (clientSocket && !message.isEmpty()) {
        clientSocket->write(message.toUtf8()); // 将消息转换为UTF-8字节流并发送到客户端
        logTextEdit->append("Sent: " + message); // 显示已发送的消息
    }
}
  • 如果客户端已经连接,并且用户输入了消息,使用 clientSocket->write() 发送数据到客户端。
  • 在日志框中显示发送的消息。
6. 接收客户端数据 (onDataReceived)
void Widget::onDataReceived()
{
    if (clientSocket) {
        QByteArray data = clientSocket->readAll(); // 读取客户端发来的数据
        logTextEdit->append("Received from client: " + data); // 显示接收到的消息
    }
}
  • 当客户端发送数据时,使用 readAll() 读取数据并显示在日志框中。

总结

  • 这个程序实现了一个简单的 TCP 服务器,能够监听客户端连接,接收客户端发送的数据,并能够向客户端发送消息。
  • 服务器通过 QTcpServer 类来启动监听,并使用 QTcpSocket 类与客户端进行通信。

http://www.niftyadmin.cn/n/5839295.html

相关文章

Ruby 类和对象

Ruby 类和对象 引言 在软件开发中,类和对象是面向对象编程(OOP)的核心概念。Ruby 作为一种动态、解释型编程语言,也以简洁的方式支持面向对象编程。本文将深入探讨 Ruby 中的类和对象,包括它们的定义、创建、使用以及一些高级特性。 类与对象的定义 类 在 Ruby 中,类…

(二)QT——按钮小程序

目录 前言 按钮小程序 1、步骤 2、代码示例 3、多个按钮 ①信号与槽的一对一 ②多对一&#xff08;多个信号连接到同一个槽&#xff09; ③一对多&#xff08;一个信号连接到多个槽&#xff09; 结论 前言 按钮小程序 Qt 按钮程序通常包含 三个核心文件&#xff1a; m…

万用表使用

目录 0 万用表表盘符号说明 测量功能符号 其他符号 表盘刻度符号 一、万用表的类型和功能 二、万用表的基本功能 三、万用表的使用步骤 四、万用表的注意事项 万用表是一种多功能、多量程的测量仪表,广泛应用于电子电路、电气设备的检测和维修中。以下是万用表的使用方…

python第七章再谈抽象

创建类 class person:def set_name(self,name): #self为该类名称&#xff0c;将该类与name关联self.namenamedef get_name(self): #不设置也没问题return self.namedef greet(self):print("hello,world!Im{}".format(self.name))fooperson() foo.set_name(luke…

TGT-HC:一种用于无线时间敏感网络的时隙感知整形MAC方案的调研、设计与评估

论文标题 中文标题&#xff1a;TGT-HC&#xff1a;一种用于无线时间敏感网络的时隙感知整形MAC方案的调研、设计与评估 英文标题&#xff1a;Survey, Design and Evaluation of TGT-HC: A Time-Aware Shaper MAC for Wireless TSN 作者信息 Raymond J. Jayabal&#xff08;I…

directx12 3d+vs2022游戏开发第三章 笔记五 变换

一、变换实质 总结来说就是通过矩阵和向量计算控制点变换&#xff0c;变换的效果可以实现局内物体的平移&#xff0c;旋转&#xff0c;缩放等一系列操作。 具体实现为先使用线性变换&#xff0c;即向量矩阵控制物体对于自身坐标系的旋转&#xff0c;缩放。 再使用仿射变换&a…

Linux网络 | 网络层IP报文解析、认识网段划分与IP地址

前言&#xff1a;本节内容为网络层。 主要讲解IP协议报文字段以及分离有效载荷。 另外&#xff0c; 本节也会带领友友认识一下IP地址的划分。 那么现在废话不多说&#xff0c; 开始我们的学习吧&#xff01;&#xff01; ps&#xff1a;本节正式进入网络层喽&#xff0c; 友友们…

解锁维特比算法:探寻复杂系统的最优解密码

引言 在复杂的技术世界中&#xff0c;维特比算法以其独特的魅力和广泛的应用&#xff0c;成为通信、自然语言处理、生物信息学等领域的关键技术。今天&#xff0c;让我们一同深入探索维特比算法的奥秘。 一、维特比算法的诞生背景 维特比算法由安德鲁・维特比在 1967 年提出…