2015-08-31 51 views
2

Qt是否有一個QIODevice對可用於內部-進程點到點通信?Qt中是否存在進程內本地管道?

可以使用具體的QTCPSocketQLocalSocket,但服務器端連接API有點麻煩,而且通過操作系統強制數據看起來很浪費。

回答

8

以下是一個可用的基本實現。它使用內部信號插槽對將數據推送到另一個端點。這樣,連接的任何一端都可以存在於任何線程中,並且可以在線程之間移動端點而不會丟失數據或引發任何比賽。

專用QRingBuffer用於代替重新發明車輪。將QT += core-private添加到.pro文件以使其可用。

在沒有其他端點集的情況下進行初始化時,必須將明確的nullptr作爲第一個參數傳遞給構造函數。這有助於避免端點與對象父級之間的混淆。

如果您希望實例化一個打開的管道,可能經常出現這種情況,您可以將I/O模式傳遞給構造函數。典型用途:

int main(/*…*/) 
{ 
    /*…*/ 
    AppPipe end1 { nullptr, QIODevice::ReadWrite }; 
    AppPipe end2 { &end1, QIODevice::ReadWrite }; 
    // the pipes are open ready to use 
    /*…*/ 
} 

無論您寫入一個管道,最終都會成爲另一個管道中的可讀數據,反之亦然。所有QIODevice語義保持 - 您可以連接到readyRead信號,使用管道QDataStreamQTextStream等。與任何QIODevice一樣,您只能使用thread()中的類,但另一個端點可以在任何線程,並且都可以根據需要在線程之間移動,而不會丟失數據。

如果另一個管端沒有打開並且可讀,則即使它們成功寫入也是空操作。關閉管道將清除讀緩衝區,以便可以重新打開以供重用。

hasIncominghasOutgoing信號用於monitoring數據通過管道。

// https://github.com/KubaO/stackoverflown/tree/master/questions/local-pipe-32317081 
#include <QtCore> 
#include <private/qringbuffer_p.h> 

/// A simple point-to-point intra-process pipe. The other endpoint can live in any 
/// thread. 
class AppPipe : public QIODevice { 
    Q_OBJECT 
    QRingBuffer m_buf; 
    Q_SLOT void _a_write(const QByteArray & data) { 
     if (! openMode() & QIODevice::ReadOnly) return; // We must be readable. 
     m_buf.append(data); 
     emit hasIncoming(data); 
     emit readyRead(); 
    } 
public: 
    AppPipe(AppPipe * other, QIODevice::OpenMode mode, QObject * parent = {}) : 
     AppPipe(other, parent) { 
     open(mode); 
    } 
    AppPipe(AppPipe * other = {}, QObject * parent = {}) : QIODevice(parent) { 
     addOther(other); 
    } 
    void addOther(AppPipe * other) { 
     if (other) { 
      connect(this, &AppPipe::hasOutgoing, other, &AppPipe::_a_write, Qt::UniqueConnection); 
      connect(other, &AppPipe::hasOutgoing, this, &AppPipe::_a_write, Qt::UniqueConnection); 
     } 
    } 
    void removeOther(AppPipe * other) { 
     disconnect(this, &AppPipe::hasOutgoing, other, &AppPipe::_a_write); 
     disconnect(other, &AppPipe::hasOutgoing, this, &AppPipe::_a_write); 
    } 
    void close() override { 
     QIODevice::close(); 
     m_buf.clear(); 
    } 
    qint64 writeData(const char * data, qint64 maxSize) override { 
     if (maxSize > 0) 
     hasOutgoing(QByteArray(data, maxSize)); 
     return maxSize; 
    } 
    qint64 readData(char * data, qint64 maxLength) override { 
     return m_buf.read(data, maxLength); 
    } 
    qint64 bytesAvailable() const override { 
     return m_buf.size() + QIODevice::bytesAvailable(); 
    } 
    bool canReadLine() const override { 
     return QIODevice::canReadLine() || m_buf.canReadLine(); 
    } 
    bool isSequential() const override { return true; } 
    Q_SIGNAL void hasOutgoing(const QByteArray &); 
    Q_SIGNAL void hasIncoming(const QByteArray &); 
}; 
# local-pipe-32317081.pro 
QT = core-private 
TARGET = local-pipe-32317081 
CONFIG += c++11 
TEMPLATE = app 
SOURCES = main.cpp