Qt中有进程内本地管道吗?

2024-01-05

Qt 有没有QIODevice适合的一对intra-处理点对点通信?

人们可以使用混凝土QTCPSocket or QLocalSocket,但是服务器端连接API有点麻烦,而且强制数据通过OS似乎很浪费。


以下是一个可用的基本实现。它使用内部信号槽对将数据推送到另一个端点。这样,连接的任一端都可以存在于任何线程中,并且两端可以在线程之间移动,而不会丢失数据或引发任何竞争。

私人的QRingBuffer用于代替重新发明轮子。添加QT += core-private to the .pro文件以使其可用。 Qt PIMPL 用于访问 Qt 5.7 及更高版本中的内部设备缓冲区。

如果您希望实例化一个开放管道(通常是这种情况),您可以将 I/O 模式传递给构造函数。典型用途:

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

无论您向一个管道写入什么内容,最终都会在另一个连接的管道中作为可读数据,反之亦然。在上面的例子中,数据写入end1两者均可读取end2 and end3独立。数据写入end2可以从以下位置读取end1. end3实际上是一个只听管道。连接额外的管道很便宜 - 向多个管道发送大块数据不会产生 O(N) 成本,因为读取QRingBuffer连接的管道存储从原始管道发送的整个字节数组的浅副本。

所有的QIODevice语义保持 - 您可以连接到readyRead信号,使用带有QDataStream or a QTextStream等。与任何QIODevice,您只能使用其中的类thread(),但另一个端点可以存在于任何线程中,并且两者都可以根据需要在线程之间移动,而不会丢失数据。

如果管道的另一端未打开且可读,则即使写入成功,写入也不会执行。关闭管道会清除读写缓冲区,以便可以重新打开以供重用。

管道缓冲区默认写入数据,可以使用以下命令强制刷新写入缓冲区AppPipe::flush(),除非打开于QIODevice::Unbuffered mode.

The hasIncoming and hasOutgoing信号可用于监控 https://stackoverflow.com/questions/32486198通过管道传输的数据。

// https://github.com/KubaO/stackoverflown/tree/master/questions/local-pipe-32317081
// This project is compatible with Qt 4 and Qt 5
#include <QtTest>
#include <private/qiodevice_p.h>
#include <private/qringbuffer_p.h>
#include <algorithm>
#include <climits>

#ifndef Q_DECL_OVERRIDE
#define Q_DECL_OVERRIDE
#endif

class AppPipePrivate : public QIODevicePrivate {
public:
#if QT_VERSION < QT_VERSION_CHECK(5,7,0)
   QRingBuffer buffer;
   QRingBuffer writeBuffer;
   int writeBufferChunkSize;
#endif
   const QByteArray *writeData;
   AppPipePrivate() : writeData(0) { writeBufferChunkSize = 4096; }
};

