2016-04-17 9 views
0

私のC++コードからpythonスクリプトを呼び出したいと思います。 Pythonスクリプトは次のようになります。C++は(bash、python ...)スクリプトを開始し、stdin/stdoutを使ってデータトランスファ[Linux]

hello.py 
    #!/usr/bin/python 
    import sys 
    print "Hello!" 
    Readin = sys.stdin.read() 
    print Readin 

C++コードはスタックオーバーフローの他の質問です。どのように動作する必要がありますか:

  • パイプのペアを作成します。

  • fork()で子プロセスを作成します。

  • はパイプをstdin/stdoutに曲げています。他の端を閉じて とスクリプトを開始する。

  • 父系は、入力を受け取るパイプread()で聞いています。その後、 メッセージを送信write()switch (readResult = read(childToPa...が入力されたときに

プログラムは、父親ラインから戻りません。

また、この書き込み部分が仕事をしているかどうかもわかりません。このようなことをするのは有望なアイデアですか、それとも他の可能性がありますか? thx!

のように見えます:

// 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())*/ 
} 
+0

にその行を変更してください、どのようにそれはあなたが他のプログラム内のPythonコードを実行することを関連していますか?答え:そうではありません。したがって、コードや質問を簡単に減らし、最小限の例に近づけることができます。しかし、それでも私はあなたがそのアプローチのアイディアをどこから得たのだろうか?それは新しいものではなく、ユニークではなく、実際に確立されています。だから、既存の実用的な例を見つけるのは簡単なことです! –

+0

@Ulrich EckhardtアセンブリにはC++コアがあります。これはジョブの入力を取得しています。コアはこの仕事を準備しており、データベースを更新しています。この後、仕事はpythonによって行われます。コアは将来も残るでしょう。しかし、今後の仕事の種類は変わります。そこで私たちはこれを行う簡単な方法を探しました。 APIを使用してスクリプトファイル名を入力 - > C++の準備 - > Pythonがやっている。これを成し遂げるには良い方法がありますか?私はプログラマーであり、このハックを使うのは好きではありません。これらのスクリプトは互いに呼び出すことができるべきであるため、stdin/put方法が提案されました。より良いアイデア? Thx =) –

答えて

1

あなたの問題は、出力、閉じていないファイルディスクリプタをバッファリングし、送信の一部の終わりを知らせるためにEOFを使用しています。最初の2つの問題は解決できますが、最後の問題は別のアプローチが必要です。それについては後で詳しく説明します。ステップバイ

ステップ:

Pythonは、バッファI/Oを使用しているので、あなたは、最初のprint文の後にラインsys.stdout.flush()を追加することで、出力をフラッシュするのPythonを強制することもできます。今すぐ"Hello!\n"が1文字ずつ読み込まれます。

しかし、次のreadは、新しい文字が到着するかパイプが閉じられるまでブロックします。 PythonスクリプトのSTDOUTはまだ開いていますが、C++プログラムは何かが到着するのを待っていますが、Pythonスクリプト自体も入力を待っています。古典的なデッドロック。

pythonスクリプトの最後の印刷を破棄し、そのSTDOUTを閉じることがあります。 readブロック以降、パイプの書き込み側を参照するすべてのファイル記述子が閉じられるまで、flushの後ろにos.close(sys.stdout.fileno())os.close(sys.stdout.fileno())を追加する必要があります。

しかし、そのパイプの書き込み部分を参照している有効なフィールド記述子があります。 C++ソースにdup2を覚えていますか?これらの3つのdup2行の後には、まだparentToChild[READ_FD]childToParent[WRITE_FD]がスクリプトSTDINとSTDOUTを参照しています。だから我々はそれらを閉じなければならない。 dup2の直後にclose(parentToChild[READ_FD]);close(childToParent[WRITE_FD]);を追加します。今度はreadは、PythonスクリプトがSTDOUTとSTDERRを閉じるときに0を返します。

次に、親は"{\"AElement\":\"Something\"}\0"を送信し、子が終了すると返されるwaitpidになります。しかし子供はまだSTDINから読んでいる。したがってwaitpidの前にclose(parentToChild[WRITE_FD]);を追加する必要があります。今概念パートの


:することはできませんread()それは0(パイプを閉じた状態)を返し、その後、その閉じられたパイプから読み続けるまで。あなたの選択:

  • パイプが閉じられるまで一度だけ読んでください。 2番目のメッセージはありません。
  • どれくらい読むかを知る。あらかじめまたは受信したバイトを解釈することによって。
  • 両方のパイプを監視します。 poll(2)と入力し、読み書きするかどうかを動的に決定します。

ところで:(!)execlpの引数はarg, ...arg[0]で始まり、NULLポインタで終わるchar *args[]いつもあるconst char *file, const char *arg, ...、です。 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; 
} 
+0

これらの情報がありがとう、私がやったすべてのエラーを指摘してくれてありがとう。私は数日でそれらの人たちで働くでしょう。詳細については、このトピックを参照してください。プログラム通信、パイプ、外部プログラムとゾンビの開始。あなたは良い本の名前、またはいくつかのキーワード、私の検索を開始する場所を教えてもらえますか? –

+0

POSIXレベルとLinuxプログラミングのベストセラーは、Michael Kerriskの "The Linux Programming Interface"です。私はDonald Lewineの "POSIX Programmer's Guide"(1991年に発行され、現在は無料で利用可能です)も好きです。しかし、私の最も重要なリファレンスはmanページです。 – Yurim

+0

**ありがとうございました!**トピックの最初の反復については、本が好きです。より多くの質問のためにマンページを楽しむことができるよりも。 –

関連する問題