日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

netcore实践:跨平台动态加载native组件

發布時間:2023/12/4 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 netcore实践:跨平台动态加载native组件 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

緣起netcore框架下實現基于zmq的應用。在.net framework時代,我們進行zmq開發由很多的選擇,比較常用的有clrzmq4和NetMQ。 其中clrzmq是基于libzmq的Interop包裝,

NetMQ是100%C#的zmq實現(基于AsyncIO組件)。以上兩種組件我都有過應用,孰優孰劣各有千秋,本文就不詳談了。

?

回歸正題,netcore下使用zmq首先也是想到引用上述組件,實踐后發現clrzmq暫時沒有基于netstandard或者netcore的支持,而NetMQ做的比較好,已經基于netstandard1.3進行了支持。

一番折騰,搭程序,配環境。。。而后 dotnet run ,在windows下正常呈現了zmq的各項功能。

?

于是繼續dotnet publlish,通過Wnscp拷貝到centos7下執行。立即報錯,

挺意外的,本以為NetMQ已經基于netstandard進行了支持,也應該對跨平臺進行支持。 可事實是AsyncIO的IOControl方法not supported on linux platform/

?

無奈,網上搜了會,也沒找到任何關于netcore在linux下進行zmq的相關內容, 事實上也沒有看到AsyncIO或者NetMQ有關于跨平臺支持的說明。

既然現有方式行不通那就只好自己動手了,自己操刀通過Interop包裝libzmq來實現跨平臺的zmq應用吧!

?

首先看下libzmq的組件目錄: 按x86和x64平臺分為i386文件夾和amd64文件夾,且都包含windos下的dll組件和linux下的so組件

這挺難辦了,要想做好還得考慮平臺類型 和 操作系統類型,? 還要想想 netcore里有沒有相關API提供。?

?

先是網上搜了圈,也極少有關于netcore進行平臺判斷相關內容。根據以往在framework下的經驗,直接到https://apisof.net搜索相關關鍵字

:OSPlatform

非常不錯,netcore已經提供了,同理搜索了 OSArchitecture 、DllImport 等都發現netcore1.1版本已經實現了相關api (說白了是netstandard已經實現了相關API)

?

準備就緒,直接開干,首先是平臺相關信息判斷,并加載目標組件 (具體方式請參照如下代碼)

class ZmqNative

? ? {

? ? ? ? private const string LibraryName = "libzmq";


? ? ? ? const int RTLD_NOW = 2; // for dlopen's flags

? ? ? ? const int RTLD_GLOBAL = 8;

? ? ? ? [DllImport(@"libdl")]

? ? ? ? static extern IntPtr dlopen(string filename, int flags);

? ? ? ? [DllImport("libdl")]

? ? ? ? protected static extern IntPtr dlsym(IntPtr handle, string symbol);



? ? ? ? [DllImport("kernel32.dll")]

? ? ? ? static extern IntPtr LoadLibrary(string filename);


? ? ? ? private static IntPtr LibPtr = IntPtr.Zero;

? ? ? ? static ZmqNative()

? ? ? ? {

? ? ? ? ? ?

? ? ? ? ? ? Console.WriteLine("OSArchitecture:{0}",RuntimeInformation.OSArchitecture);

? ? ? ? ? ? try {

? ? ? ? ? ? ? ? var libPath = @"i386";

? ? ? ? ? ? ? ? if (RuntimeInformation.OSArchitecture == Architecture.X86)

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? libPath = @"i386";

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? else if (RuntimeInformation.OSArchitecture == Architecture.X64)

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? libPath = @"amd64";

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? else

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? Console.WriteLine("OSArchitecture not suported!");

? ? ? ? ? ? ? ? }


? ? ? ? ? ? ? ? if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? var libName = $"{AppContext.BaseDirectory}\\{libPath}\\{LibraryName}.dll";

? ? ? ? ? ? ? ? ? ? Console.WriteLine("windows:{0}", libName);

? ? ? ? ? ? ? ? ? ? LibPtr = LoadLibrary(libName);

? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? var libName = $"{AppContext.BaseDirectory}/{libPath}/{LibraryName}.so";

? ? ? ? ? ? ? ? ? ? Console.WriteLine("linux:{0}", libName);

? ? ? ? ? ? ? ? ? ? LibPtr = dlopen(libName, RTLD_NOW|RTLD_GLOBAL);


? ? ? ? ? ? ? ? ? ??

? ? ? ? ? ? ? ? ? ? if(LibPtr!=IntPtr.Zero)

? ? ? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? ? ? var ptr1 = dlsym(LibPtr, "zmq_ctx_new");

? ? ? ? ? ? ? ? ? ? ? ? context = Marshal.GetDelegateForFunctionPointer<ZmqContext>(ptr1) ;


? ? ? ? ? ? ? ? ? ? ? ? var ptr2 = dlsym(LibPtr, "zmq_socket");

? ? ? ? ? ? ? ? ? ? ? ? socket = Marshal.GetDelegateForFunctionPointer<ZmqSocket>(ptr2);


? ? ? ? ? ? ? ? ? ? ? ? var ptr3 = dlsym(LibPtr, "zmq_connect");

? ? ? ? ? ? ? ? ? ? ? ? connect = Marshal.GetDelegateForFunctionPointer<ZmqConnect>(ptr3);


? ? ? ? ? ? ? ? ? ? }

? ? }

