文章目录
Qprocess作为Qt的进程通信类,在程序中的应用还是挺多的,不管是启动一个命令行,还是另外启动一个辅助程序,QProcess都是不可或缺的。
之前也遇到过类似场景,主进程开始一个辅助进程执行Python脚本,需要传递函数名和参数,并且接受执行结果,那会是用的共享内存做的,当时是单向,主进程在共享内存段写入函数名和参数,副进程定时读取,有滞后。反正需求是实现了,当时也没想那么多。。。
最近有时间,专门研究了下QProcess,双向通信是可行的。当然我这边环境是基于windows的,Qt5.9+msvc2017 x64,系统是win10
关于QProcess的介绍我就不多说了,相信大家都很了解了,不是很了解的可以查看Qt文档。我这里主要说下几个信号:
void readyReadStandardError()
void readyReadStandardOutput()
这两个对应的就是stdout和stderr,即副进程的标准输出和标准错误通道有可读内容是,这两个信号会发出来,主进程只要绑定这两个槽函数进行相应处理就行了。
QByteArray QProcess::readAllStandardError()
QByteArray QProcess::readAllStandardOutput()
这两个就是上面绑定的槽函数里面,读取对应的内容
代码如下(示例):
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow),mProcess(new QProcess)
{
ui->setupUi(this);
setWindowTitle("processServer");
init_Process();
}
MainWindow::~MainWindow()
{
delete ui;
if(mProcess){
mProcess->close();
delete mProcess;
}
}
void MainWindow::init_Process()
{
connect(mProcess,&QProcess::readyReadStandardOutput,this,&MainWindow::slot_readyStandandOutput);
connect(mProcess,&QProcess::readyReadStandardError,this,[=](){
QString log = mProcess->readAllStandardError();
print_log(0,log);
});
QStringList argunments;
argunments <<"123456";
mProcess->start("F:/QtProject/build-processClient-Desktop_Qt_5_9_9_MSVC2017_64bit-Release/release/processClient.exe",argunments);
if(mProcess->waitForStarted(3))
{
qDebug()<<"进程启动成功";
}else{
qDebug()<<"进程启动失败!";
}
}
void MainWindow::print_log(quint8 t, QString &log)
{
if(t){
log="[标准输出]:"+log;
ui->plainTextEdit->appendHtml("<font color=\"#000000\">" + log + "</font> ");
}else{
log="[标准错误]:"+log;
ui->plainTextEdit->appendHtml("<font color=\"#FF0000\">" + log + "</font> ");
}
}
void MainWindow::slot_readyStandandOutput()
{
QString log = mProcess->readAllStandardOutput();
print_log(1,log);
}
void MainWindow::on_pushButton_clicked()
{
QString text = ui->lineEdit->text();
if(text.isEmpty()) return;
if(mProcess){
mProcess->write(text.toStdString().c_str());
}
}
demo中构造函数里面进行初始化,开启副进程,路径记得换下你自己的路径,参数的话,传不传都行,根据自己需要。
代码如下(示例):
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <QFuture>
#include <QtConcurrent/QtConcurrent>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow),mFileIN(new QFile)
{
ui->setupUi(this);
setWindowTitle("processClient");
#if 0
QTimer::singleShot(5000, this,[=](){initFileIN();});
#else
QFuture<void> f1 = QtConcurrent::run(this,&MainWindow::readstdin);
connect(this,&MainWindow::sig_receivedCommand,this,[&](QString text){
ui->textEdit->append("[读取标准输入]"+ text);
});
connect(this,&MainWindow::sig_log,this,&MainWindow::slot_print);
#endif
}
MainWindow::~MainWindow()
{
delete ui;
if(mFileIN){
mFileIN->close();
delete mFileIN;
}
}
void MainWindow::on_pushButton_clicked()
{
QString text = ui->lineEdit->text();
if(text.isEmpty()) return;
#if 0
QFile fileout;
if(fileout.open(stdout,QIODevice::WriteOnly)){
fileout.write(text.toStdString().c_str());
}else{
printErr("open fail");
}
fileout.close();
#else
std::cout<<text.toStdString()<<std::endl;
#endif
}
void MainWindow::printErr(const QString &errText)
{
QFile fileerr;
if(fileerr.open(stderr,QIODevice::WriteOnly)){
fileerr.write(errText.toStdString().c_str());
}
fileerr.close();
}
void MainWindow::on_pushButton_2_clicked()
{
QString text = ui->lineEdit->text();
if(text.isEmpty()) return;
#if 0
QFile fileerr;
if(fileerr.open(stderr,QIODevice::WriteOnly)){
fileerr.write(text.toStdString().c_str());
}
fileerr.close();
#else
std::cerr<<text.toStdString()<<std::endl;
#endif
}
void MainWindow::slot_print(const QString &text)
{
qDebug()<<text;
ui->textEdit->append("[读取标准输入]"+ text);
}
void MainWindow::readstdin()
{
bool ok = true;
char chBuf[4096];
DWORD dwRead;
HANDLE hStdinDup;
const HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
if (hStdin == INVALID_HANDLE_VALUE)
return;
DuplicateHandle(GetCurrentProcess(), hStdin,
GetCurrentProcess(), &hStdinDup,
0, false, DUPLICATE_SAME_ACCESS);
CloseHandle(hStdin);
while (ok) {
ok = ReadFile(hStdinDup, chBuf, sizeof(chBuf), &dwRead, NULL);
emit sig_log(QLatin1String("ok is:")+QString::number(ok));
if (ok && dwRead != 0) emit sig_receivedCommand(QString::fromUtf8(chBuf, dwRead));
}
}
构造函数中开了个Qtconcuurrent高级线程接口,运行readstdin函数,函数中有涉及到while阻塞,一直检测标准输入通道stdin是否有可读取的信息,因此另开线程。

demo下载
https://download.csdn.net/download/weixin_46424582/86412084
例如:以上就是今天要讲的内容,具体可查看demo,仅仅演示了Qprocess的双向通信,实际应用场景还未验证。
我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',
我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是
在前面两节的例子中,主界面窗口的尺寸和标签控件显示的矩形区域等,都是用C++代码编写的。窗口和控件的尺寸都是预估的,控件如果多起来,那就不好估计每个控件合适的位置和大小了。用C++代码编写图形界面的问题就是不直观,因此Qt项目开发了专门的可视化图形界面编辑器——QtDesigner(Qt设计师)。通过QtDesigner就可以很方便地创建图形界面文件*.ui,然后将ui文件应用到源代码里面,做到“所见即所得”,大大方便了图形界面的设计。本节就演示一下QtDesigner的简单使用,学习拖拽控件和设置控件属性,并将ui文件应用到Qt程序代码里。使用QtDesigner设计界面在开始菜单中找到「Q
MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO
我正在尝试使用以下代码通过将ffmpeg实用程序作为子进程运行并获取其输出并解析它来确定视频分辨率:IO.popen'ffmpeg-i'+path_to_filedo|ffmpegIO|#myparsegoeshereend...但是ffmpeg输出仍然连接到标准输出并且ffmepgIO.readlines是空的。ffmpeg实用程序是否需要一些特殊处理?或者还有其他方法可以获得ffmpeg输出吗?我在WinXP和FedoraLinux下测试了这段代码-结果是一样的。 最佳答案 要跟进mouviciel的评论,您需要使用类似pope
我目前正在用Ruby编写一个项目,它使用ActiveRecordgem进行数据库交互,我正在尝试使用ActiveRecord::Base.logger记录所有数据库事件具有以下代码的属性ActiveRecord::Base.logger=Logger.new(File.open('logs/database.log','a'))这适用于迁移等(出于某种原因似乎需要启用日志记录,因为它在禁用时会出现NilClass错误)但是当我尝试运行包含调用ActiveRecord对象的线程守护程序的项目时脚本失败并出现以下错误/System/Library/Frameworks/Ruby.frame
我想从rubyrake脚本运行一个可执行文件,比如foo.exe我希望将foo.exe的STDOUT和STDERR输出直接写入我正在运行rake任务的控制台.当进程完成时,我想将退出代码捕获到一个变量中。我如何实现这一目标?我一直在玩backticks、process.spawn、system但我无法获得我想要的所有行为,只有部分更新:我在Windows上,在标准命令提示符下,而不是cygwin 最佳答案 system获取您想要的STDOUT行为。它还返回true作为零退出代码,这可能很有用。$?填充了有关最后一次system调
A/ctohttp://wiki.nginx.org/CoreModule#usermaster进程曾经以root用户运行,是否可以以不同的用户运行nginxmaster进程? 最佳答案 只需以非root身份运行init脚本(即/etc/init.d/nginxstart),就可以用不同的用户运行nginxmaster进程。如果这真的是你想要做的,你将需要确保日志和pid目录(通常是/var/log/nginx&/var/run/nginx.pid)对该用户是可写的,并且您所有的listen调用都是针对大于1024的端口(因为绑定(
我在我的rails应用程序中安装了来自github.com的acts_as_versioned插件,但有一段代码我不完全理解,我希望有人能帮我解决这个问题class_eval我知道block内的方法(或任何它是什么)被定义为类内的实例方法,但我在插件的任何地方都找不到定义为常量的CLASS_METHODS,而且我也不确定是什么here,并且有问题的代码从lib/acts_as_versioned.rb的第199行开始。如果有人愿意告诉我这里的内幕,我将不胜感激。谢谢-C 最佳答案 这是一个异端。http://en.wikipedia