[英]Is it possible to use a C++ stream class to buffer reads from a pipe?
In short, is it possible to do buffered reads from a pipe from a stream class, along the lines of what this pseudo-example describes. 简而言之,可以按照此伪示例描述的内容从流类的管道中进行缓冲读取。
Please ignore any pedantic problems you see (like not checking errors & the like); 请忽略您看到的所有问题(例如不检查错误等); I'm doing all that in my real code, this is just a pseudo-example to get across my question.
我正在用我的真实代码进行所有操作,这只是一个伪示例,可以解决我的问题。
#include <iostream> // or istream, ifstream, strstream, etc; whatever stream could pull this off
#include <unistd.h>
#include <stdlib.h>
#include <sstream>
void myFunc() {
int pipefd[2][2] = {{0,0},{0,0}};
pipe2( pipefd[0], O_NONBLOCK );
pipe2( pipefd[1], O_NONBLOCK );
if( 0 == fork() ) {
close( pipefd[0][1] );
close( pipefd[1][1] );
dup2( pipefd[0][0], stdout );
dup2( pipefd[1][0], stderr );
execv( /* some arbitrary program */ );
} else {
close( pipefd[0][0] );
close( pipefd[1][0] );
/* cloudy bubble here for the 'right thing to do'.
* Obviously this is faulty code; look at the intent,
* not the implementation.
*/
#ifdef RIGHT_THING_TO_DO
for( int ii = 0; ii < 2; ++ii ) {
cin.tie( pipefd[ii][1] );
do {
cin.readline( /* ... */ );
} while( /* ... */ );
}
#else
// This is what I'm doing now; it works, but I'm
// curious whether it can be done more concisely
do {
do {
select( /* ... */ );
for( int ii = 0; ii < 2; ++ii ) {
if( FD_SET( fd[ii][1], &rfds ) ) {
read( fd[ii][1], buff, 4096 );
if( /* read returned a value > 0 */ ) {
myStringStream << buff;
} else {
FD_CLR( fd[ii][1], &rfds );
}
}
}
} while( /* select returned a value > 0 */ );
} while( 0 == waitpid( -1, 0, WNOHANG ) );
#endif
}
}
Here's a simple example of how to use boost::file_descriptor
to work with a pipe; 这是一个简单的示例,说明如何使用
boost::file_descriptor
处理管道。 should work with sockets too, didn't test though. 也应该与套接字一起使用,虽然没有测试。
This is how I compiled it: 这是我的编译方式:
g++ -m32 -DBOOST_IOSTREAMS_NO_LIB -isystem ${BOOST_PATH}/include \
${BOOST_SRC_PATH}/libs/iostreams/src/file_descriptor.cpp blah.cc -o blah
Here's the example: 例子如下:
#include <fcntl.h>
#include <stdio.h>
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
int main( int argc, char* argv[] ) {
// if you just do 'using namespace...', there's a
// namespace collision with the global 'write'
// function used in the child
namespace io = boost::iostreams;
int pipefd[] = {0,0};
pipe( pipefd, 0 ); // If you use O_NONBLOCK, you'll have to
// add some extra checks to the loop so
// it will wait until the child is finished.
if( 0 == fork() ) {
// child
close( pipefd[0] ); // read handle
dup2( pipefd[1], FILENO_STDOUT );
printf( "This\nis\na\ntest\nto\nmake sure that\nit\nis\working as expected.\n" );
return 0; // ya ya, shoot me ;p
}
// parent
close( pipefd[1] ); // write handle
char *buff = new char[1024];
memset( buff, 0, 1024 );
io::stream<io::file_descriptor_source> fds(
io::file_descriptor_source( pipefd[0], io::never_close_handle ) );
// this should work with std::getline as well
while( fds.getline( buff, 1024 )
&& fds.gcount() > 0 // this condition is not enough if you use
// O_NONBLOCK; it should only bail if this
// is false AND the child has exited
) {
printf( "%s,", buff );
}
printf( "\n" );
}
There sure is. 肯定有。 There's an example from the book "The C++ Standard Library: a Tutorial and Reference" for how to make a std::streambuf that wraps file descriptors (like those you get from pipe()).
《 C ++标准库:教程和参考》一书中有一个示例,说明如何制作包装文件描述符(如从pipe()获得的描述符)的std :: streambuf。 From that creating a stream on top of it is trivial.
因此,在其之上创建流是微不足道的。
Edit: here's the book: http://www.josuttis.com/libbook/ 编辑:这是本书: http : //www.josuttis.com/libbook/
And here's an example output buffer using file descriptors: http://www.josuttis.com/libbook/io/outbuf2.hpp.html 以下是使用文件描述符的示例输出缓冲区: http : //www.josuttis.com/libbook/io/outbuf2.hpp.html
Also, here's an example input buffer: http://www.josuttis.com/libbook/io/inbuf1.hpp.html 另外,这是一个示例输入缓冲区: http : //www.josuttis.com/libbook/io/inbuf1.hpp.html
You'd want a stream that can be created with an existing file descriptor, or a stream that creates a pipe itself. 您想要一个可以使用现有文件描述符创建的流,或者想要一个本身创建管道的流。 Unfortunately there's no such standard stream type.
不幸的是,没有这样的标准流类型。
You could write your own or use, for example, boost::iostreams::file_descriptor . 您可以自己编写或使用,例如boost :: iostreams :: file_descriptor 。
Writing your own entails creating a subclass of basic_streambuf, and then then creating a very simple subclass of basic_i/ostream that does little more than hold your streambuf class and provide convenient constructors. 编写自己的代码需要先创建basic_streambuf的子类,然后再创建一个非常简单的basic_i / ostream子类,该子类只不过保留了streambuf类并提供了方便的构造函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.