简体   繁体   English

如何从运行在 Linux 上的 .NET 核心应用程序关闭计算机

[英]How to shutdown computer from a .NET Core application running on Linux

I have a .net core 2.0 program running on Linux (Ubuntu Server 16.04 LTS).我有一个运行在 Linux (Ubuntu Server 16.04 LTS) 上的 .net 核心 2.0 程序。

I'm trying to shutdown the computer by invoking a process with the following command: sudo shutdown -h now , though when the program is running in the background as daemon service, the shutdown process does not work.我试图通过使用以下命令调用进程来关闭计算机: sudo shutdown -h now ,但是当程序作为守护进程服务在后台运行时,关闭进程不起作用。

Here is the code:这是代码:

var process = new Process
{
    StartInfo =
    {
        CreateNoWindow = true,
        RedirectStandardError = true,
        RedirectStandardInput = true,
        RedirectStandardOutput = true,
        UseShellExecute = false,
        FileName = Environment.GetEnvironmentVariable("SHELL"),
        Arguments = "-s"
    },
    EnableRaisingEvents = true
};

if (process.Start())
{
    process.BeginErrorReadLine();
    process.BeginOutputReadLine();
    process.StandardInput.WriteLine("sudo shutdown -h now");
}

My assumption is that the service runs as a separate session so it doesn't have any control.我的假设是该服务作为单独的 session 运行,因此它没有任何控制权。 How can I get the application to shutdown the computer when it is running as a Linux daemon?当应用程序作为 Linux 守护程序运行时,如何让应用程序关闭计算机?

I recommend changing your code to use P/Invoke to call Linux's reboot function directly, this will also give you more details if it fails.我建议更改您的代码以使用 P/Invoke 直接调用 Linux 的reboot功能,如果失败,这也会为您提供更多详细信息。

While invoking other executables to perform tasks is the convention on Unix/Linux (especially from shell scripts), .NET programs really don't fit in well and the code required is very brittle (eg as you're seeing with sudo ), especially as in the .NET world processing Standard IO ( stdin , stdout , stderr ) from other processes is very difficult.虽然调用其他可执行文件来执行任务是 Unix/Linux 上的约定(尤其是从 shell 脚本),但 .NET 程序确实不适合,并且所需的代码非常脆弱(例如,正如您在sudo看到的那样),尤其是在 .NET 世界中,处理来自其他进程的标准 IO( stdinstdoutstderr )非常困难。

internal static class NativeMethods
{
    [DllImport( "libc.so", SetLastError = true)] // You may need to change this to "libc.so.6" or "libc.so.7" depending on your platform)
    public static extern Int32 reboot(Int32 magic, Int32 magic2, Int32 cmd, IntPtr arg);

    public const Int32 LINUX_REBOOT_MAGIC1 = unchecked((int)0xfee1dead);
    public const Int32 LINUX_REBOOT_MAGIC2 = 672274793;
    public const Int32 LINUX_REBOOT_MAGIC2A = 85072278;
    public const Int32 LINUX_REBOOT_MAGIC2B = 369367448;
    public const Int32 LINUX_REBOOT_MAGIC2C = 537993216;


    public const Int32 LINUX_REBOOT_CMD_RESTART = 0x01234567;
    public const Int32 LINUX_REBOOT_CMD_HALT = unchecked((int)0xCDEF0123);
    public const Int32 LINUX_REBOOT_CMD_CAD_ON = unchecked((int)0x89ABCDEF);
    public const Int32 LINUX_REBOOT_CMD_CAD_OFF = 0x00000000;
    public const Int32 LINUX_REBOOT_CMD_POWER_OFF = 0x4321FEDC;
    public const Int32 LINUX_REBOOT_CMD_RESTART2 = unchecked((int)0xA1B2C3D4);
    public const Int32 LINUX_REBOOT_CMD_SW_SUSPEND = unchecked((int)0xD000FCE2);
    public const Int32 LINUX_REBOOT_CMD_KEXEC = 0x45584543;

    public const Int32 EPERM  =  1;
    public const Int32 EFAULT = 14;
    public const Int32 EINVAL = 22;
}

