本人一直从事windows开发,linux系统也经常接触过,部署Docker什么的,但是还没有再linux环境下做过开发。最近跟第三方对接。对方提供了c++的linux编译库 .so文件,这时有人说让第三方重新编译dll。但是我还是尝试再linux环境下,通过CPython对多第三方接口进行封装,然后使用python编写WebAPI部署Docker服务,这样c#也就能正常调用了。虽然过程曲折,但是完美的解决了问题。
第一步,开发环境装备:
1、基本的linux系统环境。我使用的Centos,另外虚拟机也可以。不要安装什么图像化界面等,我再这方面踩了不少坑。浪费太多时间。然后新建用户user,密码123456;假定IP:192.168.1.12
2、windows系统安装xshell或者windows terminal ,然后还需要对于我们c#开发来说最熟悉的visual studio code 。
3、打开windows terminal(xshell)也可以。输入 ssh [email protected] 回车后输入密码:123456。不出意外连接linux环境。
4、安装c++编译器,linux下常见的gcc ,clang。yum install gcc。安装python ,yum install python。具体还需要什么环境根据项目来定。
5、打开我们的IDE,visual studio code,是的,我们以后的开发都是这个IDE即可,不要再linux系统下进行。安装扩展Remote-ssh。如果不会自己百度搜索vscode 扩展安装吧。
6、然后shift+ctrl+p 输入remote-ssh 选择Remote-SSH:Connect to host ,然后选择 Add new shh host。
7、输入ssh [email protected]。下面OUTPUT 会提示让你输入密码:123456.回车后,左侧出现如下图列表,恭喜你完成基本的开发环境设置了。
二、C编写Python扩展
1、开发环境有了,这样就编写Python扩展了吗?
当然首先安装c++扩展,还需要针对c++编译的一些配置。还要需要用到下面三个配置文件
这个三个文件再新建helloworld.cpp后,再调试模式下,点击运行,或者直接F5会弹出提示,让选择一个编译方式,本人使用的g++(开始选择了gcc,后面遇到一个坑)。会自动创建。
c_cpp_properties.json 关于cpp的基本配置,需要变动的是:includePath。这里要包含项目中需要使用到的相关依赖,比如gcc,python等。
launch.json 程序执行配置。
tasks.json 程序编译配置。
其中:保证tasks.json中的label 的值和launch.json中的preLaunchTask值一致。不然会报错。
最后保证程序编译正常,且运行后输出hello world 。如果出现问题请自行百度,或者留言。
2、C写一个python扩展需要四个步骤:
a、
#include
b、C函数:三种形式
static PyObject *MyFunction( PyObject *self, PyObject *args );
static PyObject *MyFunctionWithKeywords(PyObject *self, PyObject *args, PyObject *kw);
static PyObject *MyFunctionWithNoArgs( PyObject *self );
c、方法映射表就是PyMethodDef结构的数组
struct PyMethodDef {
char *ml_name;
PyCFunction ml_meth;
int ml_flags;
char *ml_doc;
};
static PyMethodDef module_methods[] = {
{ "func", (PyCFunction)module_func, METH_VARARGS, NULL },
{ NULL, NULL, 0, NULL }
};
ml_name: 这是暴露给python程序的函数名;
ml_meth: 这是指向函数的指针,也就是真正函数定义的地方;
ml_flags: 这告诉python解析器想用三种函数签名的哪一种,一般来说,它的值是METH_VARARGS;如果你想传入关键字参数的话,也可以与MET_KEYWORDS进行或运算;当然,如果你不想接受任何参数的话,可以给其赋值为METH_NOARGS;
ml_doc: 这是函数的文档字符串,如果你不想写的话,直接给其赋值为NULL。
d、初始化函数
初始化函数必须被命名为initModuleName,这里ModuleName表示你的模块名。
是不是很简单。也没那么复杂,有了这四个模块。你再python里面就可以调用。
3、再三个c函数中,有2个带参数的,当然也是我们会经常用的,那怎么传参或返回值呢?
a、获取python参数
解析无关键字的参数用 PyArg_ParseTuple方法:
int PyArg_ParseTuple(PyObject* tuple,char* format,...)
解析带有关键字的参数用 PyArg_ParseTupleAndKeywords方法:
int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, char *keywords[], ...)
遇到错误返回0,返回别的数字代表正确。
b、返回python
Python C 函数的返回值都是PyObject*类型的(错误返回NULL),如果不想返回任何值,就是用宏Py_RETURN_NONE。
PyObject* Py_BuildValue(char* format,...)
c、参数缩写对应:
Code |
C type |
Meaning |
c |
char |
A Python string of length 1 becomes a C char |
d |
double |
A Python float becomes a C double |
f |
float |
A Python float becomes a C float |
i |
int |
A Python int becomes a C int |
l |
long |
A Python int becomes a C long. |
L |
long long |
A Python int becomes a C long long |
O |
PyObject* |
Gets non-NULL borrowed reference to Python argument. |
s |
char* |
Python string without embedded nulls to C char*. |
s# |
char*+int |
Any Python string to C address and length. |
t# |
char*+int |
Read-only single-segment buffer to C address and length. |
u |
Py_UNICODE* |
Python Unicode without embedded nulls to C. |
u# |
Py_UNICODE*+int |
Any Python Unicode C address and length. |
w# |
char*+int |
Read/write single-segment buffer to C address and length. |
z |
char* |
Like s, also accepts None (sets C char* to NULL). |
z# |
char*+int |
Like s#, also accepts None (sets C char* to NULL). |
(…) |
as per … |
A Python sequence is treated as one argument per item. |
| |
The following arguments are optional. |
|
: |
Format end, followed by function name for error messages. |
|
; |
Format end, followed by entire error message text. |
4、写好的c程序怎么把发布给python调用呢?
需要使用distutils模块,来发布我们的cpp程序。
1、定义个setup.py脚本文件
from distutils.core import setup, Extension
setup(name="exampleAPP", version="1.0", ext_modules=[Extension("example", ["example.cpp"])])
2、编译 ,编译后的文件为.so。
python setup.py build
三、Python 编写WebAPI
1、python 调用cpython扩展
首先 装备python开发环境,设置sdk相关环境变量。进入python 使用 import example。
导入成功后再python脚本中使用from example import example
然后根据cpp里面的方法映射表来调用即可。
2、python封装webAPI 。
网上资料很多,自行百度吧。
3、python webAPI服务部署Docker。
网上资料很多,自行百度吧。
四、C# 调用WebAPI
使用httpClient 即可。具体自行百度。
整个项目中对于我来说,最陌生的还是基于linux开发,总认为Linux开发就必须再Linux系统中操作,觉得操作很不方便,做开发应该也会很麻烦。通过这个项目才明白,是可以再windows系统下做linux开发的,通过ssh ,linux开发也很简单。