Qt进程间双向通信(QLocalSocket和QLocalServer)实现

Qt环境:Qt4

先上代码

Client:  mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QLocalSocket>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT
    
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    
private slots:
    void on_pushButtoLinkServer_clicked();

    void OnReadyRead();

    void on_pushButtonSendMsg_clicked();

private:
    Ui::MainWindow *ui;
    QLocalSocket * m_pSocketReceive;
    QString m_serverName;
};

#endif // MAINWINDOW_H

mainwindow.cpp :

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    m_pSocketReceive(NULL),
    m_serverName("ServerName")
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButtoLinkServer_clicked()
{
    if(NULL == m_pSocketReceive)
    {
        m_pSocketReceive = new QLocalSocket(this);
        m_pSocketReceive->connectToServer(m_serverName);

//        connect(m_pSocketReceive,SIGNAL(connected()),this,SLOT(OnClientConnectSuccess()));
        connect(m_pSocketReceive,SIGNAL(readyRead()),this,SLOT(OnReadyRead()));
    }
}

void MainWindow::OnReadyRead()
{
    if(m_pSocketReceive)
    {
        QDataStream tempReadDataStream(m_pSocketReceive);
        tempReadDataStream.setVersion(QDataStream::Qt_4_8);
        QString str;
        tempReadDataStream >> str;
        ui->lineEditReceiveMsg->setText(str);
    }
}

void MainWindow::on_pushButtonSendMsg_clicked()
{
    if(m_pSocketReceive)
    {
        QDataStream tempWriteDataStream(m_pSocketReceive);
       tempWriteDataStream.setVersion(QDataStream::Qt_4_8);
        QString str = ui->lineEditSendMsg->text();
        tempWriteDataStream << str;
        m_pSocketReceive->waitForBytesWritten();
    }

}

Server端:

mainwindow.h 

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QLocalServer>
#include <QLocalSocket>
#include <QProcess>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT
    
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    
private slots:
    void on_pushButtonBuildServer_clicked();


    void on_pushButtonSendMsg_clicked();

    void on_pushButtonNewProcess_clicked();

    void OnReceiveNewMsg();

private:
    Ui::MainWindow *ui;

     QLocalServer * m_pLocalServer;
     QLocalSocket * m_pSocketSend;
     QString m_serverName;
     QProcess * m_pProcess;
     QString m_appPath;

};

#endif // MAINWINDOW_H

mainwindow.cpp 

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    m_pLocalServer(NULL),
    m_pSocketSend(NULL),
    m_serverName("ServerName"),
    m_pProcess(NULL),
    m_appPath("/opt/qtcreator-2.6.1/PICDemo/QLocSocketClient-build-desktop-Debug/QLocSocketClient")
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButtonBuildServer_clicked()
{
    if(m_pLocalServer == NULL)
    {
        m_pLocalServer = new QLocalServer(this);
        //为了能够重复链接,避免Listen Fail
        QLocalServer::removeServer(m_serverName);
        if(m_pLocalServer->listen(m_serverName))
        {
            ui->lineEditServertate->setText("TRUE");
        }
    }

}

void MainWindow::on_pushButtonSendMsg_clicked()
{
    if(NULL == m_pSocketSend)
    {
        m_pSocketSend = new QLocalSocket(this);
        m_pSocketSend = m_pLocalServer->nextPendingConnection();
        connect(m_pSocketSend,SIGNAL(readyRead()),this,SLOT(OnReceiveNewMsg()));
    }
    if(m_pSocketSend)
    {
        QDataStream tempWriteDataStream(m_pSocketSend);
        tempWriteDataStream.setVersion(QDataStream::Qt_4_8);
        QString str = ui->lineEditSendMsg->text();
        tempWriteDataStream << str;
        m_pSocketSend->waitForBytesWritten();
    }
}

void MainWindow::on_pushButtonNewProcess_clicked()
{
    if(m_pProcess == NULL)
    {
        m_pProcess = new QProcess(this);
        m_pProcess->setEnvironment(m_pProcess->environment());
        m_pProcess->start(m_appPath);
        m_pProcess->waitForStarted();
    }
}

void MainWindow::OnReceiveNewMsg()
{
    QDataStream tempReadDataStream(m_pSocketSend);
    tempReadDataStream.setVersion(QDataStream::Qt_4_8);
    QString str;
    tempReadDataStream >> str;
   ui->lineEditReceiveMsg->setText(str);
}

通过建立客户端和服务端就可以利用QLocalServer和QLocalSocket实现通信了。

原理我就请出最权威的官方F1手册了:

QLocalServer:

Detailed Description

The QLocalServer class provides a local socket based server.

This class makes it possible to accept incoming local socket connections.

Call listen() to have the server start listening for incoming connections on a specified key. The newConnection() signal is then emitted each time a client connects to the server.

Call nextPendingConnection() to accept the pending connection as a connected QLocalSocket. The function returns a pointer to a QLocalSocket that can be used for communicating with the client.

If an error occurs, serverError() returns the type of error, and errorString() can be called to get a human readable description of what happened.

When listening for connections, the name which the server is listening on is available through serverName().

Calling close() makes QLocalServer stop listening for incoming connections.

Although QLocalServer is designed for use with an event loop, it's possible to use it without one. In that case, you must use waitForNewConnection(), which blocks until either a connection is available or a timeout expires.

QLocalSocket:

Detailed Description

The QLocalSocket class provides a local socket.

On Windows this is a named pipe and on Unix this is a local domain socket.

If an error occurs, socketError() returns the type of error, and errorString() can be called to get a human readable description of what happened.

Although QLocalSocket is designed for use with an event loop, it's possible to use it without one. In that case, you must use waitForConnected(), waitForReadyRead(), waitForBytesWritten(), and waitForDisconnected() which blocks until the operation is complete or the timeout expires.

Note that this feature is not supported on versions of Windows earlier than Windows XP.

总结一下遇到的坑:

1、在Linux环境下Server端listen一次能成功,但是再启动起来失败了,但是改了listen的参数,即服务器名,就有成功了。

    解决:

//为了能够重复链接,避免Listen Fail
        QLocalServer::removeServer(m_serverName);

On Unix if the server crashes without closing listen will fail with AddressInUseError. To create a new server the file should be removed. On Windows two local servers can listen to the same pipe at the same time, but any connections will go to one of the server.

摘自:https://stackoverflow.com/questions/15635215/not-able-to-start-qlocalserver 

论坛真的还是stackoverflow好用...没有贬低国内论坛的意思。


有个问题:

QLocalSocket的connected()信号一直接不到,但是连接是成功的,不知道是不是Qt的BUG。


欢迎交流。




猜你喜欢

转载自blog.csdn.net/daizhiyan1/article/details/80455806