Usage:用法:

using static NativeMethods;

public static void Shutdown()
{
    Int32 ret = reboot( LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_POWER_OFF, IntPtr.Zero );

    // `reboot(LINUX_REBOOT_CMD_POWER_OFF)` never returns if it's successful, so if it returns 0 then that's weird, we should treat it as an error condition instead of success:
    if( ret == 0 ) throw new InvalidOperationException( "reboot(LINUX_REBOOT_CMD_POWER_OFF) returned 0.");

    // ..otherwise we expect it to return -1 in the event of failure, so any other value is exceptional:
    if( ret != -1 ) throw new InvalidOperationException( "Unexpected reboot() return value: " + ret );

    // At this point, ret == -1, which means check `errno`!
    // `errno` is accessed via Marshal.GetLastWin32Error(), even on non-Win32 platforms and especially even on Linux

    Int32 errno = Marshal.GetLastWin32Error();
    switch( errno )
    {
    case EPERM:
        throw new UnauthorizedAccessException( "You do not have permission to call reboot()" );

    case EINVAL:
        throw new ArgumentException( "Bad magic numbers (stray cosmic-ray?)" );

    case EFAULT:
    default:
        throw new InvalidOperationException( "Could not call reboot():" + errno.ToString() );
    }
}

Note that a successful call to reboot() will never return.请注意,成功调用reboot()将永远不会返回。

Adding that, for .net core running on the Raspberry Pi, we need to use the other answer, but follow user Tom's comment and change the DllImport to:补充一点,对于在 Raspberry Pi 上运行的 .net 核心,我们需要使用其他答案,但按照用户 Tom 的评论并将 DllImport 更改为:

[DllImport( "libc.so.6", SetLastError = true)]
public static extern Int32 reboot(Int32 cmd, IntPtr arg);

And then to power off we can call:然后关闭电源,我们可以调用:

reboot(LINUX_REBOOT_CMD_POWER_OFF, IntPtr.Zero);

Or to reboot:或者重新启动:

reboot(LINUX_REBOOT_CMD_RESTART, IntPtr.Zero);

This works on AWS EC2 with Ubuntu Server, used in daemon.这适用于带有 Ubuntu 服务器的 AWS EC2,用于守护进程。 Tested only there, may work also elsewhere.只在那里测试过,也可能在其他地方工作。

Process process = new Process();
process.StartInfo.FileName = "/usr/bin/sudo";
process.StartInfo.Arguments = "/sbin/shutdown -h now";
process.Start();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么和如何RabbitMQ .NET Core客户端导致应用程序关闭 - Why and how RabbitMQ .NET Core client causes the application shutdown 如何使用.Net Core从远程计算机,同一网络,linux获取mac-address - How to get mac-address from a remote computer, same network, at linux, using .Net Core 如何从Windows服务关闭远程计算机 - How to shutdown a remote computer from a windows service .NET Core 3.1 - linux 容器中的工作器服务:干净关闭 - .NET Core 3.1 - Worker Service in linux container: Clean Shutdown 在 .NET Core 2 linux 守护进程中优雅地关闭通用主机 - Gracefully shutdown a generic host in .NET Core 2 linux daemon 如何从在 Linux(docker 容器)上运行的 c#.net 核心在远程 Windows 网络路径上运行 .exe - How to run .exe on remote windows network path from c# .net core running on Linux (docker container) 无法在从 .NET Core 运行的 linux 命令中设置输入文件 - Not possible to set input file in linux command running from .NET Core 如何使用 c# windows 窗体应用程序制作计时器以关闭计算机 - How to make a timer to shutdown computer with c# windows form application 如何强制更新/防止在 Linux 上运行并由 nginx 反向代理服务器托管的 .NET Core Web 应用程序的 HTML 缓存 - How to force updates / prevent HTML caching of .NET Core web application running on Linux and hosted by an nginx reverse proxy server 如何从 ASP.NET 创建 PID 文件 Linux 下的核心应用 - How to create PID file from ASP.NET Core application under Linux
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM