(上下文)我正在开发一个跨平台(Windows和Linux)应用程序,用于基于BitTorrent Sync在计算机之间分发文件。我已经在C#中做到了,现在作为练习将其移植到C++。
BTSync可以在API mode中启动,为此,必须启动btsync可执行文件,并将配置文件的名称和位置作为参数。
此时,我最大的问题是让我的应用程序处理可执行文件。我在搜索跨平台流程管理库时发现Boost.Process,并决定尝试一下。正如some evidence所暗示的那样,似乎v0.5是它的最新工作版本,并且可以推断出有很多人在使用它。
我按如下方式实现了该库(仅相关代码):
文件: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的
shutdown
方法),就像期望的那样。但是在Linux上,尽管btsync进程没有终止,但它在启动进程后立即完成了执行,就好像根本没有
wait_for_exit()
一样。为了查看是否与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是什么以及它如何工作,正如sehe的回答所指出的(谢谢!)。
问题2:如果在我的主应用程序被阻止的情况下使用系统监视器向子进程“Fake-Btsync”发送
End
命令,则wait_for_exit()
将引发异常:这与Windows上的行为不同,在Windows上仅说“确定”并以状态0终止。
更新2: sehe的回答很好,但是并没有以我真正理解的方式解决问题2。我将为此写一个新问题,并在此处发布链接。
最佳答案
问题是您对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
可以使用“official”
btsync
和“fake” 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