2026/6/9 16:32:01
网站建设
项目流程
广州商城网站开发,对php网站开发技术课程总结,网站建设与管理基础及实训(php版),wordpress免费商城主题前言
本节将学习第二种IPC方式LocalSocket#xff0c;它基于CS架构#xff0c;建立类似于TCP方式的本地连接#xff0c;实现全双工字节流的持续读写交互。如果我们期望实现本地/本机的两个进程间的持续通信#xff0c;我们可以使用LocalSocket。当然TCP也是可以的#xff…前言本节将学习第二种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.网络 socketAF_INETIPv4、AF_INET6IPv62.本地 socketAF_UNIXUnix Domain Socket或 Windows 的 Named Pipe命名管道在这个意义上QLocalServer 就是基于“本地 socket”实现的因此属于 socket 通信的一种。二、代码示例和之前一样我们为QLocalSocket方式设计单独的测试窗口#ifndefLOCALSOCKETWINDOW_H#defineLOCALSOCKETWINDOW_H#includeQWidget#includeQTextEdit#includeQLineEdit#includeQPushButton#includeQVBoxLayout#includeQHBoxLayout#includeQLocalServer#includeQLocalSocket#includeQProcess#includeQDateTimeclassLocalSocketWindow:publicQWidget{Q_OBJECTpublic:explicitLocalSocketWindow(constQStringrole,QWidget*parentnullptr);privateslots:voidonSendMessage();voidonAcceptConnection();voidonReadyRead();voidonDisconnected();voidonConnectClicked();private:voidappendLog(constQStringmsg);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#includelocalsocketwindow.h#includeQLabelLocalSocketWindow::LocalSocketWindow(constQStringrole,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_logViewnewQTextEdit();m_logView-setReadOnly(true);m_inputEditnewQLineEdit();m_inputEdit-setPlaceholderText(Enter message to send...);m_sendButtonnewQPushButton(Send Message);m_sendButton-setEnabled(false);m_connectButtonnewQPushButton(Connect);QVBoxLayout*mainLayoutnewQVBoxLayout();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_roleServer){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_servernewQLocalServer(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_socketnewQLocalSocket(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_socketm_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 datam_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 msgm_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(constQStringmsg){m_logView-append(QDateTime::currentDateTime().toString(hh:mm:ss) | msg);}代码看似冗长实则非常简单和简洁。它和tcp一样分为服务端和客户端。先说服务端创建好对象后我们只需要指定字符串名字进行监听接收到连接之后就可以保存该客户端的socket对象之后在sendMessage中往里面写入数据而客户端的话先创建socket对象然后进行服务器的连接连接成功且服务端对它发送消息后触发槽函数。这一系列的步骤几乎和Qt中的tcp连接一模一样。直接贴上运行效果图三、总结进程间通信大致分为本机和跨机器两种使用场景在本机的进程间交互中如果双方程序都是用Qt编写的那么使用LocalSocket无疑是更好的选择。而跨机器则应该考虑Tcp的方式。但事实上跨机器的通信方式有很多只要是走网络协议的都可以但如果扩展到那个层面上需要学习的就太多了而且从概念上更偏向于网络通信而不是进程间通信了。所以聚焦到本机的进程间通信上我认为Tcp和Udp还是有使用价值的下一节将学习记录一下。