Skip to content

Instantly share code, notes, and snippets.

@alberto-santini
Created April 21, 2019 14:51
Show Gist options
  • Save alberto-santini/bd70a15ebd4eec55c2dfcd03f6e3b931 to your computer and use it in GitHub Desktop.
Save alberto-santini/bd70a15ebd4eec55c2dfcd03f6e3b931 to your computer and use it in GitHub Desktop.
Send work to a server via a pipe, and get the result again via a pipe
#include <ext/stdio_filebuf.h> // For stdio_filebuf
#include <unistd.h> // For pipe, close
#include <cstdlib> // For _Exit
#include <memory> // For unique_ptr
#include <sys/types.h> // For pid_t
#include <sys/wait.h> // For waitpid
#include <stdio.h> // For perror
#include <iostream>
#include <cassert>
#include <string>
using Buffer = __gnu_cxx::stdio_filebuf<char>;
class Pipe {
// File descriptors for each end of the pipe.
int fd[2];
public:
Pipe() {
if(::pipe(fd) != 0) {
std::cerr << "Error creating pipe.\n";
std::_Exit(1);
}
}
~Pipe() {
close();
}
void close() {
::close(readFd());
::close(writeFd());
}
int readFd() const { return fd[0]; }
int writeFd() const { return fd[1]; }
};
class ExtProcessCaller {
Pipe writePipe;
Pipe readPipe;
public:
std::unique_ptr<Buffer> writeBuffer;
std::unique_ptr<Buffer> readBuffer;
std::ostream stdIn;
std::istream stdOut;
pid_t processPid = -1;
ExtProcessCaller(const char *const argv[]) :
stdIn(nullptr),
stdOut(nullptr)
{
processPid = ::fork();
if(processPid == -1) {
std::cerr << "Could not run child process.\n";
std::_Exit(1);
}
if(processPid == 0) {
// Child process.
::dup2(writePipe.readFd(), STDIN_FILENO);
::dup2(readPipe.writeFd(), STDOUT_FILENO);
writePipe.close();
readPipe.close();
// Separate initialisation because execv only returns if
// an error occurs. In that case, it returns -1.
int result = 0;
result = ::execv(argv[0], const_cast<char *const *>(argv));
if(result == -1) {
::perror("Error in child process");
std::_Exit(1);
}
} else {
// Parent process.
::close(writePipe.readFd());
::close(readPipe.writeFd());
writeBuffer = std::make_unique<Buffer>(writePipe.writeFd(), std::ios::out);
readBuffer = std::make_unique<Buffer>(readPipe.readFd(), std::ios::in);
stdIn.rdbuf(writeBuffer.get());
stdOut.rdbuf(readBuffer.get());
}
}
void sendEof() {
assert(writeBuffer);
writeBuffer->close();
}
pid_t wait() {
pid_t status;
::waitpid(processPid, &status, 0);
return status;
}
};
inline std::string callServer(const std::string& carpInput) {
const char *const argv[] = { "./server", (const char*)0 };
ExtProcessCaller caller{argv};
caller.stdIn << carpInput << std::endl;
std::string carpOutput;
std::getline(caller.stdOut, carpOutput);
caller.sendEof();
caller.wait();
return carpOutput;
}
int main() {
// Expected "Output: 6"
std::cout << "Output: " << callServer("3") << "\n";
return 0;
}
#include <iostream>
#include <thread>
#include <chrono>
int main() {
using namespace std::chrono_literals;
int number;
if(!(std::cin >> number)) {
std::cerr << "Wrong input!\n";
return 1;
}
std::this_thread::sleep_for(5s);
std::cout << number * 2 << "\n";
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment