news 2026/9/5 18:02:15

Qt多进程(三)QLocalSocket

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Qt多进程(三)QLocalSocket

前言

本节将学习第二种IPC方式LocalSocket,它基于CS架构,建立类似于TCP方式的本地连接,实现全双工字节流的持续读写交互。如果我们期望实现本地/本机的两个进程间的持续通信,我们可以使用LocalSocket。当然TCP也是可以的,但它会产生更多的网络开销,效率也不如LocalSocket。TCP更推荐的开始跨机器的局域网连接,本机还是使用LocalSocket更加推荐。

一、LocalSocket

在Qt中,提供QLocalServer和QLocalSocket两个核心类,用以实现本地的连接通信。他们的使用和QTcpServer和QClient几乎完全一样,也就是说Qt官方故意将两者封装成类似的接口,目的是降低学习成本。
但注意,它的底层实现和tcp有本质区别!
在Windows环境下,它的底层协议基于命名管道实现,而unix下则是Unix Domain Socket。它不走网络协议,因此无网络花销,通过内核直接传递数据,建立连接和传输数据的效率都要更快。而Tcp需要走TCP/IP协议栈,需要经历一系列校验和、缓冲、拥塞控制等环节。它使用时也无需像Tcp那样指定ip和端口,只需要指定特定识别的字符串名称,且无需建立所谓三次握手的连接校验。
总的来说,如果你只在本机通信,优先用 QLocalSocket;如果可能跨机器,才用 QTcpSocket。
另外,你可能有疑问,既然LocalSocket不是基于TCP/IP实现的,那它还算是socket通信的一种吗?
的确,如果从狭义理解出发,QLocalSocket不走网络协议栈,因此不属于网络socket。
但是,从广义理解考虑,socket是一种通用的进程间通信抽象概念,它包括:
1.网络 socket:AF_INET(IPv4)、AF_INET6(IPv6)
2.本地 socket:AF_UNIX(Unix Domain Socket)或 Windows 的 Named Pipe(命名管道)
在这个意义上,QLocalServer 就是基于“本地 socket”实现的,因此属于 socket 通信的一种

二、代码示例

和之前一样,我们为QLocalSocket方式设计单独的测试窗口:

#ifndefLOCALSOCKETWINDOW_H#defineLOCALSOCKETWINDOW_H#include<QWidget>#include<QTextEdit>#include<QLineEdit>#include<QPushButton>#include<QVBoxLayout>#include<QHBoxLayout>#include<QLocalServer>#include<QLocalSocket>#include<QProcess>#include<QDateTime>classLocalSocketWindow:publicQWidget{Q_OBJECTpublic:explicitLocalSocketWindow(constQString&role,QWidget*parent=nullptr);privateslots:voidonSendMessage();voidonAcceptConnection();voidonReadyRead();voidonDisconnected();voidonConnectClicked();private:voidappendLog(constQString&msg);voidsetupServer();voidsetupClient();QString m_role;QTextEdit*m_logView;QLineEdit*m_inputEdit;QPushButton*m_sendButton;QPushButton*m_connectButton;QLocalServer*m_server;QLocalSocket*m_socket;QString m_serverName;};#endif// LOCALSOCKETWINDOW_H
#include"localsocketwindow.h"#include<QLabel>LocalSocketWindow::LocalSocketWindow(constQString&role,QWidget*parent):QWidget(parent),m_role(role),m_server(nullptr),m_socket(nullptr),m_serverName("ipc_test_local"){setWindowTitle("Local Socket - "+role);resize(600,500);m_logView=newQTextEdit();m_logView->setReadOnly(true);m_inputEdit=newQLineEdit();m_inputEdit->setPlaceholderText("Enter message to send...");m_sendButton=newQPushButton("Send Message");m_sendButton->setEnabled(false);m_connectButton=newQPushButton("Connect");QVBoxLayout*mainLayout=newQVBoxLayout();mainLayout->addWidget(m_logView);mainLayout->addWidget(m_inputEdit);mainLayout->addWidget(m_sendButton);mainLayout->addWidget(m_connectButton);setLayout(mainLayout);connect(m_sendButton,&QPushButton::clicked,this,&LocalSocketWindow::onSendMessage);connect(m_connectButton,&QPushButton::clicked,this,&LocalSocketWindow::onConnectClicked);if(m_role=="Server"){setupServer();m_connectButton->hide();}else{setupClient();}appendLog("Local Socket "+m_role+" initialized with server name: "+m_serverName);}voidLocalSocketWindow::setupServer(){QLocalServer::removeServer(m_serverName);// Clean up any previous instancem_server=newQLocalServer(this);if(!m_server->listen(m_serverName)){appendLog("Failed to start server: "+m_server->errorString());return;}connect(m_server,&QLocalServer::newConnection,this,&LocalSocketWindow::onAcceptConnection);appendLog("Server listening on "+m_serverName);}voidLocalSocketWindow::setupClient(){m_socket=newQLocalSocket(this);connect(m_socket,&QLocalSocket::connected,this,[this](){appendLog("Connected to server!");m_sendButton->setEnabled(true);m_inputEdit->setPlaceholderText("Enter message to send to server...");});connect(m_socket,&QLocalSocket::readyRead,this,&LocalSocketWindow::onReadyRead);connect(m_socket,&QLocalSocket::disconnected,this,&LocalSocketWindow::onDisconnected);}voidLocalSocketWindow::onAcceptConnection(){if(m_socket){// m_socket->disconnectFromHost();m_socket->disconnectFromServer();m_socket->deleteLater();}m_socket=m_server->nextPendingConnection();if(!m_socket)return;connect(m_socket,&QLocalSocket::readyRead,this,&LocalSocketWindow::onReadyRead);connect(m_socket,&QLocalSocket::disconnected,this,&LocalSocketWindow::onDisconnected);appendLog("Client connected!");m_sendButton->setEnabled(true);m_inputEdit->setPlaceholderText("Enter message to send to client...");}voidLocalSocketWindow::onReadyRead(){if(!m_socket)return;QByteArray data=m_socket->readAll();appendLog("Received: "+QString::fromUtf8(data));}voidLocalSocketWindow::onDisconnected(){appendLog("Disconnected from peer");m_sendButton->setEnabled(false);}voidLocalSocketWindow::onSendMessage(){if(!m_socket||m_socket->state()!=QLocalSocket::ConnectedState){appendLog("Not connected!");return;}QString msg=m_inputEdit->text();if(msg.isEmpty())return;m_socket->write(msg.toUtf8());m_socket->flush();appendLog("Sent: "+msg);m_inputEdit->clear();}voidLocalSocketWindow::onConnectClicked(){if(!m_socket)return;m_socket->connectToServer(m_serverName);appendLog("Attempting to connect to "+m_serverName);}voidLocalSocketWindow::appendLog(constQString&msg){m_logView->append(QDateTime::currentDateTime().toString("hh:mm:ss")+" | "+msg);}

代码看似冗长,实则非常简单和简洁。它和tcp一样,分为服务端和客户端。
先说服务端,创建好对象后,我们只需要指定字符串名字进行监听:

接收到连接之后,就可以保存该客户端的socket对象,之后在sendMessage中往里面写入数据:

而客户端的话,先创建socket对象,然后进行服务器的连接:

连接成功,且服务端对它发送消息后,触发槽函数。

这一系列的步骤,几乎和Qt中的tcp连接一模一样。
直接贴上运行效果图:

三、总结

进程间通信大致分为本机和跨机器两种使用场景,在本机的进程间交互中,如果双方程序都是用Qt编写的,那么使用LocalSocket无疑是更好的选择。而跨机器则应该考虑Tcp的方式。
但事实上,跨机器的通信方式有很多,只要是走网络协议的都可以,但如果扩展到那个层面上,需要学习的就太多了,而且从概念上更偏向于网络通信,而不是进程间通信了。
所以聚焦到本机的进程间通信上,我认为Tcp和Udp还是有使用价值的,下一节将学习记录一下。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/6 1:02:56

碧蓝航线Alas脚本终极指南:三步实现全自动委托与科研管理

碧蓝航线Alas脚本终极指南&#xff1a;三步实现全自动委托与科研管理 【免费下载链接】AzurLaneAutoScript Azur Lane bot (CN/EN/JP/TW) 碧蓝航线脚本 | 无缝委托科研&#xff0c;全自动大世界 项目地址: https://gitcode.com/gh_mirrors/az/AzurLaneAutoScript 还在为…

作者头像 李华
网站建设 2026/9/6 12:10:21

TranslucentTB任务栏透明化完整指南:从零基础到高级定制

TranslucentTB任务栏透明化完整指南&#xff1a;从零基础到高级定制 【免费下载链接】TranslucentTB 项目地址: https://gitcode.com/gh_mirrors/tra/TranslucentTB Windows任务栏透明化不再是复杂的技术难题&#xff01;TranslucentTB这款开源工具让每个人都能轻松打造…

作者头像 李华
网站建设 2026/9/5 20:49:44

记录一段经常会忘记的但很好用的代码

前言 来记录一段经常会忘记的但很好用的代码&#xff0c;主要是为了以后好找。 Web平滑滚动代码 // 平滑滚动public scrollTo(id: string) {const el document.getElementById(id);if (el) {el.scrollIntoView({behavior: smooth,block: center});}}behavior: 定义滚动动画&am…

作者头像 李华
网站建设 2026/9/6 6:53:32

【独家】Open-AutoGLM邀请码获取渠道TOP3排名,第1名成功率高达95%

第一章&#xff1a;Open-AutoGLM邀请码的获取意义与背景在人工智能快速发展的当下&#xff0c;大语言模型&#xff08;LLM&#xff09;的应用门槛逐渐降低&#xff0c;但高质量模型的访问权限仍受到严格控制。Open-AutoGLM 作为一款面向开发者和研究者的自动化语言生成平台&…

作者头像 李华
网站建设 2026/9/6 12:56:56

Open-AutoGLM部署后无法访问?10分钟定位并解决常见网络与权限问题

第一章&#xff1a;Open-AutoGLM部署教程Open-AutoGLM 是一个开源的自动化通用语言模型推理与部署框架&#xff0c;支持多种模型格式和硬件后端。本章将指导如何在本地环境中完成 Open-AutoGLM 的部署。环境准备 部署前需确保系统已安装以下基础组件&#xff1a; Python 3.9 或…

作者头像 李华