1. 程式人生 > >用QProcess實現父子程序的雙向互動

用QProcess實現父子程序的雙向互動

記得以前寫過Linux的C程式, 裡面用popen開啟一個子程序, 這樣可以用read/write和子程序通訊, 而在子程序裡則是通過從stdin讀和向stdout寫實現對父程序的通訊。 QProcess的底層實現用的是類似的理念。 QProcess類提供的API讓父程序可以輕鬆地讀取子程序stdout的資料, 也可以輕鬆地向子程序的stdin寫資料。 不過這其中還是會有各種各樣頗讓人費解的謎團, 需要memo一下。

Test Case

兩個小程式, 父程序程式名為server。 其中定義了一個QProcess, 將QProcess的readyRead訊號連線到一個槽函式上, 用來接收client端stdout上的資訊。 在按下“Send to Client”按鈕時呼叫QProcess::write傳送編輯框裡的文字。

子程序名為client, 定義一個QFile開啟stdin, 連線readyRead訊號等待server端寫入的資料。 按下“Send message”時向stdout寫入資料。

大家覺得這個test case能如我們預料那樣正常執行嗎?

問題分析

這個程式從結構上來看非常簡單, 如果程式碼不亂寫不像是會出問題的樣子。 實際執行的結果還是頗讓人意外的, 從client端向server端傳送資料很正常, 但在client裡始終收不到readyRead訊號!  雙向交流變成了單向, 這可真讓人鬱悶。 仔細看QFile的文件包括QIODevice有關的描述, 看不出問題所在。 不得已只好求助專家拉, 按照專家的意見, QFile是不支援readyRead訊號的。 這一點比較好理解。 但是似乎沒有什麼好的Qt API可以解決此問題。

Qt的API設計裡沒有包括最底層裝置處理的類, 這個問題經常看到有人埋怨, 比如串列埠通訊等功能就沒有直接的Qt類可用。 不過嘛筆者覺得這個不算什麼問題, 像這種特別底層的東西API超簡單, open->ioctl->read/write->close就完事,就算拿Qt包一層也不會更簡單 , 何必多此一舉呢, 如果什麼功能都依賴Qt實現, 那要我們這些程式設計師幹啥用?!

這裡就需要把原來用QFile來操作stdin的程式碼修改成直接open/read/write/close的方式。 如果要保持原來的“有事件才動作”也不是難事, 這部分可以用Qt裡的QSocketNotifier類監控fd的讀寫事件, 在收到訊號時才去呼叫read/write。

主要程式碼

server端開程序
if(! pro )
{
pro = new QProcess(this);
connect(pro, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(processFinished(int, QProcess::ExitStatus)));
connect(pro, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError)));
connect(pro, SIGNAL(readyRead()), this, SLOT(readFromClient()));
pro->start(“./client”);
}

server端接收資料
void MainWin::readFromClient()
{
if( !pro) return;
QByteArray output = pro->readAllStandardOutput();
qWarning() }

server端傳送資料
void MainWin::writeToClient()
{
if( !pro) return;
pro->write(le->text().toLatin1().constData(), le->text().length());
qWarning() text();
}

client端監控stdin的讀寫訊息
filein.open(stdin, QIODevice::ReadOnly);
QSocketNotifier* sn = new QSocketNotifier(filein.handle(), QSocketNotifier::Read, this);
connect(sn, SIGNAL(activated(int)), this, SLOT(readFromServer(int)));

client端接收資料
void MainWin::readFromServer(int fd)
{
if(fd != filein.handle() )
return;

char buffer[256];
int count = read(filein.handle(), buffer, 256);
le->setText(“FROM SERVER:” + QString(buffer).left(count));
}

client端傳送資料
void MainWin::writeToServer()
{
QFile fileout;
fileout.open(stdout, QIODevice::WriteOnly);
fileout.write(le->text().toLatin1().constData(), le->text().length()); // write to stderr
qWarning() text();
fileout.close();
}

主要程式碼列出來,例子就不貼附件了。


from: http://blog.chinaunix.net/uid-13830775-id-97752.html