当前位置: 首页 > news >正文

开源 C++ QT Widget 开发(十三)IPC通讯--本地套接字 (Local Socket)

   文章的目的为了记录使用C++ 进行QT Widget 开发学习的经历。临时学习,完成app的开发。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。
 
相关链接:

开源 C++ QT Widget 开发(一)工程文件结构-CSDN博客

开源 C++ QT Widget 开发(二)基本控件应用-CSDN博客

开源 C++ QT Widget 开发(三)图表--波形显示器-CSDN博客

开源 C++ QT Widget 开发(四)文件--二进制文件查看编辑-CSDN博客

 开源 C++ QT Widget 开发(五)通讯--串口调试-CSDN博客

开源 C++ QT Widget 开发(六)通讯--TCP调试-CSDN博客

开源 C++ QT Widget 开发(七)线程--多线程及通讯-CSDN博客

开源 C++ QT Widget 开发(八)网络--Http文件下载-CSDN博客

开源 C++ QT Widget 开发(九)图表--仪表盘-CSDN博客

开源 C++ QT Widget 开发(十)IPC进程间通信--共享内存-CSDN博客

开源 C++ QT Widget 开发(十一)进程间通信--Windows 窗口通信-CSDN博客

开源 C++ QT Widget 开发(十二)图表--环境监测表盘-CSDN博客



推荐链接:

开源 java android app 开发(一)开发环境的搭建-CSDN博客

开源 java android app 开发(二)工程文件结构-CSDN博客

开源 java android app 开发(三)GUI界面布局和常用组件-CSDN博客

开源 java android app 开发(四)GUI界面重要组件-CSDN博客

开源 java android app 开发(五)文件和数据库存储-CSDN博客

开源 java android app 开发(六)多媒体使用-CSDN博客

开源 java android app 开发(七)通讯之Tcp和Http-CSDN博客

开源 java android app 开发(八)通讯之Mqtt和Ble-CSDN博客

开源 java android app 开发(九)后台之线程和服务-CSDN博客

开源 java android app 开发(十)广播机制-CSDN博客

开源 java android app 开发(十一)调试、发布-CSDN博客

开源 java android app 开发(十二)封库.aar-CSDN博客

推荐链接:

开源C# .net mvc 开发(一)WEB搭建_c#部署web程序-CSDN博客

开源 C# .net mvc 开发(二)网站快速搭建_c#网站开发-CSDN博客

开源 C# .net mvc 开发(三)WEB内外网访问(VS发布、IIS配置网站、花生壳外网穿刺访问)_c# mvc 域名下不可訪問內網,內網下可以訪問域名-CSDN博客

开源 C# .net mvc 开发(四)工程结构、页面提交以及显示_c#工程结构-CSDN博客

开源 C# .net mvc 开发(五)常用代码快速开发_c# mvc开发-CSDN博客

内容:Qt 有名管道 IPC 通信代码,本地套接字 (Local Socket)。这是在同一台机器上进行进程间通信的最常用、最推荐的方式之一。它基于 Windows 的命名管道和 Unix 的本地域套接字,提供了类似于网络 TCP 的流式通信接口。

目录:

1.功能介绍

2.核心代码分析

3.所有源码

4.显示效果

一、功能介绍

工作原理:一个服务器进程 (QLocalServer) 监听一个唯一的服务器名(如 "MyAwesomeServer")。客户端进程 (QLocalSocket) 通过该服务器名连接到服务器。之后,双方就可以像操作网络套接字一样进行读写。

适用场景:需要可靠、双向、基于流的通信。例如,一个主程序与它的插件进程、守护进程或辅助工具进行通信。

二、核心代码分析

1) 服务器端代码分析
1. 服务器启动机制

removeServer() 是必须的,避免"地址已在使用"错误

服务器名称 "MyLocalServer" 是通信的唯一标识

支持启动/停止切换功能

void MainWindow::on_startServer_clicked()
{// 清理旧实例 - 防止资源泄漏QLocalServer::removeServer(serverName); // 关键:清理可能存在的旧服务器if (server->listen(serverName)) { // 监听指定名称的服务器// 成功监听}
}

2. 连接管理机制

