gpt4 book ai didi

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

转载 作者:塔克拉玛干 更新时间:2023-11-03 06:45:38 28 4
gpt4 key购买 nike

好的,我正在做一个“简单”的项目,即使用 fork 和管道在文件中搜索给定单词的出现次数。该程序将以这样的方式 fork 进程,即 parent 一次向 child 发送一个单词,让 child 搜索文件并总结所传递单词的出现次数。我的问题是我不熟悉 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;
}

我觉得我知道一旦我得到了字符串就知道该怎么做,但没有那部分我就无法真正前进。感谢您提供任何建议或帮助。

最佳答案

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

  • 除非仅在父进程上,否则不会打开输入文件流。
  • 修复了管柄上的多个闭合问题。
  • 使用std:string成员进行数据指针和长度计算
  • 确保字符串终止符作为数据包的一部分发送。
  • 将 child 身上的终止符视为完成字符串的信号。

您如何处理收到的文字取决于您。我对此进行了调整,以便在重置之前将它们简单地发送到标准输出。我觉得您可能有其他计划,但这与问题有些无关。

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

#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;
}

测试

我通过此发送的 word 文件是比利·莎士比亚 (Billy Shakespeare) 在《如你所愿》第二幕第七场中的独白。输出的开头和结尾如下所示:

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 在客户端使用.下面是我能收集到的最简单的示例,一个字符缓冲区 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();
}
};

利用这一点,先前源代码 list 中的客户端进程代码段可以简单地适应以下内容:

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 以缓冲多个字符(一些额外的内务处理的东西),但我把它留给你去发现。

关于c++ - 从管道创建(或传递)字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22189637/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com