[英]C++ start a script ( bash, python … ) and using stdin/stdout for datatransfare [linux]
我想從我的C ++代碼中調用python腳本。 python腳本看起來像:
hello.py
#!/usr/bin/python
import sys
print "Hello!"
Readin = sys.stdin.read()
print Readin
C ++代碼來自堆棧溢出的另一個問題。 它應該如何工作:
創建一對管道。
用fork()
創建一個子進程。
孩子正在將其管道彎曲到標准輸入/標准輸出。 關閉另一端並啟動腳本。
父親正在聽管道read()
,接收輸入。 然后,發送一條消息write()
。
當輸入switch (readResult = read(childToPa...
)時,程序不會從父行返回。
我也不知道本文是否正在發揮作用。 這樣做是一個有前途的想法,還是還有其他可行的方法? 謝謝!
看起來像:
// maybe not all includes are necessary
#include <iostream>
#include <fstream>
#include <string>
#include <errno.h>
#include <sys/stat.h> // mkdir
#include <stdlib.h> // system()
#include <unistd.h> // rmdir
#include <cstring> // memset
// wait:
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;
int main() {
char target[] = "./hello.py";
enum PIPE_FILE_DESCRIPTERS {
READ_FD = 0, WRITE_FD = 1
};
enum CONSTANTS {
BUFFER_SIZE = 100
};
int parentToChild[2];
int childToParent[2];
pid_t pid;
string dataReadFromChild;
char buffer[BUFFER_SIZE + 1];
memset(buffer,0x00,BUFFER_SIZE + 1);
ssize_t readResult;
int status;
int retPipe1 = pipe(parentToChild);
int retPipe2 = pipe(childToParent);
switch (pid = fork()) {
case -1:
printf("Fork failed");
exit(-1);
case 0: /* Child will start scripts*/
{
// Bending stdin/out to the pipes?
int retdup21 = dup2(parentToChild[READ_FD], STDIN_FILENO);
int retdup22 = dup2(childToParent[WRITE_FD], STDOUT_FILENO);
int retdup23 = dup2(childToParent[WRITE_FD], STDERR_FILENO);
// Close in this Process the other sides of the pipe
int retclose1 = close(parentToChild[WRITE_FD]);
int retclose2 = close(childToParent[READ_FD]);
int retexe = execlp( target ," "); // warning not enough variable arguments to fit a sentinel [-Wformat=]
printf("This line should never be reached!!!"); // why? what happens if execlp finishes?
exit(-1);
break; // to make the compiler happy =)
}
default: /* Parent */
cout << "Child " << pid << " process running..." << endl;
// close the other ends of the pipe from the other process.
int retdup21 = close(parentToChild[READ_FD]);
int retdup22 = close(childToParent[WRITE_FD]);
// readtry
while (true) {
switch (readResult = read(childToParent[READ_FD], buffer, 1)) // execution does not return from this function.
{
case 0: /* End-of-File, or non-blocking read. */
{
cout << "End of file reached..." << endl << "Data received was (" << dataReadFromChild.size() << "):" << endl
<< dataReadFromChild << endl;
cout << "starting writing" << endl;
char bufferW[] = "{\"AElement\":\"Something\"}\0";
int writeResult = write(parentToChild[WRITE_FD],bufferW,sizeof(bufferW));
int saveerrno = errno;
if( -1 == writeResult)
{
cout << "errno while writing: " << errno << std::endl;
if ( 9 == saveerrno )
cout << "Errno Bad File descriptor" << endl;
}
cout << "Write Result: " << writeResult << std::endl;
int retWait = waitpid(pid, &status, 0);
cout << endl << "Child exit staus is: " << WEXITSTATUS(status) << endl << endl;
exit(0);
}
case -1:
{
if ((errno == EINTR) || (errno == EAGAIN)) {
errno = 0;
break;
} else {
printf("read() failed");
exit(-1);
}
}
default:
dataReadFromChild.append(buffer, readResult);
printf("%s",buffer);
memset(buffer,0x00,BUFFER_SIZE + 1);
break;
}
} /* while ( true ) */
} /* switch ( pid = fork() )*/
}
您的問題是緩沖輸出,未關閉的文件描述符以及使用EOF表示傳輸的一部分結束。 前兩個問題可以解決,但最后一個需要不同的方法。 以后再說。
一步步:
Python使用的是緩沖I / O,因此您可能想通過在第一個print語句之后添加sys.stdout.flush()
行來強制Python刷新輸出。 現在, "Hello!\\n"
被逐字符讀取。
但是隨后的下一個read
阻塞,直到出現新字符或管道被關閉為止。 Python腳本的STDOUT仍然打開,C ++程序正在等待到達的內容,但是Python腳本本身也在等待一些輸入。 經典僵局。
您可能會丟棄python腳本中的最后一個打印,然后嘗試關閉其STDOUT。 由於read
阻塞,直到所有引用管道寫入端的文件描述符都被關閉,因此在flush
之后,您將不得不添加os.close(sys.stdout.fileno())
和os.close(sys.stdout.fileno())
。
但是仍然有有效的文件描述符引用該管道的寫入部分。 還記得C ++源代碼中的dup2
嗎? 在這三行dup2
行之后,仍然有parentToChild[READ_FD]
和childToParent[WRITE_FD]
引用腳本STDIN和STDOUT。 因此,我們必須關閉它們。 添加close(parentToChild[READ_FD]);
並close(childToParent[WRITE_FD]);
在dup2
之后。 現在,當Python腳本關閉STDOUT和STDERR時, read
返回0
。
接下來,父級發送"{\\"AElement\\":\\"Something\\"}\\0"
並到達waitpid
,當孩子退出時, waitpid
返回。 但是孩子仍然在讀STDIN。 因此,您必須添加close(parentToChild[WRITE_FD]);
在waitpid
之前。
現在是概念部分:在它返回0
(管道關閉)之前,您不能read()
),然后繼續從該關閉的管道讀取。 您的選擇:
順便說一句: execlp
的參數是const char *file, const char *arg, ...
,其中arg, ...
是通常的char *args[]
以arg[0]
(!)開頭,以空指針結尾。 請將該行更改為int retexe = execlp(target, target, (char*) NULL);
#!/usr/bin/python2.7
import os
import sys
print "Hello!"
sys.stdout.flush()
os.close(sys.stdout.fileno())
os.close(sys.stderr.fileno())
data = sys.stdin.read()
with open("data_received_by_child.txt", "w") as fp:
print >>fp, data
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <sys/wait.h>
#include <unistd.h>
using namespace std;
int main()
{
const char *target = "./hello.py";
enum PIPE_FILE_DESCRIPTERS {
READ_FD = 0, WRITE_FD = 1
};
/* Make pipes */
int parentToChild[2]; /* Parent to child pipe */
if (pipe(parentToChild) < 0)
{
perror("Can't make pipe");
exit(1);
}
int childToParent[2]; /* Child to parent pipe */
if (pipe(childToParent) < 0)
{
perror("Can't make pipe");
exit(1);
}
/* Create a child to run command. */
pid_t pid = fork();
switch (pid)
{
case -1:
perror("Can't fork");
exit(1);
case 0: /* Child */
close(parentToChild[WRITE_FD]);
close(childToParent[READ_FD]);
dup2(parentToChild[READ_FD], STDIN_FILENO);
dup2(childToParent[WRITE_FD], STDOUT_FILENO);
close(parentToChild[READ_FD]);
close(childToParent[WRITE_FD]);
execlp(target, target, (char *) NULL);
perror("Can't execute target");
exit(1);
default: /* Parent */
close(parentToChild[READ_FD]);
close(childToParent[WRITE_FD]);
cout << "Child " << pid << " process running..." << endl;
}
/* Read data from child */
string dataReadFromChild;
char ch;
int rc;
while ((rc = read(childToParent[READ_FD], &ch, 1)) != 0)
{
if (rc == -1) {
if ((errno == EINTR) || (errno == EAGAIN)) {
continue;
}
perror("read() failed");
exit(-1);
}
dataReadFromChild += ch;
}
close(childToParent[READ_FD]);
cout << "End of file reached..." << endl;
cout << "Data received was (" << dataReadFromChild.size() << "):" << endl;
cout << dataReadFromChild << endl;
/* Write data to child */
cout << "starting writing" << endl;
const char bufferW[] = "{\"AElement\":\"Something\"}\0";
while (true) {
int rc = write(parentToChild[WRITE_FD], bufferW, sizeof(bufferW));
if (rc == -1) {
if ((errno == EINTR) || (errno == EAGAIN)) {
continue;
}
perror("write() failed");
exit(-1);
}
break;
}
close(parentToChild[WRITE_FD]);
/* Wait for child to exit */
int status;
int retWait = waitpid(pid, &status, 0);
cout << endl << "Child exit status is: " << WEXITSTATUS(status) << endl << endl;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.