单客户端设计:每次只保持一个连接,新连接会替换旧连接

信号槽机制实现异步事件处理

自动内存管理:使用 deleteLater() 安全释放资源

void MainWindow::on_newConnection()
{clientConnection = server->nextPendingConnection(); // 获取新连接connect(clientConnection, &QLocalSocket::readyRead, this, &MainWindow::on_readyRead);connect(clientConnection, &QLocalSocket::disconnected, this, &MainWindow::on_disconnected);
}


 

3. 数据通信机制

使用 readAll() 而非 readLine(),更稳定但需要自定义协议

UTF-8 编码确保跨平台兼容性

简单的字符串协议,

void MainWindow::on_readyRead()
{QByteArray data = clientConnection->readAll(); // 读取所有可用数据QString message = QString::fromUtf8(data).trimmed();
}



正确的资源释放顺序,避免内存泄漏

MainWindow::~MainWindow()
{if (server) {server->close();    // 先关闭delete server;      // 再删除}// 类似的客户端连接清理
}


 

2) 客户端代码分析
架构设计

class QLocalSocket; // 前向声明QLocalSocket *socket; // 客户端套接字对象


核心机制分析
1. 连接管理机制
 

void MainWindow::on_connectButton_clicked()
{if (!socket) {socket = new QLocalSocket(this); // 父对象管理生命周期// 连接所有信号槽}socket->connectToServer(serverName); // 异步连接
}


技术要点:

连接/断开切换功能

异步连接操作,不阻塞UI线程

父对象管理内存,自动释放

2. 错误处理机制

// 兼容旧版本的错误处理
connect(socket, SIGNAL(error(QLocalSocket::LocalSocketError)), this, SLOT(on_errorOccurred(QLocalSocket::LocalSocketError)));void MainWindow::on_errorOccurred(QLocalSocket::LocalSocketError socketError)
{Q_UNUSED(socketError); // 不使用错误代码,直接获取错误字符串ui->textBrowser->append("Error: " + socket->errorString());
}

使用传统 SIGNAL/SLOT 语法确保版本兼容性

errorString() 提供人类可读的错误信息

Q_UNUSED 避免编译器警告

3. 状态管理
 

void MainWindow::on_connected()
{ui->connectButton->setText("Disconnect"); // UI状态更新
}void MainWindow::on_disconnected()
{ui->connectButton->setText("Connect"); // UI状态恢复
}

3. 通信协议分析
当前实现

// 发送端
QByteArray data = message.toUtf8(); // 简单字符串编码
socket->write(data);// 接收端  
QByteArray data = socket->readAll(); // 读取所有数据
QString message = QString::fromUtf8(data).trimmed();

三、所有源码

服务器和客户端.pro文件都需要添加

QT += core gui network

1.  服务器端

mianwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QLocalServer>
#include <QLocalSocket>QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void on_startServer_clicked();void on_sendMessage_clicked();void on_newConnection();void on_readyRead();void on_disconnected();private:Ui::MainWindow *ui;QLocalServer *server;QLocalSocket *clientConnection;
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow), server(nullptr), clientConnection(nullptr)
{ui->setupUi(this);setWindowTitle("Server - Named Pipe Example");
}MainWindow::~MainWindow()
{if (server) {server->close();delete server;}if (clientConnection) {clientConnection->close();delete clientConnection;}delete ui;
}void MainWindow::on_startServer_clicked()
{if (server) {server->close();delete server;server = nullptr;}server = new QLocalServer(this);connect(server, &QLocalServer::newConnection, this, &MainWindow::on_newConnection);QString serverName = "MyLocalServer";if (server->listen(serverName)) {ui->textBrowser->append("Server started successfully!");ui->textBrowser->append("Listening on: " + serverName);ui->startServer->setText("Stop Server");} else {ui->textBrowser->append("Failed to start server: " + server->errorString());delete server;server = nullptr;}
}void MainWindow::on_newConnection()
{if (clientConnection) {clientConnection->close();delete clientConnection;}clientConnection = server->nextPendingConnection();connect(clientConnection, &QLocalSocket::readyRead, this, &MainWindow::on_readyRead);connect(clientConnection, &QLocalSocket::disconnected, this, &MainWindow::on_disconnected);ui->textBrowser->append("New client connected!");
}void MainWindow::on_readyRead()
{if (clientConnection && clientConnection->canReadLine()) {QByteArray data = clientConnection->readLine();QString message = QString::fromUtf8(data).trimmed();ui->textBrowser->append("Received: " + message);}
}void MainWindow::on_disconnected()
{ui->textBrowser->append("Client disconnected");if (clientConnection) {clientConnection->deleteLater();clientConnection = nullptr;}
}void MainWindow::on_sendMessage_clicked()
{if (!clientConnection || clientConnection->state() != QLocalSocket::ConnectedState) {QMessageBox::warning(this, "Warning", "No client connected!");return;}QString message = ui->lineEdit->text();if (message.isEmpty()) {return;}QByteArray data = (message + "\n").toUtf8();clientConnection->write(data);clientConnection->flush();ui->textBrowser->append("Sent: " + message);ui->lineEdit->clear();
}