/// A simple point-to-point intra-process pipe. The other endpoint can live in any
/// thread.
class AppPipe : public QIODevice {
   Q_OBJECT
   Q_DECLARE_PRIVATE(AppPipe)
   static inline int intLen(qint64 len) { return std::min(len, qint64(INT_MAX)); }
   Q_SLOT void _a_write(const QByteArray &data) {
      Q_D(AppPipe);
      if (!(d->openMode & QIODevice::ReadOnly)) return; // We must be readable.
      d->buffer.append(data); // This is a chunk shipped from the source.
      emit hasIncoming(data);
      emit readyRead();
   }
   void hasOutgoingLong(const char *data, qint64 len) {
      while (len) {
         int const size = intLen(len);
         emit hasOutgoing(QByteArray(data, size));
         data += size;
         len -= size;
      }
   }
public:
   AppPipe(QIODevice::OpenMode mode, QObject *parent = 0) :
      QIODevice(*new AppPipePrivate, parent) {
      open(mode);
   }
   AppPipe(AppPipe *other, QIODevice::OpenMode mode, QObject *parent = 0) :
      QIODevice(*new AppPipePrivate, parent) {
      open(mode);
      addOther(other);
   }
   AppPipe(AppPipe *other, QObject *parent = 0) :
      QIODevice(*new AppPipePrivate, parent) {
      addOther(other);
   }
   ~AppPipe() Q_DECL_OVERRIDE {}
   void addOther(AppPipe *other) {
      if (other) {
         connect(this, SIGNAL(hasOutgoing(QByteArray)), other, SLOT(_a_write(QByteArray)), Qt::UniqueConnection);
         connect(other, SIGNAL(hasOutgoing(QByteArray)), this, SLOT(_a_write(QByteArray)), Qt::UniqueConnection);
      }
   }
   void removeOther(AppPipe *other) {
      disconnect(this, SIGNAL(hasOutgoing(QByteArray)), other, SLOT(_a_write(QByteArray)));
      disconnect(other, SIGNAL(hasOutgoing(QByteArray)), this, SLOT(_a_write(QByteArray)));
   }
   void flush() {
      Q_D(AppPipe);
      while (!d->writeBuffer.isEmpty()) {
         QByteArray const data = d->writeBuffer.read();
         emit hasOutgoing(data);
         emit bytesWritten(data.size());
      }
   }
   void close() Q_DECL_OVERRIDE {
      Q_D(AppPipe);
      flush();
      QIODevice::close();
      d->buffer.clear();
   }
   qint64 write(const QByteArray &data) { // This is an optional optimization. The base method works OK.
      Q_D(AppPipe);
      QScopedValueRollback<const QByteArray*> back(d->writeData);
      if (!(d->openMode & Text))
         d->writeData = &data;
      return QIODevice::write(data);
   }
   qint64 writeData(const char *data, qint64 len) Q_DECL_OVERRIDE {
      Q_D(AppPipe);
      bool buffered = !(d->openMode & Unbuffered);
      if (buffered && (d->writeBuffer.size() + len) > d->writeBufferChunkSize)
         flush();
      if (!buffered
          || len > d->writeBufferChunkSize
          || (len == d->writeBufferChunkSize && d->writeBuffer.isEmpty()))
      {
         if (d->writeData && d->writeData->data() == data && d->writeData->size() == len)
            emit hasOutgoing(*d->writeData);
         else
            hasOutgoingLong(data, len);
      }
      else
         memcpy(d->writeBuffer.reserve(len), data, len);
      return len;
   }
   bool isSequential() const Q_DECL_OVERRIDE { return true; }
   Q_SIGNAL void hasOutgoing(const QByteArray &);
   Q_SIGNAL void hasIncoming(const QByteArray &);
#if QT_VERSION >= QT_VERSION_CHECK(5,7,0)
   // all the data is in the read buffer already
   qint64 readData(char *, qint64) Q_DECL_OVERRIDE { return 0; }
#else
   qint64 readData(char *data, qint64 len) Q_DECL_OVERRIDE {
      Q_D(AppPipe);
      qint64 hadRead = 0;
      while (len && !d->buffer.isEmpty()) {
         int size = d->buffer.read(data, intLen(len));
         hadRead += size;
         data += size;
         len -= size;
      }
      return hadRead;
   }
   bool canReadLine() const Q_DECL_OVERRIDE {
      Q_D(const AppPipe);
      return d->buffer.indexOf('\n') != -1 || QIODevice::canReadLine();
   }
   qint64 bytesAvailable() const Q_DECL_OVERRIDE {
      Q_D(const AppPipe);
      return QIODevice::bytesAvailable() + d->buffer.size();
   }
   qint64 bytesToWrite() const Q_DECL_OVERRIDE {
      Q_D(const AppPipe);
      return QIODevice::bytesToWrite() + d->writeBuffer.size();
   }
#endif
};

// ...

#include "main.moc"

最小的测试工具:

