如何在Windows和Linux上进行跨平台PInvoke

如何在Windows和Linux上进行跨平台PInvoke,第1张

NET的程序是和Java一样的托管代码,在底层 *** 作上,具有很大的局限性,像Java的JNI一样,.NET具有Platform Invoke(平台调用,通常叫P/Invoke)。本文中,Linux下的.NET托管代码运行在Mono CLR上。之所以做跨平台的P/Invoke,是因为考虑到有些客户在Win32/WinCE等系统中开发的.NET程序,需要换到Linux平台运行。嵌入式开发中,经常需要 *** 作IO,.NET程序就通过P/Invoke来调用一些用比如c/c++一类语言开发的native代码完成IO *** 作。这时候针对windows编写的native代码,就不能不加修改的移植到Linux上,要完成这个移植工作就需要编写Linux下的native代码。但如何做到不修改.NET程序呢,下面就让笔者以实例讲述。

要保证.NET程序不加修改,不许重新编译,需要做到native代码具有一致的接口。比如我们有native.dll何libnative.so两个不同系统下的动态链接库,在.NET程序中,调用动态库中的getSum(int a,int b)函数,则需要在native.dll和libnative.so中都存在getSum(int a, int b)函数,而且导出的名字要一致,都是getSum。编译时要注意编译器对符号名称的修饰,vc编译器中,可以用Module-Defination File(.def)文件来规范到处的函数名称。

在.NET的代码中,透过DllImport引入外部函数时,指定的链接库模块不要加扩展名。比如native.dll,只要写native就好。windows中,会自动寻找native.dll,Linux下对应的是libnative.so。

以下是实例代码:

using System

using System.Runtime.InteropServices

namespace Managed

{

class Program

{

[DllImport("native")]

public static extern int getSum(int a, intb)

static void Main(string[] args)

{

System.Console.WriteLine("Managed code out.")

System.Console.WriteLine("1+2=" + getSum(1, 2))

}

}

}

上边的代码演示了从外部动态链接库引入函数的方式,注意没有加扩展名。接下来在看看windows下的c代码是如何编写的:

/**

* native.h 头文件,声明函数原型

*/

#ifndef NATIVE_H

#define NATIVE_H

#ifdef __cplusplus

extern "C" {

#endif

int __stdcall getSum(const int a, const intb)// 原型

#ifdef __cplusplus

}

#endif

#endif

/*

* native.cpp

* 2013-03-05 实现功能的代码

*/

#include "native.h"

#include <stdio.h>

int __stdcall getSum(const int a, const intb)

{

printf("WindowsNative code.\n")

returna+b

}

以上是具体的代码,另外需要模块定义文件(.def)来指定导出的函数表。如下:

LIBRARY "native"

EXPORTS

getSum

在VC中,编译,以上代码,可以生成dll文件。用dumpbin工具可以看到导出的函数名为getSum。

Linux下的共享库(Shared Object,简称so)的实现比上边更简单,编译时gcc加上-shared参数即可,这方面网上很多。我直接采用了code block的IDE,建立shared library工程。编译时IDE就会把这些处理好。编写的代码如下:

#include <stdio.h>

int getSum(int a, int b)

{

printf("Linux Natie code\n")

return a+b

}

编译生成libnative.so。

我们在native的代码中插入了输出语句,用来显示调用了哪个库。将这些native.dll, libnative.so, 还有C#程序managed.exe拷贝到一个文件夹,在Windows上运行managed.exe结果如下:

可以看出,在Windows和Linux下的P/Invoke调用都很成功。差不多到这里就该结束了,但是还有一点需要提醒,不论哪个平台,如果提示找不到库的问题,请将库放在一个程序能够找到的地方。

以上只是简单的演示了P/Invoke,实际上更复杂的情况,我们可以在.NET程序中,判断当前运行的 *** 作系统,然后采用LoadLibrary或者dlopen等,动态加载共享库,这样更灵活,不再有上边提到的“不加扩展名”,路径找不到的要求或者问题。感兴趣的读者可以自行了解这方面的内容。

详细的内容可以参考下面的参考文档,下面的内容主要是为网络设备运维人员使用的pexpect 跨平台简明教程。

Expect 程序主要用于人机对话的模拟,就是那种系统提问,人来回答 yes/no ,或者账号登录输入用户名和密码等等的情况。

pexpect是 Don Libes 的 Expect 语言的一个 Python 实现,是一个用来启动子程序,并使用正则表达式对程序输出做出特定响应,以此实现与其自动交互的 Python 模块。它可以用来实现与ssh, ftp, telnet等程序的自动交互。

send命令后执行结果内容保存在buffer中,这时child.expect('keyword')后,child.before即为“keyword”之前的字符串,child.after即为匹配的”keyword”字符串。

command的执行结果都保存在一个buffer中,每次执行expect时都从buffer中开始检查匹配的pattern,如果找到了匹配的pattern,则所有在匹配处之前的内容都从buffer中清除。

(这边没有看明白也没有关系,可以看后面的实践篇例子)

通常维护人员有的偏向于用WIN系统,有的偏向于LINUX系统。所以前期团队希望形成一个统一框架的时候就出现了一个难题。框架如何适用于不同的系统。

LInux系统pexpect包,win系统前期尝试使用winpexpect,但是程序改动很大,并没有调试成功。

如何在WIN系统使用python的pexpect包很难找到相关资料,某乎上都是类似的疑问没有解答。

团队成员增加后,终于有了新的思路 , 团结就是力量 。

通过这个模块进行不同系统的适配。

将plink.exe装在python的文件夹在python的安装目录下,win系统可以同样使用pexpect模块

参考信息1:Pexpect 官方文档 New in version 4.0: Windows support。Pexpect can be used on Windows to wait for a pattern to be produced by a child process, using [ pexpect.popen_spawn.PopenSpawn ]

参考信息2:PuTTY是一个Telnet、SSH、rlogin、纯TCP以及串行接口连接软件。plink是可以独立使用的exe实现形式,可以让我们直接在命令行制定好命令,然后执行,完成后自动关闭session。ssh是一个安全通道协议。plink是这个通道协议的一个实现 [图片上传中...(-572001-1587612890428-0)]

从官方文档来看,

sendline() 和 send() 唯一的区别就是在发送的字符串后面加上了回车换行符,这也使它们用在了不同的地方:

只需要发送字符就可以的话用send()

如果发送字符后还要回车的话,就用 sendline()

但是在调测过程中,WIN系统下命令输入后,child.before始终得不到预想中的结果。

经过逐步排查,发现在WIN系统下只能使用send() ,如果使用sendline() ,第一次交互没有问题,后续交互就开始问题。

WIN系统下child.before输出为b'byte型,做判断时要转为str型。具体可以参考最后面一篇讲编码类型的文章,讲的很详细。

例子1

send Username后,child.before一直到'Tac_Userna',child.after为‘me:’,child.buffer为空。

expect关键字assword:后,child.before回显一直到keyword之前,child.after为keyword,child.buffer为空。

例子2

下发command命令,child.before维持原来的不变,expect到keyword以后,child.before变为下发command命令后的设备回显。

参考文档

官方文档

探索Pexpect

Pexpect示例及使用Tips

Python Pexpect模块讲解

Pexpect模块使用说明

windows下使用plink实现全自动登陆ssh

Python3_字符编码


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/yw/8487742.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-17
下一篇 2023-04-17

发表评论

登录后才能评论

评论列表(0条)

保存