python与C互相调用的方法详解


Posted in Python onJuly 14, 2017

前言

最近因为工作的需要,在考虑基于udp做一个用于网游战斗中的数据同步协议,为了前期测试数据,决定先做一个外部的代理tunnel,原理是在server端和client端分别建立网络转发proxy,即原来的C/S连接改为两个proxy之间数据快速传输。因为udp库是用C++写的代码,在测试数据的时候需要不断地修改参数,重新编译,修改输出统计数据制表等,不胜其烦,最终决定导出接口由python脚本来进行逻辑调用。下面话不多说,来一起看看详细的介绍:

C/C++导出到python有多种方法,根据不同的需求,可以使用下面不同的方式:

1、ctypes绑定。ctypes就包含在万能的python标准库模块里面,它可以运行时载入动态链接库(dll,so),在CPython 2.x/3.x和PyPy上都支持。这种方式好处就是不用针对性地用python api写导出函数,可以直接加载动态链接库的符号表,在python中就可以直接调用了。

2、第三方的python binding。例子有boost-python,实现方式是工具自动化用Python/C api生成一系列C++ wrapper函数。特别适用于大型的库或引擎导出到python。

3、手动写python binding函数。如果对Python C api熟悉的话,这种方式应该是最灵活的,读一遍API文档就可以使用。理论上效率应该是最好的,但对于我这种python初学者,可能需要花上不少时间。

以之前折腾C函数导出到Lua脚本的经历,本以为要先研究一番python c api,再搞上半天才能搞定。后面发现python标准库模块的ctypes已经非常强大,虽然性能应该是三种方式里面最差的,但在这个最高60fps的tunnel里面,C/Python接口边界调用的损耗先忽略。跟其他两种方式设计不一样的是,ctypes采用的是非入侵式调用接口的方式,不需要修改原来的C接口或者写一些绑定代码,直接对编译出来的动态库进行调用。ctypes使用过程也是非常愉悦的。

下面介绍下ctypes的使用:

1、加载DLL动态链接库

这里需要注意区分动态链接库函数是使用cdecl还是stdcall的调用约定,分别使用cdll或windll加载动态库。

例如:

# 加载udp库函数 
udp_server = cdll.LoadLibrary("./udp_server.so") 
init_udp_server = udp_server.init_udp_server 
destroy_udp_server = udp_server.destroy_udp_server 
update_udp_server = udp_server.update_udp_server 
SendMsg = udp_server.SendMsg 

SetConnectCallback = udp_server.SetConnectCallback 
SetDisconnectCallback = udp_server.SetDisconnectCallback 
SetTimeoutCallback = udp_server.SetTimeoutCallback 
SetRecvCallback = udp_server.SetRecvCallback

2、数据类型映射

除了ctypes定义的基本数据类型(c_char, c_int, c_double等),还能使用pointer函数转换成指针类型。对于要导出的网络库,设置回调函数是必不可少的,在C++库里面,回调函数是通过设置一个函数指针完成的,ctypes同样支持函数指针的声明。如:recv_cb = CFUNCTYPE( None, c_char_p, c_int ) ,表示一个返回值为void,参数为char*和int类型的回调函数。

def __init__(self, port, ip="127.0.0.1"): 
  self._port = port 
  self._ip = ip 

  self._clients = {} 

  self.c_connect_cb = connect_cb(self.server_connect) 
  self.c_disconnect_cb = disconnect_cb(self.server_disconnect) 
  self.c_timeout_cb = timeout_cb(self.server_timeout) 
  self.c_recv_cb = recv_cb(self.server_recv) 

def create(self): 
  if self._port: 
   if init_udp_server(self._ip, self._port) == 0: 
    print "server listen %s:%d" % (self._ip, self._port) 
    SetConnectCallback( self.c_connect_cb ) 
    SetDisconnectCallback( self.c_disconnect_cb ) 
    SetTimeoutCallback( self.c_timeout_cb ) 
    SetRecvCallback( self.c_recv_cb ) 
    return True 
  print "[error] init_udp_server error", self._ip, self._port 
  return False