class TestAppPipe : public QObject {
   Q_OBJECT
   QByteArray data1, data2;
   struct PipePair {
      AppPipe end1, end2;
      PipePair(QIODevice::OpenMode mode = QIODevice::NotOpen) :
         end1(QIODevice::ReadWrite | mode), end2(&end1, QIODevice::ReadWrite | mode) {}
   };
   Q_SLOT void initTestCase() {
      data1 = randomData();
      data2 = randomData();
   }
   Q_SLOT void sizes() {
      QCOMPARE(sizeof(AppPipe), sizeof(QIODevice));
   }
   Q_SLOT void basic() {
      PipePair p;
      QVERIFY(p.end1.isOpen() && p.end1.isWritable() && p.end1.isReadable());
      QVERIFY(p.end2.isOpen() && p.end2.isWritable() && p.end2.isReadable());
      static const char hello[] = "Hello There!";
      p.end1.write(hello);
      p.end1.flush();
      QCOMPARE(p.end2.readAll(), QByteArray(hello));
   }
   static QByteArray randomData(int const size = 1024*1024*32) {
      QByteArray data;
      data.resize(size);
      char *const d = data.data();
      for (char *p = d+data.size()-1; p >= d; --p)
         *p = qrand();
      Q_ASSERT(data.size() == size);
      return data;
   }
   static void randomChunkWrite(AppPipe *dev, const QByteArray &payload) {
      for (int written = 0, left = payload.size(); left; ) {
         int const chunk = std::min(qrand() % 82931, left);
         dev->write(payload.mid(written, chunk));
         left -= chunk; written += chunk;
      }
      dev->flush();
   }
   void runBigData(PipePair &p) {
      Q_ASSERT(!data1.isEmpty() && !data2.isEmpty());
      randomChunkWrite(&p.end1, data1);
      randomChunkWrite(&p.end2, data2);
      QCOMPARE(p.end1.bytesAvailable(), qint64(data2.size()));
      QCOMPARE(p.end2.bytesAvailable(), qint64(data1.size()));
      QCOMPARE(p.end1.readAll(), data2);
      QCOMPARE(p.end2.readAll(), data1);
   }
   Q_SLOT void bigDataBuffered() {
      PipePair p;
      runBigData(p);
   }
   Q_SLOT void bigDataUnbuffered() {
      PipePair p(QIODevice::Unbuffered);
      runBigData(p);
   }
   Q_SLOT void cleanupTestCase() {
      data1.clear(); data2.clear();
   }
};

QTEST_MAIN(TestAppPipe)
# local-pipe-32317081.pro
QT = core
greaterThan(QT_MAJOR_VERSION, 4): QT = core-private testlib
else: CONFIG += qtestlib
DEFINES += \
  QT_DEPRECATED_WARNINGS \
  QT_DISABLE_DEPRECATED_BEFORE=0x060000 \
  QT_RESTRICTED_CAST_FROM_ASCII
CONFIG += console c++14
CONFIG -= app_bundle
TEMPLATE = app
SOURCES = main.cpp
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt中有进程内本地管道吗? 的相关文章

