在Linux上的.NET Core中从C#获取uname发布字段

编程入门 行业动态 更新时间:2024-10-26 06:30:57
本文介绍了在Linux上的.NET Core中从C#获取uname发布字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我正在尝试在Ubuntu 18.04上运行的.NET Core 2.2中获取C#中uname -r的输出.

I'm trying to get the output of uname -r in C# in .NET Core 2.2 running on Ubuntu 18.04.

我在编写此文件时会考虑到性能,因此一直尝试使用P/Invoke来实现它.

I'm writing this with performance in mind, so have been trying to use a P/Invoke to achieve it.

uname(2) 文档指示我需要传递带有相关大小字段的结构.在玩了很多变体之后,我想到了:

The uname(2) docs indicate I need to pass a struct in with the relevant sized fields. After playing with a lot of variations, I came up with:

[StructLayout(LayoutKind.Sequential)] unsafe internal struct Utsname { public fixed byte sysname[65]; public fixed byte nodename[65]; public fixed byte release[65]; public fixed byte version[65]; public fixed byte machine[65]; } public static class Main { [DllImport("libc.so.6", CallingConvention = CallingConvention.Cdecl)] internal static extern int uname(ref Utsname buf); public static void Main(string[] args) { byte[] bs = new byte[65]; unsafe { var buf = new utsname(); uname(ref buf); Marshal.Copy((IntPtr)buf.release, bs, 0, 65); } Console.WriteLine(Encoding.UTF8.GetString(bs)); } }

这似乎可行,但是将其移入包装函数,如:

This seems to work, but moving it into a wrapper function like:

public static class Main { ... public static string GetUnameRelease() { var bs = new List<byte>(); unsafe { var buf = new utsname(); uname(ref buf); int i = 0; byte* p = buf.release; while (i < 65 && *p != 0) { bs.Add(*p); p++; i++; } } return Encoding.UTF8.GetString(bs.ToArray()); } public static void Main(string[] args) { Console.WriteLine(GetUnameRelease()); } }

似乎导致它失败.我只是不确定自己在做什么错.它默默地失败了,大概是由于段错误造成的,尽管我不确定在哪里/如何找到它.

Seems to cause it to fail. I'm just not sure what I'm doing wrong. It fails silently, presumably due to a segfault, although I'm not sure where/how to get a trace of that.

我还尝试了其他几种方法来恢复该结构.

I also tried a few other ways to get the struct back.

最简单的方法似乎是具有固定长度值的string字段(但我认为这样做会失败,因为调用方需要分配可变字段供被调用方设置):

The simplest seemed to be the string fields with fixed-length values (but I assume this fails because the caller needs to allocate mutable fields for the callee to set):

internal struct Utsname { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)] public string sysname; ... }

或简单的byte数组:

internal struct Utsname { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 65)] public byte[] sysname; ... }

在这种情况下,我认为问题出在将托管数组传递给调用时与In/Out调用约定有关.

In this case, I assume the problem is something to do with the In/Out calling convention when passing a managed array into the call.

我也尝试使用out而不是ref来简化P/Invoke,但是我得到的印象是uname()希望调用者在调用之前分配内存.

I tried using out instead of ref to simplify the P/Invoke as well, but I get the impression uname() expects the caller to allocate the memory before the call.

我也尝试使用[In]和[Out]属性,但是不确定默认值是什么或使用它们会如何改变.

I also tried using the [In] and [Out] attributes, but not sure what the defaults are or how using them would change things.

我还编写了一个小的C库来包装调用,以使调用约定更易于处理:

I also wrote a small C library to wrap the call to make the calling convention easier to handle:

#include <string.h> #include <stdlib.h> #include <sys/utsname.h> char *get_uname_release() { struct utsname buf; uname(&buf); size_t len = strlen(buf.release); char *release = malloc(len * sizeof(char)); strcpy(release, buf.release); return release; }

我用gcc -shared -o libget_uname.so -fPIC get_uname.c进行了编译,并将其放在主托管DLL的旁边.

I compiled this with gcc -shared -o libget_uname.so -fPIC get_uname.c and put it next to the main managed DLL.

只需:

public static class Main { ... [DllImport("libget_uname.so", EntryPoint = "uname_get_release", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] internal static extern string GetUnameRelease(); }

这似乎在我每次使用时都有效.

This seemed to work every time I used it.

但是我不建议在代码中包含本机库,如果可以直接P/Invoke代替的话.

But I'm averse to including a native library in code, if it might be possible to just P/Invoke directly instead.

另一个明显的简单选择是将uname coreutil称为子进程:

The other obvious simple choice would just be to call the uname coreutil as a subprocess:

public static class Main { ... public static string GetUnameRelease() { var unameProc = new Process() { StartInfo = new ProcessStartInfo() { FileName = "uname", Arguments = "-r", UseShellExecute = false, RedirectStandardOutput = true, CreateNoWindow = true } }; unameProc.Start(); unameProc.WaitForExit(); return unameProc.StandardOutput.ReadToEnd(); } }

但是我希望避免子进程的开销...也许在Linux上还不错,值得一试?

But I was hoping to avoid the overhead of a subprocess... Perhaps it's not so bad on Linux and just worth doing?

但是我现在花了一段时间研究PInvoke,所以我想知道是否有可能.

But I've spent a while looking into the PInvoke now, so I would like to know if it's possible.

所以我的问题是:

  • 从C#中从uname获取release字段的最佳(最快可靠方式)是什么?
  • 我如何可靠地在libc中P/调用uname() syscall以获取utsname结构?
  • What's the best (fastest reliable) way to get the release field from uname from C#?
  • How would I P/Invoke the uname() syscall in libc reliably to get the utsname struct back?
推荐答案

将代码移至函数时不起作用的原因是您的结构不包含domainname成员,因此在调用它破坏了您为结构分配的内存之外的内存.

The reason it is not working when you move the code to a function is that your structure does not include the domainname member, so when you call uname it is clobbering memory beyond the memory you allocated for your structure.

using System; using System.Runtime.InteropServices; [StructLayout(LayoutKind.Sequential)] unsafe internal struct Utsname { public fixed byte sysname[65]; public fixed byte nodename[65]; public fixed byte release[65]; public fixed byte version[65]; public fixed byte machine[65]; public fixed byte domainname[65]; } public static class Program { [DllImport("libc.so.6", CallingConvention = CallingConvention.Cdecl)] internal static extern int uname(ref Utsname buf); public static void Main(string[] args) { Console.WriteLine(GetUnameRelease()); } static unsafe string GetUnameRelease() { Utsname buf; uname(ref buf); return Marshal.PtrToStringAnsi((IntPtr)buf.release); } }

更多推荐

在Linux上的.NET Core中从C#获取uname发布字段

本文发布于:2023-11-16 04:28:53,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1600990.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:字段   NET   Linux   uname   Core

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!