26 Mart 2018 Pazartesi

process child Sınıfı asio::buffer Kullanarak Çıktıyı Okumak

Giriş
Asenkron olarak uygulamayı çalıştırır. Belirtilen buffer kadar okur. Eğer çıktı buffer'dan büyükse çıktının gerisi kırpılır. Bu örneklerde async_pipe kullanılmıyor ve daha kolay. Açıklaması şöyle
async_pipe with async_read only reads until the buffer is full or EOF is reached. If the child process outputs more than the buffer size (8k in your sample) then it will get stuck and never finish.
Burada buffer küçük olduğu için takılma olmayacağını yani uygulamalar arası pipe'ın otomatik kapatıldığı için çalıştırılan uygulamanın düzgünce çıktığını düşünüyorum.

buffer olarak std::array std::vector kullanılabilir.

Örnek
Şöyle yaparız. Boost örneklerinde vector için bellek ayrılmıyor ve yanlış. Aslında ayırmak lazım.
boost::asio::io_service ios;
boost::asio::io_service::work work;
bp::async_pipe ap;
std::vector<char> buf (1024);



void read(const boost::system::error_code& ec,std::size_t size) {
  std::cout << ec << std::endl;
  std::cout << size << std::endl;
}


bp::child c(bp::search_path("ls"), ".", bp::std_out > ap);
boost::asio::async_read(ap, boost::asio::buffer(buf),
  boost::bind(&test::read,
              this,
              boost::asio::placeholders::error,
              boost::asio::placeholders::bytes_transferred));

ios.run();
Örnek
Şöyle yaparız. Çıktı std::array olduğu için büyüyemez ve 8K ile sınırlıdır.
namespace bp   = boost::process;
using Args     = std::vector<std::string>;
using Buffer8k = std::array<char, 8192>;


auto a1 = std::make_unique<Buffer8k>(),
a2 = std::make_unique<Buffer8k>();

*a1 = {};
*a2= {};

boost::asio::io_service ios;

bp::child first("/bin/echo", Args{"-n", "first"}, bp::std_out > boost::asio::buffer(*a1),
  ios);
bp::child second("/bin/echo", Args{"-n", "second"}, bp::std_out >boost::asio::buffer(*a2),
  ios);

std::cout << "Launched" << std::endl;

ios.run();
first.wait();
second.wait();

std::string const str1(a1->data()); // uses NUL-termination (assumes text output)
std::string const str2(a2->data()); // uses NUL-termination (assumes text output)

process child Sınıfı

Giriş
Şu satırı dahil ederiz.
#include <boost/process.hpp>
#include <boost/process/windows.hpp> // for windows::hide
Constructor - path + option
Örnek
Şöyle yaparız.
boost::filesystem::path p = 
  boost::process::search_path( "raspiyuv" );  // returns correct path
boost::process::child ch (p, "-w 2592 -h 1944 -o - -t 0 -y -s >> /var/tmp/myfifo" );
Constructor - command + environment + option
Açıklaması şöyle.
child constructor accepts a list of types that will be later converted using fancy ::boost::fusion methods into chain of calls performing actual initializations. So you can just push arguments of supported kind in any order:
Örnek
Şöyle yaparız.
boost::process::environment env = ::boost::this_process::environment();
boost::process::child ch ("cmd", env, ::boost::process::windows::hide); // ok
Örnek
Şöyle yaparız.
boost::process::child ch (
  boost::filesystem::path("C:\\Windows\\System32\\cmd.exe"),
  boost::process::windows::hide, env); //ok
Constructor - command + environment
Örnek
Şu macroyu tanımlarız.
#define BOOST_POSIX_HAS_VFORK 1
Şöyle yaparız.
bp::child c("ls", bp::posix::use_vfork);
Constructor - command + asio::buffer + io_service
asio::buffer Kullanımı yazısına taşıdım.

Constructor - command + asio::streambuf + io_service
Örnek
Şöyle yaparız. Burada asio::streambuf EOF karakterini görünceye kadar çıktının boyu kadar büyür.
boost::asio::io_service ios;
bp::async_pipe ap (ios);
boost::asio::streambuf buf;


void read(const boost::system::error_code &ec, std::size_t size) {
  std::cout << ec.message() << "\n";
  std::cout << size << "\n";
  std::cout << &buf << std::flush;
}

