1

在 C++ 中,我需要从一个主程序启动一个辅助程序,向第二个程序发送一些参数。我需要将辅助程序产生的数据返回给主程序。在这种情况下,数据恰好是一个二维 std::string 数组;我们会调用它stringArray。这很容易做到:

// snippet from Primary
std::string executionString ("./secondaryProgram arg1 arg2 arg3");
system(executionString);

我不知道该怎么做是将辅助程序产生的数据返回给主程序(没有从辅助程序写入临时文件,然后从主程序读取文件)。

换句话说,如果我能做这样的事情会很棒:

// snippet from Primary
std::string stringArray[2][3];  
stringArray = system(executionString);

我不希望有这样简单的解决方案或任何人的工作代码,任何朝着正确方向的轻推都会受到赞赏。

我不能为此目的使用套接字。我无法弄清楚如何在 std::cout 和 std::cin 之间构建适用于这种情况的管道。我唯一真正的限制是我的解决方案system()以某种方式涉及。

4

6 回答 6

0

system()不会为子进程创建管道。子进程继承父进程的标准输入、标准输出和标准错误描述符。

在 Linux 上,popen()如果您想访问孩子的标准输入或标准输出,则可以使用。

由于您必须使用system(),您可以让辅助程序将其结果存储在文件中。然后,您的主程序将在系统完成后打开该文件。有点像这样:

std::string executionString ("./secondaryProgram arg1 arg2 arg3 > output_file.txt");
system(executionString);
std::ifstream result("output_file.txt");
while( result >> str) {
  result_vector.push_back(str);
}
于 2013-02-12T19:10:59.643 回答
0

您可以使用管道进行通信。提供的链接有 linux 的示例,但它与您为 windows 编写的非常相似。

如果您需要发送可能在运行时更改的任意数据,您可以考虑序列化通过管道发送的数据并在接收器处反序列化。您可能会使用 XML、JSON 或类似Protobuf的东西。如果您使其具有人类可读性,则增加了重用组件或使用眼球标记调试正在发生的事情的机会 1

于 2013-02-12T21:05:00.210 回答
0

好吧,这就是我最终要做的。

“翻译”

#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>
#include <algorithm>
#include <cstdlib>
#include <unistd.h>

std::vector<std::string> sortTerms(int n, char* argv[]) {
  std::vector<std::string> sortedTerms (n);

  for (int i = 0; i < n; i++) {
sortedTerms[i] = argv[i+1]; // first term argv is program name
  }

  std::sort(sortedTerms.begin(),sortedTerms.end());

  return sortedTerms;
}

std::vector<std::string> splitString(int n,std::string str) {
  std::vector<std::string> stringVector (n);

  std::istringstream iss(str);

  for (int i = 0; i < n; i++) 
std::getline(iss, stringVector[i], ' ');

  return stringVector;
}