随机推荐

  • git 添加 . -> 对于新文件仍然“无需提交”

    我在 Git 上遇到了困难 我似乎无法添加我的文件 我跑了ls显示文件位于当前目录中 然后运行git add then git status这表明 没有什么可承诺的 JJ Computer first app JJ git init Rei
  • UI 在大量计算时冻结

    我正在将巨大的文件加载到内存中 但在此计算中我的应用程序冻结了 知道我的代码有什么问题吗 public void Drop DragEventArgs args BackgroundWorker worker new BackgroundW
  • 如何计算性能测试响应时间的改进百分比

    我应该如何计算响应时间的改进百分比 我正进入 状态15306 ms旧代码的响应时间和799 ms更新代码的响应 响应时间的改进百分比是多少 有两种方法可以解释 响应时间的百分比改进 一种是计算百分比的经典且普遍存在的公式change在数据点
  • 如何设置QTextEdit的PlaceHolderText

    我想设置一个占位符文本QTextEdit 我知道如何将其设置为QLineEdit 有一个财产setPlaceHolderText 但此属性不适用于QTextEdit 请提出您宝贵的建议来解决这个问题 Use QTextEdit的功能 使用以
  • Spring MVC 处理程序拦截器不运行

    我有以下拦截器类 package cz coffeeexperts feedback server web interceptors import javax servlet http HttpServletRequest import j
  • 如何将图像转换为Buffer

    我想将图像 Mat 转换为缓冲区 console log image output Mat step 960 elemSize 3 sizes 160 320 empty 0 depth 0 dims 2 channels 3 type 1
  • openerp:ubuntu 上的内部服务器错误

    我刚刚在我的系统中安装了新的 OpenERP 8 0 替换了 Ubuntu 12 04 上现有的 OpenERP 7 0 我已经在家里的 Ubuntu 笔记本电脑上下载了这个 它运行得很好 并且想在我的办公室服务器上做同样的事情 我采取的步
  • STL 是否包含哈希表? [复制]

    这个问题在这里已经有答案了 可能的重复 C 中的哈希表 https stackoverflow com questions 133569 hashtable in c 有人可以提供一个简单的 C hash map 示例吗 https sta
  • 丢失的 ;在 for 循环初始化程序之后

    var nodeWordsString document getElementById nodeWordsTextArea value trim var nodeWordsStringArray nodeWordsString split
  • 在 mac el Capitan 上将 Brew 降级到之前版本 (opencv3/3.0.0)

    我在 mac 上并使用过brew安装opencv3 我有 opencv3 3 0 0 今天 我更新了它并获得了版本3 1 0 1 但是 此更新破坏了一切 当我尝试使用 VideoCapture 读取帧并使用 waitKey 函数时 它会因以
  • 如何从`MoyaError`获取错误状态代码?

    我正在使用一个Moya Moya ModelMapper and RxSwift执行网络请求 这是我的示例代码 let provider RxMoyaProvider
  • 如何使用 Realm 查询随机项目

    我只是好奇有没有办法从 Realm 查询随机项目 我需要从我的领域中获取 4 件随机物品 一件指定了 ID 的特定物品 Edit 我不知道 Realm 中有获取随机对象的方法 但您可以按照下面的描述进行操作 一种方法是查询所有对象 然后生成
  • 使用 C# 将光标移动到 MsWord 中文本的末尾?

    这个问题听起来可能很简单 但我无法找到任何解决方案 我想做的是将MsWord中的光标位置移动到文本末尾 我的代码如下 object StartPos 0 object Endpos 1 Microsoft Office Interop Wo
  • 如何使用 casperJS 等待 socket.io 连接返回数据?

    我正在抓取一个使用 socket io 填充一些选择标签选项的页面 在评估页面之前如何等待套接字接收数据 我在用casperJS http casperjs org 套接字代码 由目标站点加载 socket on list function
  • 导入错误:没有名为“Cython”的模块

    我正在尝试做from Cython Build import cythonize我收到消息ImportError No module named Cython 但是我用命令安装了Pythonpip install Cython 怎么了 Py
  • scapy 十六进制转储()

    我想知道哪个hexdump scapy 使用 因为我想修改它 但我根本找不到任何东西 我发现的是 def hexdump self lfilter None for i in range len self res p self elt2pk
  • Linux 上的 Java BlockingQueue 延迟较高

    我正在使用 BlockingQueue s 尝试 ArrayBlockingQueue 和 LinkedBlockingQueue 在我当前正在处理的应用程序中的不同线程之间传递对象 在此应用程序中 性能和延迟相对重要 因此我很好奇使用 B
  • 检查 JSON 和 XML 是否有效? C#

    我使用 newtonsoft json nethttp json codeplex com http json codeplex com 我想知道 如何验证 json 和 xml 是否有效 json xml 我如何验证这一点 您想要在服务器
  • 如何在双引号字符串中使用对象的属性?

    我有以下代码 DatabaseSettings NewDatabaseSetting select DatabaseName DataFile LogFile LiveBackupPath NewDatabaseSetting Databa
  • Qt中有进程内本地管道吗?

    Qt 有没有QIODevice适合的一对intra 处理点对点通信 人们可以使用混凝土QTCPSocket or QLocalSocket 但是服务器端连接API有点麻烦 而且强制数据通过OS似乎很浪费 以下是一个可用的基本实现 它使用内部