从管道创建(或传递)字符串

时间:2014-03-05 05:49:01

标签: c++ c

好吧,我正在开发一个“简单”的项目,即使用forks和piping来搜索文件以查找给定单词的出现次数。该程序以一种方式分叉该过程,其中父母一次向孩子发送一个单词给孩子,然后搜索文件并总结所传递单词的出现。我的问题是我不熟悉C ++,因此很难弄清楚如何从字符串中取出字符串。程序当前正在通过管道传递单词,但它们仅在运行时作为一长串字符出现。任何人都可以提供一些示例或提示,以检索字符串而不是单个字符?这是我现在的代码:

int main (int argc, char * argv[]) {

fstream fileWell ("well.txt");
fstream fileWords ("words.txt");

int pipefd[2];
int counter = 0;
pid_t cpid;
char buf;
const char * sentWord;
string toCheck;
string toSend;

pipe(pipefd);
cpid = fork();

if (cpid == -1) {
    cout << "ERROR" << endl;
    exit(1);
}

if (cpid == 0) {
    close(pipefd[1]);
        while (read(pipefd[0], &buf, 1) > 0)
            write(1, &buf, 1);
        cout << endl;
        write(1, "\n", 1);
}

else {
    while (getline(fileWords, toSend)) {
        close(pipefd[0]);
        sentWord = toSend.c_str();
        write(pipefd[1], sentWord, strlen(sentWord));
    }
    close(pipefd[0]);
    toSend = "-1";
    sentWord = toSend.c_str();
    write(pipefd[1], sentWord, 3);
    close(pipefd[1]);
    wait(NULL);
    exit(EXIT_SUCCESS);
}
return 0;
}

我觉得一旦拿到琴弦就知道该怎么办,但如果没有这一部分我就无法前进。感谢您提出任何建议或帮助。

1 个答案:

答案 0 :(得分:2)

拉出未使用的数据并专注于功能代码的目的,我相当确定以下是您至少要完成的任务。一些已经解决的问题。

  • 输入文件流未打开,除非仅在父进程上。
  • 修复了管道手柄上的多个闭合。
  • 使用std:string成员进行数据指针和长度计算
  • 确保字符串终结符已作为数据包的一部分发送。
  • 将孩子的终结者视为完成字符串的信号。

您对收到的词语所做的取决于您自己。我调整了这个,只是在重置之前将它们发送到标准输出。我觉得你可能有其他计划,但这与这个问题有点无关。

见下文。根据需要进行调整:

#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
#include <unistd.h>
using namespace std;

#define READ_FD     0
#define WRITE_FD    1

int main (int argc, char * argv[])
{
    int fd[2];
    pid_t cpid;

    pipe(fd);
    if ((cpid = fork()) == -1)
    {
        cout << "ERROR" << endl;
        exit(1);
    }

    // child process
    if (cpid == 0)
    {
        // don't need the write-side of this
        close(fd[WRITE_FD]);

        std::string s;
        char ch;
        while (read(fd[READ_FD], &ch, 1) > 0)
        {
            if (ch != 0)
                s.push_back(ch);
            else
            {
                std::cout << s << '\n';
                s.clear();
            }
        }

        // finished with read-side
        close(fd[READ_FD]);
    }

    // parent process
    else
    {
        // don't need the read-side of this
        close(fd[READ_FD]);

        fstream fileWords ("words.txt");
        string toSend;
        while (fileWords >> toSend)
        {
            // send word including terminator
            write(fd[WRITE_FD], toSend.c_str(), toSend.length()+1);
        }

        // finished with write-side
        close(fd[WRITE_FD]);
        wait(NULL);
    }
    return EXIT_SUCCESS;
}

测试

我通过这个发送的文件是比利莎士比亚的“你喜欢它的独白,第二幕,第七场”的独白。输出的开头和结尾显示如下:

All
the
worlds
a
stage
And
all
the
men
and
women
merely
players
....
oblivion
Sans
teeth
sans
eyes
sans
taste
sans
everything

替代方案:自定义流缓冲区

另一种选择(也许你真正想要的)是调整可以与std::istream结合的流缓冲区,以便在客户端使用,类似于常规流io。我可以集合的最简单的例子是一个char-buffer streambuf,如下所示:

// adapt a single char streambuf for an input stream
class ifd_streambuf : public std::streambuf
{
protected:
    int  d_fd;
    char d_buffer[1];

public:
    ifd_streambuf(int fd) : d_fd(fd)
    {
        setg(d_buffer, d_buffer + 1, d_buffer + 1);
    };

private:
    int underflow()
    {
        if (read(d_fd, d_buffer, 1) <= 0)
            return EOF;

        setg(d_buffer, d_buffer, d_buffer + 1);
        return *gptr();
    }
};

利用此功能,可以调整上一个源列表中的客户端流程代码段,以便简单地遵循:

ifd_streambuf fdbuf(fd[READ_FD]);
std::istream inf(&fdbuf);

std::string s;
while (inf >> s)
    std::cout << s << '\n';

这是你可能习以为常的C ++风格。服务器端也需要更改,附加任何空格作为字分隔符:

while (fileWords >> toSend)
{
    write(fd[WRITE_FD], toSend.c_str(), toSend.length());
    write(fd[WRITE_FD], " ", 1);
}

需要额外的工作来调整这个streambuf来缓冲超过一个字符(一些额外的内务管理的东西),但我留下让你发现。