news 2026/8/6 1:39:12

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/8/5 11:06:00

Blender 3MF插件完全指南:打造专业级3D打印工作流

Blender 3MF插件完全指南&#xff1a;打造专业级3D打印工作流 【免费下载链接】Blender3mfFormat Blender add-on to import/export 3MF files 项目地址: https://gitcode.com/gh_mirrors/bl/Blender3mfFormat 作为3D打印领域的重要文件格式&#xff0c;3MF&#xff08;…

作者头像 李华
网站建设 2026/8/4 15:04:41

Bypass Paywalls Clean:打破付费墙的终极解决方案

在当今数字内容付费化的趋势下&#xff0c;优质新闻和深度报道往往被付费墙所阻隔。Bypass Paywalls Clean作为一款专为突破内容限制而设计的浏览器扩展&#xff0c;为用户提供了访问150多个主流新闻网站的完整内容权限。这款工具凭借其智能化的技术架构和简洁的用户界面&#…

作者头像 李华
网站建设 2026/8/5 17:06:58

League Akari:解决英雄联盟玩家最头疼的5个问题

League Akari&#xff1a;解决英雄联盟玩家最头疼的5个问题 【免费下载链接】LeagueAkari ✨兴趣使然的&#xff0c;功能全面的英雄联盟工具集。支持战绩查询、自动秒选等功能。基于 LCU API。 项目地址: https://gitcode.com/gh_mirrors/le/LeagueAkari 还在为错过匹配…

作者头像 李华
网站建设 2026/8/5 12:29:12

Open-AutoGLM开源全景指南(从零搭建到生产级应用)

第一章&#xff1a;Open-AutoGLM开源全景概述 Open-AutoGLM 是一个面向通用语言模型自动化任务的开源框架&#xff0c;旨在降低开发者构建、训练和部署自然语言处理应用的技术门槛。该框架集成了自动化提示工程、模型微调、评估流水线与可视化分析模块&#xff0c;支持多种主流…

作者头像 李华
网站建设 2026/8/5 14:15:22

Open-AutoGLM手机端部署实战(从模型压缩到推理加速全解析)

第一章&#xff1a;Open-AutoGLM手机端部署概述 Open-AutoGLM 是基于 AutoGLM 架构优化的轻量化大语言模型&#xff0c;专为移动端设备设计&#xff0c;在保持较高推理能力的同时显著降低资源消耗。其核心优势在于支持离线运行、低内存占用以及高效的本地化推理&#xff0c;适用…

作者头像 李华
网站建设 2026/8/6 0:51:20

美客多跨境难精准?自养号测评打通拉美市场

在拉美电商市场快速崛起之际&#xff0c;美客多&#xff08;Mercado Libre&#xff09;作为该地区的头部平台&#xff0c;正吸引着越来越多跨境卖家的目光。面对迥异的市场偏好、复杂的竞争环境和相对较高的获客成本&#xff0c;如何以低成本获取精准的市场反馈&#xff0c;成为…

作者头像 李华