void run() {
  bp::child c(bp::search_path("ls"), ".", bp::std_out > ap, ios);

  async_read(ap, buf, boost::bind(&test::read, this, _1, _2));
  ios.run ();
}
Çıktı olarak şunu alırız.
End of file
15
a.out
main.cpp
Örnek
Şöyle yaparız. std_in'e string yazılır.
#include <iostream>
#include <boost/process.hpp>
using namespace boost::process;

int main() {
  boost::asio::io_service ios;

  std::future<std::string> outdata;
  std::future<std::string> errdata;

  child c("/bin/cat",
          std_out > outdata,
          std_err > errdata,
          std_in < "main.cpp", ios);

  ios.run();
  std::cout << "stdout: " << outdata.get() << std::endl;
  std::cerr << "stderr: " << errdata.get() << std::endl;
}
Şu komut ile aynıdır.
cat main.cpp
Örnek
Şöyle yaparız. std_in'e yazmak için boost::process::async_pipe kullanılır.
#include <iostream>
#include <boost/process.hpp>
#include <boost/process/async.hpp>
using namespace boost::process;

int main() {
  boost::asio::io_service ios;

  std::future<std::string> outdata;
  std::future<std::string> errdata;

  async_pipe in(ios);
  child c("/bin/cat",
          std_out > outdata,
          std_err > errdata,
          std_in < in, ios);

  std::string greeting("hi, there!");
  boost::asio::async_write(in, buffer(greeting), [&](boost::system::error_code, size_t) {
    in.close();
  });

  ios.run();
  std::cout << "stdout: '" << outdata.get() << "'\n";
  std::cerr << "stderr: '" << errdata.get() << "'\n";
}
Şu komut ile aynıdır.
echo "hi, there" | cat
Çıktı olarak şunu alırız.
stdout: 'hi, there!'
Constructor - command + future + io_service
Şöyle yaparız.
struct BProcess {
  BProcess(boost::asio::io_service& svc) : ios(svc) {}

  void Execute(std::string const& sfilename) {
    namespace bp = boost::process;
    child_process = bp::child(sfilename, bp::std_out > output, ios);
  }

  boost::asio::io_service& ios;
  boost::process::child child_process;
  std::future<std::string> output;
};
Örnek
Şöyle yaparız.
boost::asio::io_service ios;
std::future<std::vector<char>> output;
boost::process::child c("hostname.exe",
        boost::process::std_out > output,
        boost::process::std_err > boost::process::null,
        ios);
ios.run();
c.wait();
if (output.valid())
{
  auto processOutput = output.get();
  processOutput.push_back('\0');
  printf(processOutput.data());
}
Constructor - command + stream
Şöyle yapmak mümkün.
bool redirect = true; // or false
bp::ipstream out;
bp::child c("c++filt", (redirect) ? std_out > out : "what should I put here??" );
Constructor - command + arguments + stream
Örnek
Şöyle yaparız.
void runProcess( const std::string& exe, const std::vector<std::string>& args )
{
  bp::ipstream out;
  bp::child ch (exe, args, std_out > out);
    ...
}
Constructor - command + environment + stream
Environment ile Windows'ta komutun "cmd.exe /c" ile başlatılmasını sağlar.

Örnek
Şöyle yaparız. Başlatılan uygulamanın akımlarını belirtilen stream'lere yönlendiririz.
bp::opstream inStream ;
bp::ipstream outStream;
bp::ipstream errStream;

bp::child child(
  command, // the command line
  bp::shell,
  bp::std_out > outStream,
  bp::std_err > errStream,
  bp::std_in  < inStream);
Yanlış Kullanım
Açıklaması şöyle
This will also deadlock, because the pipe does not close when the subprocess exits. So the ipstream will still look for data even though the process has ended.
Şu kod yanlış. Başlatınlan uygulamanın pipe'ı kapatacağını beklemeyin diyor.
#include <boost/process.hpp>

#include <iostream>

namespace bp = ::boost::process;

int main(void)
{
  bp::ipstream is;
  bp::child c("ls", bp::std_out > is);

  std::string line;
  while (std::getline(is, line))
  {
    std::cout << line << "\n";
  }

  return 0;
}
exit_code metodu
Şöyle yaparız.
int exitCode = ch.exit_code();
id metodu
Şöyle yaparız.
boost::process::child ch = ...;
int pid = ch.id();
running metodu
Şöyle yaparız.
bool running() const { return child.running(); }
wait metodu
Şöyle yaparız.
ch.wait();