gpt4 book ai didi

c# - 如何从 Linux 上运行的 .NET Core 应用程序关闭计算机

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:35:11 25 4
gpt4 key购买 nike

我有一个在 Linux (Ubuntu Server 16.04 LTS) 上运行的 .net core 2.0 程序。

我试图通过使用以下命令调用进程来关闭计算机:sudo shutdown -h now,尽管当程序作为守护程序服务在后台运行时,关闭进程确实不行。

代码如下:

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");
}

我的假设是该服务作为单独的 session 运行,因此它没有任何控制权。当应用程序作为 Linux 守护进程运行时,如何让应用程序关闭计算机?

最佳答案

我建议更改您的代码以使用 P/Invoke 直接调用 Linux 的 reboot 函数,如果失败,这也会为您提供更多详细信息。

虽然调用其他可执行文件来执行任务是 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;
}

用法:

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() );
}
}

请注意,对 reboot() 的成功调用将永远不会返回。

关于c# - 如何从 Linux 上运行的 .NET Core 应用程序关闭计算机,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50141260/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com