绑定回调参数需要注意的是,绑定的回调函数需要保存为成员变量(上面的写法),目的是避免python垃圾回收导致回调函数变成野指针。这算是一个小小的坑吧。基本上一个小小的库也就用到这些功能。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
Python中使用 Selenium 实现网页截图实例
Jul 18 Python
Python脚本实现代码行数统计代码分享
Mar 10 Python
Python实现的归并排序算法示例
Nov 21 Python
python MysqlDb模块安装及其使用详解
Feb 23 Python
python训练数据时打乱训练数据与标签的两种方法小结
Nov 08 Python
python 格式化输出百分号的方法
Jan 20 Python
详解Python用户登录接口的方法
Apr 17 Python
python中update的基本使用方法详解
Jul 17 Python
python常用运维脚本实例小结
Feb 14 Python
Python连接Hadoop数据中遇到的各种坑(汇总)
Apr 14 Python
将tf.batch_matmul替换成tf.matmul的实现
Jun 18 Python
matplotlib grid()设置网格线外观的实现
Feb 22 Python
Python django实现简单的邮件系统发送邮件功能
Jul 14 #Python
使用Django Form解决表单数据无法动态刷新的两种方法
Jul 14 #Python
Python md5与sha1加密算法用法分析
Jul 14 #Python
Python自动化开发学习之三级菜单制作
Jul 14 #Python
python实现杨辉三角思路
Jul 14 #Python
Django 添加静态文件的两种实现方法(必看篇)
Jul 14 #Python
python 实现上传图片并预览的3种方法(推荐)
Jul 14 #Python
You might like
php冒泡排序、快速排序、快速查找、二维数组去重实例分享
2014/04/24 PHP
浅谈使用PHP开发微信支付的流程
2015/10/04 PHP
PHP中抽象类和抽象方法概念与用法分析
2016/05/24 PHP
thinkPHP模板中for循环与switch语句用法示例
2016/11/30 PHP
php+mysql+jquery实现日历签到功能
2017/02/27 PHP
基于thinkphp6.0的success、error实现方法
2019/11/05 PHP
JavaScript 计算图片加载数量的代码
2011/01/01 Javascript
json中换行符的处理方法示例介绍
2014/06/10 Javascript
在Web项目中引入Jquery插件报错的完美解决方案(图解)
2016/09/19 Javascript
jquery操作checkbox火狐下第二次无法勾选的解决方法
2016/10/10 Javascript
js实现拖拽功能
2017/03/01 Javascript
浅谈JavaScript正则表达式-非捕获性分组
2017/03/08 Javascript
NodeJS实现自定义流的方法
2018/08/01 NodeJs
vue-cli项目修改文件热重载失效的解决方法
2018/09/19 Javascript
简单易扩展可控性强的Jquery转盘抽奖程序
2019/03/16 jQuery
vue2 v-model/v-text 中使用过滤器的方法示例
2019/05/09 Javascript
[04:54]DOTA2 2017国际邀请赛:上届冠军WINGS采访短片
2017/08/09 DOTA
Python使用pylab库实现画线功能的方法详解
2017/06/08 Python
Python实现购物车程序
2018/04/16 Python
Django处理文件上传File Uploads的实例
2018/05/28 Python
python实现寻找最长回文子序列的方法
2018/06/02 Python
Python实现账号密码输错三次即锁定功能简单示例
2019/03/29 Python
python实现微信小程序用户登录、模板推送
2019/08/28 Python
在python中利用pycharm自定义代码块教程(三步搞定)
2020/04/15 Python
美国网上眼镜供应商:LEOTONY(眼镜、RX太阳镜和太阳镜)
2017/10/31 全球购物
美国宠物美容和宠物用品购物网站:Cherrybrook
2018/12/07 全球购物
公司业务主管岗位职责
2013/12/07 职场文书
求职简历中的自我评价分享
2013/12/08 职场文书
葡萄牙语专业个人求职信
2013/12/10 职场文书
学生自我鉴定模板
2013/12/30 职场文书
2014小学生国庆65周年演讲稿
2014/09/21 职场文书
夫妻忠诚协议范文
2014/11/16 职场文书
小学生作文批改评语
2014/12/25 职场文书
财务负责人岗位职责
2015/02/03 职场文书
请学会珍惜眼前,因为人生没有下辈子!
2019/11/12 职场文书
《月歌。》宣布制作10周年纪念剧场版《RABBITS KINGDOM THE MOVIE》
2022/04/02 日漫