ui_mainwindow.h

/********************************************************************************
** Form generated from reading UI file 'mainwindow.ui'
**
** Created by: Qt User Interface Compiler version 5.14.2
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/#ifndef UI_MAINWINDOW_H
#define UI_MAINWINDOW_H#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QStatusBar>
#include <QtWidgets/QTextEdit>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QWidget>QT_BEGIN_NAMESPACEclass Ui_MainWindow
{
public:QWidget *centralwidget;QWidget *verticalLayoutWidget;QVBoxLayout *verticalLayout;QTextEdit *textBrowser;QLineEdit *lineEdit;QPushButton *sendMessage;QPushButton *startServer;QHBoxLayout *horizontalLayout;QMenuBar *menubar;QStatusBar *statusbar;void setupUi(QMainWindow *MainWindow){if (MainWindow->objectName().isEmpty())MainWindow->setObjectName(QString::fromUtf8("MainWindow"));MainWindow->resize(753, 365);centralwidget = new QWidget(MainWindow);centralwidget->setObjectName(QString::fromUtf8("centralwidget"));verticalLayoutWidget = new QWidget(centralwidget);verticalLayoutWidget->setObjectName(QString::fromUtf8("verticalLayoutWidget"));verticalLayoutWidget->setGeometry(QRect(10, 1, 741, 301));verticalLayout = new QVBoxLayout(verticalLayoutWidget);verticalLayout->setObjectName(QString::fromUtf8("verticalLayout"));verticalLayout->setContentsMargins(0, 0, 0, 0);textBrowser = new QTextEdit(verticalLayoutWidget);textBrowser->setObjectName(QString::fromUtf8("textBrowser"));verticalLayout->addWidget(textBrowser);lineEdit = new QLineEdit(verticalLayoutWidget);lineEdit->setObjectName(QString::fromUtf8("lineEdit"));verticalLayout->addWidget(lineEdit);sendMessage = new QPushButton(verticalLayoutWidget);sendMessage->setObjectName(QString::fromUtf8("sendMessage"));verticalLayout->addWidget(sendMessage);startServer = new QPushButton(verticalLayoutWidget);startServer->setObjectName(QString::fromUtf8("startServer"));verticalLayout->addWidget(startServer);horizontalLayout = new QHBoxLayout();horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));verticalLayout->addLayout(horizontalLayout);MainWindow->setCentralWidget(centralwidget);menubar = new QMenuBar(MainWindow);menubar->setObjectName(QString::fromUtf8("menubar"));menubar->setGeometry(QRect(0, 0, 753, 26));MainWindow->setMenuBar(menubar);statusbar = new QStatusBar(MainWindow);statusbar->setObjectName(QString::fromUtf8("statusbar"));MainWindow->setStatusBar(statusbar);retranslateUi(MainWindow);QMetaObject::connectSlotsByName(MainWindow);} // setupUivoid retranslateUi(QMainWindow *MainWindow){MainWindow->setWindowTitle(QCoreApplication::translate("MainWindow", "MainWindow", nullptr));sendMessage->setText(QCoreApplication::translate("MainWindow", "\345\217\221\351\200\201\346\266\210\346\201\257", nullptr));startServer->setText(QCoreApplication::translate("MainWindow", "\345\220\257\345\212\250\346\234\215\345\212\241\345\231\250", nullptr));} // retranslateUi};namespace Ui {class MainWindow: public Ui_MainWindow {};
} // namespace UiQT_END_NAMESPACE#endif // UI_MAINWINDOW_H

2.  客户端代码

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QLocalSocket>QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void on_connectButton_clicked();void on_sendButton_clicked();void on_connected();void on_readyRead();void on_disconnected();void on_errorOccurred(QLocalSocket::LocalSocketError socketError); // 修改参数private:Ui::MainWindow *ui;QLocalSocket *socket;
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow), socket(nullptr)
{ui->setupUi(this);setWindowTitle("Client - Named Pipe Example");
}MainWindow::~MainWindow()
{if (socket) {socket->close();delete socket;}delete ui;
}void MainWindow::on_connectButton_clicked()
{if (socket && socket->state() == QLocalSocket::ConnectedState) {socket->disconnectFromServer();return;}if (!socket) {socket = new QLocalSocket(this);connect(socket, &QLocalSocket::connected, this, &MainWindow::on_connected);connect(socket, &QLocalSocket::readyRead, this, &MainWindow::on_readyRead);connect(socket, &QLocalSocket::disconnected, this, &MainWindow::on_disconnected);// 兼容旧版本 Qt 的错误处理方式#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)connect(socket, &QLocalSocket::errorOccurred, this, &MainWindow::on_errorOccurred);#elseconnect(socket, QOverload<QLocalSocket::LocalSocketError>::of(&QLocalSocket::error),this, &MainWindow::on_errorOccurred);#endif}QString serverName = "MyLocalServer";socket->connectToServer(serverName);ui->textBrowser->append("Connecting to server...");
}void MainWindow::on_connected()
{ui->textBrowser->append("Connected to server successfully!");ui->connectButton->setText("Disconnect");
}void MainWindow::on_readyRead()
{if (socket && socket->canReadLine()) {QByteArray data = socket->readLine();QString message = QString::fromUtf8(data).trimmed();ui->textBrowser->append("Received: " + message);}
}void MainWindow::on_disconnected()
{ui->textBrowser->append("Disconnected from server");ui->connectButton->setText("Connect");
}void MainWindow::on_errorOccurred(QLocalSocket::LocalSocketError socketError)
{Q_UNUSED(socketError);ui->textBrowser->append("Error: " + socket->errorString());
}void MainWindow::on_sendButton_clicked()
{if (!socket || socket->state() != QLocalSocket::ConnectedState) {QMessageBox::warning(this, "Warning", "Not connected to server!");return;}QString message = ui->lineEdit->text();if (message.isEmpty()) {return;}QByteArray data = (message + "\n").toUtf8();socket->write(data);socket->flush();ui->textBrowser->append("Sent: " + message);ui->lineEdit->clear();
}

ui_mianwindow.h

/********************************************************************************
** Form generated from reading UI file 'mainwindow.ui'
**
** Created by: Qt User Interface Compiler version 5.14.2
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/#ifndef UI_MAINWINDOW_H
#define UI_MAINWINDOW_H#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QStatusBar>
#include <QtWidgets/QTextBrowser>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QWidget>QT_BEGIN_NAMESPACEclass Ui_MainWindow
{
public:QWidget *centralwidget;QWidget *verticalLayoutWidget;QVBoxLayout *verticalLayout;QTextBrowser *textBrowser;QLineEdit *lineEdit;QPushButton *sendButton;QPushButton *connectButton;QMenuBar *menubar;QStatusBar *statusbar;void setupUi(QMainWindow *MainWindow){if (MainWindow->objectName().isEmpty())MainWindow->setObjectName(QString::fromUtf8("MainWindow"));MainWindow->resize(581, 401);centralwidget = new QWidget(MainWindow);centralwidget->setObjectName(QString::fromUtf8("centralwidget"));verticalLayoutWidget = new QWidget(centralwidget);verticalLayoutWidget->setObjectName(QString::fromUtf8("verticalLayoutWidget"));verticalLayoutWidget->setGeometry(QRect(10, 10, 561, 321));verticalLayout = new QVBoxLayout(verticalLayoutWidget);verticalLayout->setObjectName(QString::fromUtf8("verticalLayout"));verticalLayout->setContentsMargins(0, 0, 0, 0);textBrowser = new QTextBrowser(verticalLayoutWidget);textBrowser->setObjectName(QString::fromUtf8("textBrowser"));verticalLayout->addWidget(textBrowser);lineEdit = new QLineEdit(verticalLayoutWidget);lineEdit->setObjectName(QString::fromUtf8("lineEdit"));verticalLayout->addWidget(lineEdit);sendButton = new QPushButton(verticalLayoutWidget);sendButton->setObjectName(QString::fromUtf8("sendButton"));verticalLayout->addWidget(sendButton);connectButton = new QPushButton(verticalLayoutWidget);connectButton->setObjectName(QString::fromUtf8("connectButton"));verticalLayout->addWidget(connectButton);MainWindow->setCentralWidget(centralwidget);menubar = new QMenuBar(MainWindow);menubar->setObjectName(QString::fromUtf8("menubar"));menubar->setGeometry(QRect(0, 0, 581, 26));MainWindow->setMenuBar(menubar);statusbar = new QStatusBar(MainWindow);statusbar->setObjectName(QString::fromUtf8("statusbar"));MainWindow->setStatusBar(statusbar);retranslateUi(MainWindow);QMetaObject::connectSlotsByName(MainWindow);} // setupUivoid retranslateUi(QMainWindow *MainWindow){MainWindow->setWindowTitle(QCoreApplication::translate("MainWindow", "MainWindow", nullptr));sendButton->setText(QCoreApplication::translate("MainWindow", "\345\217\221\351\200\201\346\266\210\346\201\257", nullptr));connectButton->setText(QCoreApplication::translate("MainWindow", "\350\277\236\346\216\245", nullptr));} // retranslateUi};namespace Ui {class MainWindow: public Ui_MainWindow {};
} // namespace UiQT_END_NAMESPACE#endif // UI_MAINWINDOW_H

四、显示效果

http://www.xdnf.cn/news/1488079.html

相关文章:

  • 【Flink】Flink Runtime 架构设计
  • LangChain实战(二十一):构建自动化AI客服系统
  • 蓓韵安禧DHA孕期友好配方:纯净营养安心孕育健康
  • 自然语言处理 基于神经网络的词向量转化模型word2vec
  • GitHub App 架构解析与最佳实践
  • [C/C++学习] 6.弹跳小球(B)
  • 机器学习入门实践:加州房价预测从 0 到 1 全过程
  • Altium Designer(AD24)新建原理图文件的几种方法
  • 性能剖析工具火焰图介绍与实战demo
  • 系统广告拦截工具:一键关闭烦人弹窗
  • GitHub 热榜项目 - 日榜(2025-09-07)
  • 力扣1210. 穿过迷宫的最少移动次数 详解
  • 【数学建模】在烟雾导弹遮蔽模型中的实际参考文献
  • 数据结构:顺序表与链表
  • VBA之Word应用第四章第二节:段落集合Paragraphs对象(二)
  • Vue2.x核心技术与实战(六)-Vuex
  • Ubuntu中如何进入root用户
  • LeetCode 几道 Promises 和 Time 的题目
  • 论文阅读:ICLR 2021 BAG OF TRICKS FOR ADVERSARIAL TRAINING
  • 初识Vue
  • nvidia 的 PTX 有多少个?
  • win10(三)视频剪裁
  • Balabolka:免费高效的文字转语音软件
  • unsloth 笔记:从最近的检查点继续微调
  • Apache EnumUtils枚举工具类
  • 计算机⽹络及TCP⽹络应⽤程序开发
  • 定制开发开源AI智能名片S2B2C商城小程序的优势与局限性分析
  • ZYNQ PS XADC读取芯片内部温度值,电压值。
  • Java 模块系统深度解析:从 Jigsaw 到现代模块化开发
  • 功率器件固晶挑战:抗高温翘曲治具提升IGBT焊接强度30%