(上下文)我正在开发一个跨平台(Windows和Linux)应用程序,用于根据BitTorrent Sync在计算机之间分发文件。我已经在C#中创建了它,现在正在移植到C ++作为练习。
BTSync可以在API mode中启动,为此,必须启动' btsync '可执行文件将配置文件的名称和位置作为参数传递。
此时,我最大的问题是让我的应用程序处理可执行文件。我在搜索跨平台流程管理库时找到了Boost.Process,并决定尝试一下。似乎v0.5是它的最新工作版本,正如some evidence所暗示的那样,并且很多人都可以使用它。
我按如下方式实现了库(仅限相关代码):
文件: test.hpp
namespace testingBoostProcess
{
class Test
{
void StartSyncing();
};
}
文件: Test.cpp
#include <string>
#include <vector>
#include <iostream>
#include <boost/process.hpp>
#include <boost/process/mitigate.hpp>
#include "test.hpp"
using namespace std;
using namespace testingBoostProcess;
namespace bpr = ::boost::process;
#ifdef _WIN32
const vector<wstring> EXE_NAME_ARGS = { L"btsync.exe", L"/config", L"conf.json" };
#else
const vector<string> EXE_NAME_ARGS = { "btsync", "--config", "conf.json" };
#endif
void Test::StartSyncing()
{
cout << "Starting Server...";
try
{
bpr::child exeServer = bpr::execute(bpr::initializers::set_args(EXE_NAME_ARGS),
bpr::initializers::throw_on_error(), bpr::initializers::inherit_env());
auto exitStatus = bpr::wait_for_exit(exeServer); // type will be either DWORD or int
int exitCode = BOOST_PROCESS_EXITSTATUS(exitStatus);
cout << " ok" << "\tstatus: " << exitCode << "\n";
}
catch (const exception& excStartExeServer)
{
cout << "\n" << "Error: " << excStartExeServer.what() << "\n";
}
}
(问题)在Windows上,上面的代码将启动 btsync 并等待(阻止),直到进程终止(通过使用任务管理器或API&#39; s shutdown
方法),就像所希望的那样
但是在Linux上,它在启动过程后立即完成执行,好像wait_for_exit()
根本不存在,尽管 btsync 进程没有终止。
试图查看是否与 btsync 可执行文件本身有关,我用这个简单的程序替换它:
文件: Fake-Btsync.cpp
#include <cstdio>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define SLEEP Sleep(20000)
#include <Windows.h>
#else
#include <unistd.h>
#define SLEEP sleep(20)
#endif
using namespace std;
int main(int argc, char* argv[])
{
for (int i = 0; i < argc; i++)
{
printf(argv[i]);
printf("\n");
}
SLEEP;
return 0;
}
当与此程序一起使用时,我的应用程序可以根据需要运行,而不是从官方网站下载的原始 btsync 。它将阻塞20秒然后退出。
问题:所描述行为的原因是什么?我唯一能想到的是btsync
在Linux上重启。但如何确认呢?或者还有什么呢?
更新:我需要做的就是了解forking是什么以及它是如何运作的,正如在回答中所指出的那样(谢谢!)。
问题2:如果我使用系统监视器向子进程发送End
命令&#39; Fake-Btsync &#39;当我的主应用程序被阻止时,wait_for_exit()
会抛出异常说:
waitpid(2)失败:没有子进程
这是一种与Windows不同的行为,它只是简单地说&#34; ok&#34;并以状态0结束。
更新2:这些答案很棒,但并没有以我能够理解的方式完全解决问题2。我将写一个关于该问题的新问题并在此处发布链接。
答案 0 :(得分:3)
问题是你对btsync的假设。让我们开始吧:
./btsync
By using this application, you agree to our Privacy Policy, Terms of Use and End User License Agreement.
http://www.bittorrent.com/legal/privacy
http://www.bittorrent.com/legal/terms-of-use
http://www.bittorrent.com/legal/eula
BitTorrent Sync forked to background. pid = 24325. default port = 8888
那么,整个故事就在那里: BitTorrent Sync forked to background
。而已。没什么。如果您愿意,btsync --help
会告诉您通过--nodaemon
。
让我们使用测试程序--nodaemon
运行btsync
。在一个单独的子shell中,让我们在5秒后杀死子btsync
进程:
sehe@desktop:/tmp$ (./test; echo exit code $?) & (sleep 5; killall btsync)& time wait
[1] 24553
[2] 24554
By using this application, you agree to our Privacy Policy, Terms of Use and End User License Agreement.
http://www.bittorrent.com/legal/privacy
http://www.bittorrent.com/legal/terms-of-use
http://www.bittorrent.com/legal/eula
[20141029 10:51:16.344] total physical memory 536870912 max disk cache 2097152
[20141029 10:51:16.344] Using IP address 192.168.2.136
[20141029 10:51:16.346] Loading config file version 1.4.93
[20141029 10:51:17.389] UPnP: Device error "http://192.168.2.1:49000/l2tpv3.xml": (-2)
[20141029 10:51:17.407] UPnP: ERROR mapping TCP port 43564 -> 192.168.2.136:43564. Deleting mapping and trying again: (403) Unknown result code (UPnP protocol violation?)
[20141029 10:51:17.415] UPnP: ERROR removing TCP port 43564: (403) Unknown result code (UPnP protocol violation?)
[20141029 10:51:17.423] UPnP: ERROR mapping TCP port 43564 -> 192.168.2.136:43564: (403) Unknown result code (UPnP protocol violation?)
[20141029 10:51:21.428] Received shutdown request via signal 15
[20141029 10:51:21.428] Shutdown. Saving config sync.dat
Starting Server... ok status: 0
exit code 0
[1]- Done ( ./test; echo exit code $? )
[2]+ Done ( sleep 5; killall btsync )
real 0m6.093s
user 0m0.003s
sys 0m0.026s
没问题!
这应该是可移植的,并且在被杀/终止/中断时表现得更好:
#include <boost/asio/signal_set.hpp>
#include <boost/asio.hpp>
#include <iostream>
int main(int argc, char* argv[])
{
boost::asio::io_service is;
boost::asio::signal_set ss(is);
boost::asio::deadline_timer timer(is, boost::posix_time::seconds(20));
ss.add(SIGINT);
ss.add(SIGTERM);
auto stop = [&]{
ss.cancel(); // one of these will be redundant
timer.cancel();
};
ss.async_wait([=](boost::system::error_code ec, int sig){
std::cout << "Signal received: " << sig << " (ec: '" << ec.message() << "')\n";
stop();
});
timer.async_wait([&](boost::system::error_code ec){
std::cout << "Timer: '" << ec.message() << "'\n";
stop();
});
std::copy(argv, argv+argc, std::ostream_iterator<std::string>(std::cout, "\n"));
is.run();
return 0;
}
您可以测试它是否表现良好
(./btsync --nodaemon; echo exit code $?) & (sleep 5; killall btsync)& time wait
同样的测试可以用&#34;官方&#34; btsync
和&#34;假&#34; btsync
。我的linux盒子输出:
sehe@desktop:/tmp$ (./btsync --nodaemon; echo exit code $?) & (sleep 5; killall btsync)& time wait
[1] 24654
[2] 24655
./btsync
--nodaemon
Signal received: 15 (ec: 'Success')
Timer: 'Operation canceled'
exit code 0
[1]- Done ( ./btsync --nodaemon; echo exit code $? )
[2]+ Done ( sleep 5; killall btsync )
real 0m5.014s
user 0m0.001s
sys 0m0.014s