请教一个制作NT_Service的问题
参照ACE/example中的NT_Service的例子,我写了自己的NT_Service类并且在NT_Service 的函数svc()中启动Service_Config.open()开启静态服务
----------------------------------------
int
Win_NT_Service::svc (void)
{
ACE_DEBUG ((LM_DEBUG,
"Service::svc\n"));
// As an NT service, we come in here in a different thread than the
// one which created the reactor.So in order to do anything, we
// need to own the reactor. If we are not a service, report_status
// will return -1.
if (report_status (SERVICE_RUNNING) == 0)
ACE_Reactor::instance ()->owner (ACE_Thread::self ());
ACE_Service_Config::open
(argc, argv, ACE_DEFAULT_LOGGER_KEY, 0);
ACE_STATIC_SVC_REGISTER (Service_Descriptor);
stop_ = 0;
while(!stop_) ACE_Reactor::instance ()->run_reactor_event_loop ();
// Cleanly terminate connections, terminate threads.
ACE_DEBUG ((LM_DEBUG,
"Shutting down\n"));
return 0;
}
--------------------------------------------
出现的问题是:
如果我在main函数中简单的调用NT_Service的svc()函数,则服务正常的运行
--------------------------------------------
ACE_NT_SERVICE_DEFINE (Server,
Win_NT_Service,
ACE_TEXT ("Message Service"));
int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) {
WIN_NT_SERVICE::instance ()->name (ACE_TEXT ("Server"),
ACE_TEXT ("Message Service"));
WIN_NT_SERVICE::instance ()->svc ();
return 0;
}
-------------------------------------------
然而把NT_Service对象注册到WIndows中后,在服务管理器中启动它,服务却没有启动(客户端无法连接)
并且,在windows服务管理器中选择停止也无法停止该服务,只能在进程管理器中杀死它。
----------------------------------------------------
ACE_NT_SERVICE_DEFINE (Server,
Win_NT_Service,
ACE_TEXT ("Message Service"));
int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) {
WIN_NT_SERVICE::instance ()->set_arg (argc, argv);
WIN_NT_SERVICE::instance ()->name (ACE_TEXT ("Server"),
ACE_TEXT ("Message Service"));
ofstream *output_file = new ofstream("ntsvc.log", ios::out);
if (output_file && output_file->rdstate() == ios::goodbit)
ACE_LOG_MSG->msg_ostream(output_file, 1);
ACE_LOG_MSG->open(argv,
ACE_Log_Msg::STDERR | ACE_Log_Msg::OSTREAM,
0);
ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%T (%t): Starting service.\n")));
ACE_NT_SERVICE_RUN (RMServer,
WIN_NT_SERVICE::instance (),
ret);
if (ret == 0)
ACE_ERROR ((LM_ERROR,
ACE_TEXT ("%p\n"),
ACE_TEXT ("Couldn't start service")));
else
ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("%T (%t): Service stopped.\n")));
return 0;
}
不清楚当NT_Service在windows服务管理器中被启动的时候,是不是直接调用我注册的exe,并且是指向svc()这个函数的句柄,它的调用喝平常的启动exe程序有没有什么本质的区别,以至于两种方式会产生完全不同的结果。
另外在windows管理器中选择停止服务不能结束也是很奇怪的问题,我不知道该怎么调试,因为一旦这个服务被注册到windows服务管理器中,就不能象在VC中哪样单步跟踪和命令行输出DEBUG信息了,多谢指点~~!! 你没有正确理解NT Service的概念。
NT Service程序,无非是一个console的程序,但是这个console程序,实现了NT系统规定的几个接口,比如启动、暂停、退出等等。ACE的包装很简单,那个例子也很实用,我的程序都是抄那个实例的。
你的ACE_TMAIN中,是不能直接调用处理器的svc方法的,这样只能用于调试,否则肯定无法相应NT的服务管理器的处理信号。
正确的办法,是你照抄那个实例中的CProcess并且稍加修改。
ACE\ACE_wrappers\examples\NT_Service\main.cpp,里面已经展示的很清晰了。 嗯,我照抄这个例子,只做了极少的改动,已经可以在windows服务管理中启动和停止服务。
但是最大的问题还是:使用-d(debug模式)我的服务能正确的运行,能看到debug信息,而且客户端也能正确的连接,但是一旦我用-s(以启动服务的方式启动)或者在windows服务管理中选择启动服务,客户端都不能正确的连接,查看监听的端口也不在监听中。
至少这个能说明-d下和-s启动的结果不同,请问这两种启动方式在原理上会有什么差异,而使得启动的结果不同呢?
以下是我的svc()函数,感觉是我在这里使用 ACE_Service_Config::open()启动静态注册的服务,在-s的方式下并没有被初始化,而且在停止服务的时候,ACE::fini()清理的时候出现错误,原因是我的Acceptor类并没有在Service:init()中被实例化,因此析构的时候析构到空值。
这是为什么呢?只有在-d的时候,注册的静态服务类才正确的被实例化、启动了。
我也猜想这个和reactor工作在不同的线程控件中有没有什么关系呢?却不知道怎么检测判断。
Win_NT_Service::svc (void)
{
ACE_DEBUG ((LM_DEBUG,
"Service::svc\n"));
// As an NT service, we come in here in a different thread than the
// one which created the reactor.So in order to do anything, we
// need to own the reactor. If we are not a service, report_status
// will return -1.
if (report_status (SERVICE_RUNNING) == 0)
reactor ()->owner (ACE_Thread::self ());
ACE_STATIC_SVC_REGISTER (Jabber_Room_Descriptor);
ACE_Service_Config::open
(argc, argv, ACE_DEFAULT_LOGGER_KEY, 0);
reactor ()->run_reactor_event_loop ();
// Cleanly terminate connections, terminate threads.
ACE_DEBUG ((LM_DEBUG,
"Shutting down\n"));
return 0;
}
-d 是调试状态,直接调用svc方法,肯定是你实现的有问题。我用了N次都没错过的。 我看到-d的结果就是
if (opt_debug)
{
SetConsoleCtrlHandler (&ConsoleHandler, 1);
SERVICE::instance ()->svc ();
}
else
所以说-d就是直接调用的SERVICE::instance ()->svc ();
而服务启动的代码是下面这个宏来完成的:
#define ACE_NT_SERVICE_RUN(SVCNAME, SVCINSTANCE, RET) \
ACE_TEXT_SERVICE_TABLE_ENTRY _ace_nt_svc_table = \
{ \
ACE_NT_SERVICE_ENTRY(ACE_TEXT (#SVCNAME), SVCNAME), \
{ 0, 0 } \
}; \
_ace_nt_svc_obj_##SVCNAME = SVCINSTANCE; \
_ace_nt_svc_obj_##SVCNAME->capture_log_msg_attributes (); \
ACE_OS::last_error (0); \
int RET = ACE_TEXT_StartServiceCtrlDispatcher(_ace_nt_svc_table);
这个StartServiceCtrlDispatcher()做得什么工作呢??他是告诉windows本服务的启动句柄是SERVICE::instance ()->svc ()么?
按道理说我也觉得不应该会有什么不同,只不过一个是由自身启动svc(),另一个是由windows来调用.
但确实就不正确,又不知道该怎么调试,所以很郁闷
我在静态服务启动的初始代码处放置了输出信息到文件的代码,在-d的方式下,没有任何问题,相关信息被写到文件中,但是用其他方式(没有console输出)启动服务则这段代码没有被执行,也就是ACE_Service_Config::open
(argc, argv, ACE_DEFAULT_LOGGER_KEY, 0);
这行在svc()中的代码没有被正确执行,不知为何? 难道启动静态服务在普通application中和在NT_Service有什么不同和需要注意的么?
请问你有没有和我类似的代码,也就是用ACE_Service_Config::open()启动静态或动态服务的? 可否帮我看看有什么本质差别? 你问的问题很多,其实归结到一点,你得先研究一下什么是windows service 程序,有要求。
看看MSPress-ProgrammingServer-SideApplications for MS Windows2000 郁闷了很久,居然使用MessageBeep (MB_OK);这样的代码来定位看服务是否运行了某处代码,终于解决了问题。
结果如下:我在svc.conf定义了一个静态服务对象static AAA.这个类继承自ACE_Service_Object。
它在debug的情况下被正确的实例化并且调用了挂钩函数:init (int argc,ACE_TCHAR *argv[]),在这个函数中我实例化了自己的ACCEPTOR类,并启动监听。
然而在windows服务管理器来启动服务的时候,AAA被实例化,但是这个init()函数并没有被调用,我查了一下,这个init()函数是继承自ACE_Shared_Object类,这个函数的说明是:
virtual intinit (int argc, ACE_TCHAR *argv[])
Initializes object when dynamic linking occurs.
动态连接的时候被调用?不懂具体是什么意思,启动服务为什么不会激活这个函数?
于是我把原来放在init()中的代码放到了,AAA的构造函数中,代码于是被执行了。
所以说制作一个NT_Service还是有一些需要注意的细节问题,希望大家能更多的发布经验交流。
另外发现在服务中要读取文件的话也不能使用exe的相对路径,我是暂时用的绝对路径,看能不能有获取应用程序当前路径,和系统path变量之类的方式来解决文件方便定位的问题。
NT_Service
启动服务后,关闭机器,如何kill掉此服务? 我在WIN7下直接运行NT_Service的例子,出现“Couldn't start service:服务进程无法连接到服务控制器上”的错误。这是什么原因呢? 楼上朋友,使用GetLastError()查看具体的错误代码。我估计跟权限有关系。
页:
[1]
2