好吧,我正在一个使用 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
成员进行数据指针和长度计算您对接收到的单词的处理取决于您自己。我对此进行了修改,以便在重置之前将其发送到标准输出。我认为您可能有替代计划,但这与问题无关。
见下文。根据需要进行调整:
#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;
}
测试
我通过此发送的文字文件是比利·莎士比亚(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缓冲多于一个字符(需要一些额外的内部管理工作),需要付出额外的工作,但我留给您发现。