int main(int argc, char** argv) {
  const int NUM_TERMS = (argc - 1); // number of words to translate
  std::string output[NUM_TERMS][2]; // used to store a translated word alongside the English equivalent
  std::string stringBuffer; // used to start dictionary with arguments
  std::vector<std::string> stringVector (NUM_TERMS); // used as a buffer
  std::ofstream outputFile("translated.txt"); // file to write translations to
  const bool VERBOSE = true;

  stringBuffer.clear();
  stringBuffer.append("./dictionary ");

  // Sort English words and load them into output
  stringVector = sortTerms(NUM_TERMS, argv);
  for (int i = 0; i < NUM_TERMS; i++) {
output[i][0] = stringVector[i];
stringBuffer = stringBuffer.append(stringVector[i]);
stringBuffer = stringBuffer.append(" ");
  }

  int pipeStatus;
  int pipeOutput[2]; // file descriptor

  pipeStatus = pipe(pipeOutput); // create output read/write pipe ends
  if (pipeStatus < 0) {
std::cerr << "ERROR CREATING PIPE" << std::endl;
exit(1);
  }

  int pid = 0;
  pid = fork();

  if (pid == 0) { // dictionary
// Connect the pipes
dup2 (pipeOutput[1],1);

// Execute the program
system(stringBuffer.c_str());

// Close pipes
close(pipeOutput[0]);
close(pipeOutput[1]);

exit(0);
  }
  else if (pid > 0) { // Original process
char* buffer = new char[1024]; // input buffer

// Receive string from dictionary
read(pipeOutput[0],buffer,1024); // read in from output of dictionary

stringBuffer = buffer; // I'd rather work with a std::string

stringVector = splitString(NUM_TERMS, stringBuffer);
for (int i = 0; i < NUM_TERMS; i++)
  output[i][1] = stringVector[i];

// Close pipes
close(pipeOutput[0]);
close(pipeOutput[1]);

if (VERBOSE) {
  for (int i = 0; i < NUM_TERMS; i++)
    std::cout << output[i][0] << " -> " << output[i][1] << std::endl;
}

// write translationString to file
for (int i = 0; i < NUM_TERMS; i++) {
  outputFile.write(output[i][0].c_str(),output[i][0].length());
  outputFile.write(" -> ",4);
  outputFile.write(output[i][1].c_str(),output[i][1].length());
  outputFile.write("\n",1);
} 

outputFile.close();

exit(0);
  }
  else if (pid == -1) {
std::cerr << "ERROR FORKING PROCESS" << std::endl;
exit(1);
  }
  return 0;
}

“字典”

#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>

std::vector<std::string> splitString(std::string str)
{
  std::vector<std::string> stringVector (2);

  std::istringstream iss(str);

  std::getline(iss, stringVector[0], ' ');
  std::getline(iss, stringVector[1], ' ');

  return stringVector;
}

int main(int argc, char* argv[]) {  
  const int NUM_TERMS = (argc - 1);
  std::string stringBuffer;
  std::string returnString[NUM_TERMS];
  std::vector<std::string> stringVector;
  std::ifstream dictionaryFile ("./dictionary.txt");

  // There must be at least one arguement
  if (argc <= 1)
std::cout << "Nothing to translate..." << std::endl;

  for (int i = 0; i < NUM_TERMS; i++) {
while (dictionaryFile) {
  getline(dictionaryFile,stringBuffer);  
  stringVector = splitString(stringBuffer);
  if (stringVector[0] == argv[i+1]) { // wut
    returnString[i] = stringVector[1];
    break;
  }
}
  }

  // clear string buffer
  stringBuffer.clear();

  // Form translated words string
  for (int i = 0; i < NUM_TERMS; i++) {
    stringBuffer.append(returnString[i]);
    if (i < (NUM_TERMS - 1))
        stringBuffer.append(" "); // append a space after each but the last term
  }

  // print translated words
  std::cout << stringBuffer << std::endl;

  dictionaryFile.close();

  return 0;
}

“字典.txt”

Apple Apfel
Banana Banane
Blackberry Brombeere
Blueberry Heidelbeere
Cherry Kirsche
Fruit Obst
Grape Traube
Lemon Zitrone
Lime Limone
Orange Orange
Peach Pfirsich
Pear Birne
Plum Zwetschge
Raspberry Himbeere
Strawberry Erdbeere

意味着运行$ ./dictionary Apple Orange Strawberry

产生“translated.txt”

Apple -> Apfel
Orange -> Orange
Strawberry -> Erdbeere

在上交之前,我还有一些润色工作要做,但这就是要点。多谢你们!

于 2013-02-18T02:20:00.233 回答
0

Boost Interprocess应该适合你。它支持不同进程的线程之间的消息队列。

于 2013-02-12T20:50:53.777 回答
0

看看boost.interprocess。它包含许多可用于 IPC 的便携式实用程序。

如果你不想依赖boost,你可以做这样的事情。使用 C++11 模式和-pthreadGCC 选项编译。

于 2013-02-12T19:38:15.943 回答
0

为什么不将第二个进程中的相关信息写入一个文件,然后在第一个进程中读取该文件。这样做似乎很奇怪,但我认为它符合您教授的标准,至少您与我们分享的部分。

于 2013-02-12T20:42:54.273 回答