【问题标题】:getting integer value for win32 daemon state in windows and not getting current status在 Windows 中获取 win32 守护程序状态的整数值而不获取当前状态
【发布时间】:2020-07-01 16:04:32
【问题描述】:

我想创建和安装一个应该在后台运行的服务,直到它不应该暂停或停止服务。

所以我创建了以下测试脚本:

use Win32::Daemon;

my $ServicePath = 'C:\Strawberry\perl\bin\perl.exe';
my $ServiceParams = 'C:\ila\bin\ilad.pl';

my %service_info = (
    name    => 'ilad',
    display => 'intelligent Lightweight Agent (ilad)',
    path    => $ServicePath,
    description => 'ilad',
    parameters => $ServiceParams,
    service_type => SERVICE_WIN32_OWN_PROCESS,
    start_type => SERVICE_AUTO_START);

## create ilad service ##

if(Win32::Daemon::CreateService( \%service_info))
{
    print "successfully added \n";
}
else
{
    print "failed to add service: " . Win32::FormatMessage( Win32::Daemon::GetLastError()); 
}

# Tell the OS to start processing the service...
Win32::Daemon::StartService(\%service_info))

print "Waiting...\n";
# Wait until the service manager is ready for us to continue...

print "SERVICE_NOT_READY " . SERVICE_NOT_READY . "\n";
print "SERVICE_STOPPED " . SERVICE_STOPPED . "\n";
print "SERVICE_RUNNING " . SERVICE_RUNNING . "\n";
print "SERVICE_PAUSED " . SERVICE_PAUSED . "\n";
print "SERVICE_START_PENDING " . SERVICE_START_PENDING . "\n";
print "SERVICE_STOP_PENDING " . SERVICE_STOP_PENDING . "\n";
print "SERVICE_CONTINUE_PENDING " . SERVICE_CONTINUE_PENDING . "\n";
print "SERVICE_PAUSE_PENDING " . SERVICE_PAUSE_PENDING . "\n";

while( SERVICE_START_PENDING != Win32::Daemon::State() )
{
    sleep( 1 );
    print Win32::Daemon::State() . "\n";
}
print "Running...\n";
# Now let the service manager know that we are running...
Win32::Daemon::State( SERVICE_RUNNING );

# Okay, go ahead and process stuff...
unlink( glob( "c:\\temp\\*.tmp" ) );

# Tell the OS that the service is terminating...
Win32::Daemon::StopService();

我有这个:

successfully added  
Waiting...  
SERVICE_NOT_READY 0  
SERVICE_STOPPED 1  
SERVICE_RUNNING 4  
SERVICE_PAUSED 7  
SERVICE_START_PENDING 2  
SERVICE_STOP_PENDING 3  
SERVICE_CONTINUE_PENDING 5  
SERVICE_PAUSE_PENDING 6  
0  
0  
0  
0  
0  
0  
0  
0  
0  
0  
0  
0  
0  
0  
1  
1  
1  
1  
1  
1  
Terminating on signal SIGINT(2)  

因此它永远不会达到 SERVICE_RUNNING 状态并获取整数值并且不会获取当前的服务状态。

我正在使用草莓 perl。那么有人有什么想法吗?

【问题讨论】:

  • 服务参数C:\ila\bin\ilad.pl是什么?
  • 请注意这一行有语法错误:Win32::Daemon::StartService(\%service_info))) 太多,末尾缺少分号
  • 如果我在修复上面的语法错误后尝试运行它(并使用简单的测试脚本ilad.pl),我会收到以下错误:failed to add service: Access is denied.
  • 我发现我需要以管理员身份运行命令提示符,现在它会按照您的描述输出一系列1
  • @Håkon Hægland 已回答问题

标签: perl


【解决方案1】:

与您的想法相反,该服务确实运行了。问题是您没有查看服务的输出。

您正在执行只能由服务 (StartService) 在命令行脚本中执行的代码。这是错误的。

您正在执行在服务内创建服务 (CreateService) 的代码。这毫无意义。

固定:

use 5.014;
use warnings;

use FindBin qw( $RealBin $RealScript );
use Win32::Daemon;

my $log_qfn = "C:\\Users\\ikegami\\a.log";
my $service_name = 'testtest';

sub logit {
   my ($msg) = @_;
   chomp($msg);

   open(my $fh, ">>", $log_qfn)
      or warn("Can't append to logit \"$log_qfn\": $!\n"), return;

   say $fh "[$$] $msg";
}

sub install_service {
   my %service_info = (
      name        => $service_name,
      display     => 'TESTTEST',
      description => 'TESTTESTTEST',
      path        => $^X,
      parameters  => qq{"$RealBin/$RealScript" service},
   );

   if (Win32::Daemon::CreateService(\%service_info)) {
      say "Successfully added.";
   } else {
      print "Failed to add service: " . Win32::FormatMessage( Win32::Daemon::GetLastError()); 
   }
}