? ? ? ? ? ? ? ? else

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? Console.WriteLine("OSPlatform not suported!");

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? if (LibPtr != IntPtr.Zero)

? ? ? ? ? ? ? ? ? ? Console.WriteLine("load zmqlib success!");

? ? ? ? ? ? }

? ? ? ? ? ? catch(Exception ex)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? Console.WriteLine("load zmqlib error:\r\n{0}",ex);

? ? ? ? ? ? }

? ? ? ? }


? ? ? ? public delegate IntPtr ZmqContext();


? ? ? ? [DllImport(LibraryName, EntryPoint = "zmq_ctx_new", CallingConvention=CallingConvention.Cdecl)]

? ? ? ? public static extern IntPtr zmq_ctx_new();

? ? ? ? public static ZmqContext context = null;



? ? ? ? public delegate IntPtr ZmqSocket(IntPtr context, Int32 type);

? ? ? ? [DllImport(LibraryName, EntryPoint = "zmq_socket", CallingConvention = CallingConvention.Cdecl)]

? ? ? ? public static extern IntPtr zmq_socket(IntPtr context, Int32 type);

? ? ? ? public static ZmqSocket socket = null;



? ? ? ? public delegate Int32 ZmqConnect(IntPtr socket, IntPtr endpoint);

? ? ? ? [DllImport(LibraryName, EntryPoint = "zmq_connect", CallingConvention = CallingConvention.Cdecl)]

? ? ? ? public static extern Int32 zmq_connect(IntPtr socket, IntPtr endpoint);

? ? ? ? public static ZmqConnect connect = null;



? ? ? ? [DllImport(LibraryName, EntryPoint = "zmq_errno", CallingConvention = CallingConvention.Cdecl)]

? ? ? ? public static extern Int32 zmq_errno();


? ? ? ? [DllImport(LibraryName, EntryPoint = "zmq_strerror", CallingConvention = CallingConvention.Cdecl)]

? ? ? ? public static extern IntPtr zmq_strerror(int errnum);

? ? }

以上為測試代碼,請自動忽略代碼質量!

?

簡單解釋下,如上代碼通過平臺判斷,動態加載組件,采用LoadLibaray的方式。?有心的同學可能會發現幾個delegate并且在Linux部分內通過dlsym獲取了函數指針,具體原因下面會講。

?

以上測試代碼,在windows平臺下同樣正常無誤, 而在linux下還是遇到幾個小坑~~容我慢慢道來:

1、通過DllImport進行Interop的時候,組件路徑必須是確定的,這就引起了如何動態加載不同目錄下組件的問題;

??? 好在windows平臺下通過LoadLibaray加載dll到進程空間后,DllImport標記的函數就從進程空間查找,不會重復import組件了。

?? 而同樣的原理在linux下用dlopen卻不能實現,還是會提示找不到組件

?

2、初次部署centos7上時,報找不到libdl.so組件問題,主要原因是系統下沒有glibc的原因,該問題可以通過yum安裝glibc的方式解決;

?

//先查找系統內是否存在組件$ sudo find / -name libdl*//如不存在則安裝glibc#
yum install glibc#安裝完畢后進行鏈接 $ sudo ln -s /usr/lib64/libdl.so.2 /usr/lib64/libdl


3、解決了libdl組件問題后,繼續運行還是會發現報找不到libzmq組件的問題,實際就產生了問題1中所描述的,在linux系統下dlopen后,Interop過的函數并不會從進程空間查找。?

?

為了解決上面遇到的問題,我們還有一條辦法,就是創建 delegate , 并且通過LoadLibaray組件后通過GetProcAddress方式獲取函數指針了。? 具體的解決方案在上述測試代碼已經體現了,這里就不過多解釋了。

?

以上,就全部解決了在 netcore框架基礎上進行跨平臺native組件應用的問題。 真實測試結果如圖:

?

請主動忽略初zmq應用外的其他信息, 本次測試一同測試了通過App入口啟動webapi +? websockets + zmq ,api創建為aspnetcore在Web.dll內,websockets在Lib.dll內,zmq在App.dll內。

原文地址:http://www.cnblogs.com/cxwx/p/6726441.html


.NET社區新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關注

總結

以上是生活随笔為你收集整理的netcore实践:跨平台动态加载native组件的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。