sub uninstall_service {
   if (Win32::Daemon::DeleteService("", $service_name)) {
      say "Successfully removed.";
   } else {
      print "Failed to remove service: " . Win32::FormatMessage( Win32::Daemon::GetLastError()); 
   }
}


sub start_service {
   system("net", "start", "testtest");
}


sub service {
   logit("SERVICE_NOT_READY "        . SERVICE_NOT_READY);
   logit("SERVICE_STOPPED "          . SERVICE_STOPPED);
   logit("SERVICE_RUNNING "          . SERVICE_RUNNING);
   logit("SERVICE_PAUSED "           . SERVICE_PAUSED);
   logit("SERVICE_START_PENDING "    . SERVICE_START_PENDING);
   logit("SERVICE_STOP_PENDING "     . SERVICE_STOP_PENDING);
   logit("SERVICE_CONTINUE_PENDING " . SERVICE_CONTINUE_PENDING);
   logit("SERVICE_PAUSE_PENDING "    . SERVICE_PAUSE_PENDING);

   logit("state = " . Win32::Daemon::State());

   Win32::Daemon::StartService();

   logit("Waiting");
   while (1) {
      my $state = Win32::Daemon::State();
      logit("state = $state");
      last if $state == SERVICE_START_PENDING;
      sleep(1);
   }

   logit("Running");
   Win32::Daemon::State( SERVICE_RUNNING );
   logit("state = " . Win32::Daemon::State());

   logit("This is the service doing stuff.");

   logit("Stopping");
   Win32::Daemon::StopService();
   logit("state = " . Win32::Daemon::State());
}


{
   @ARGV == 1
      or die("usage\n");

   my $cmd = shift(@ARGV);
   logit($cmd);
   if    ( $cmd eq 'install'   ) { install_service();   }
   elsif ( $cmd eq 'uninstall' ) { uninstall_service(); }
   elsif ( $cmd eq 'start'     ) { start_service();     }
   elsif ( $cmd eq 'service'   ) { service();           }
   else {
      die("usage\n");
   }
}

输出:

C:\Users\ikegami>a.pl install
Successfully added.

C:\Users\ikegami>type a.log
[40952] install

C:\Users\ikegami>wmic Service WHERE Name="testtest" GET Name, PathName
Name      PathName
testtest  C:\progs\sp5302-x64\perl\bin\perl.exe "C:/Users/ikegami\a.pl" service

C:\Users\ikegami>a.pl start
The TESTTEST service is starting..
The TESTTEST service could not be started.

The service did not report an error.

More help is available by typing NET HELPMSG 3534.


C:\Users\ikegami>type a.log
[40952] install
[28480] start
[39880] service
[39880] SERVICE_NOT_READY 0
[39880] SERVICE_STOPPED 1
[39880] SERVICE_RUNNING 4
[39880] SERVICE_PAUSED 7
[39880] SERVICE_START_PENDING 2
[39880] SERVICE_STOP_PENDING 3
[39880] SERVICE_CONTINUE_PENDING 5
[39880] SERVICE_PAUSE_PENDING 6
[39880] state = 0
[39880] Waiting
[39880] state = 0
[39880] state = 2
[39880] Running
[39880] state = 4
[39880] This is the service doing stuff.
[39880] Stopping
[39880] state = 1

C:\Users\ikegami>a.pl uninstall
Successfully removed.

我知道net start 说服务没有启动,但日志清楚地显示它是,所以忽略该消息。服务(故意)在启动后很快停止,以至于 net start 没有注意到或假定失败。

可以进行很多改进。

  • 记录消息to the event viewer,而不是一些任意的日志文件。
  • 出现异常时彻底停止服务。
  • 使用文档示例 5 中所示的回调。
  • 找到不使用net start 的方式启动服务。也许 Win32::Daemon 能够做到这一点。如果是这样,请使用它。如果没有,请添加支持!

【讨论】:

  • 很好的例子,它回答了我的大部分问题!一件小事:不知道使用FindBinWin32::GetFullPathName($0)获取脚本的工作目录有什么区别?
  • @Håkon Hægland,FindBin 将适用于其他系统。我不知道如何处理类似于 Windows 上的链接的东西。您可能会发布一个关于他们与符号链接 (Win32::Symlink) 硬链接 (Win32::Hardlink) 和联结(如果有不同的话)的交互的自我回答问题。需要两种类型的测试:链接到路径中的目录,以及链接到脚本本身。
  • 我发现的另一个问题:如果我尝试通过运行 net stop my_service 来停止服务,我将无法停止它。我收到错误:The requested pause, continue, or stop is not valid for this service. More help is available by typing NET HELPMSG 2191.
  • @HåkonHægland 使用文档示例 5 中的回调方法(正如我提到的应该这样做)应该可以解决该问题
  • 如何通过服务菜单停止或暂停该服务?
猜你喜欢
  • 1970-01-01
  • 2018-07-23
  • 2011-01-05
  • 1970-01-01
  • 1970-01-01
  • 2021-09-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多