python和C的如何實現互相呼叫?
本文和大家分享的是python和c的互相呼叫相關知識,一起來看看吧,希望對大家學習python有所幫助。
最近在考慮基於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垃圾回收導致回撥函式變成野指標。這算是一個小小的坑吧。基本上一個小小的庫也就用到這些功能。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/758/viewspace-2814165/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Android JNI實現Java與C/C++互相呼叫,以及so庫的生成和呼叫(JNI方式呼叫美圖秀秀so)AndroidJavaC++
- Unity——Js和Unity互相呼叫UnityJS
- C# 實現 gRPC 服務和呼叫C#RPC
- python和c++的相互呼叫教程PythonC++
- 【抬槓C#】如何實現介面的base呼叫C#
- 深入xLua實現原理之Lua如何呼叫C#C#
- 深入xLua實現原理之C#如何呼叫LuaC#
- python如何呼叫subprocess模組實現外部命令?Python
- 微服務互相呼叫-Feign微服務
- 在 C/C++ 中使用 TensorFlow 預訓練好的模型—— 間接呼叫 Python 實現C++模型Python
- C#呼叫python的方法C#Python
- Openfeign動態構建client實現同服務serviceId不同instanceId互相呼叫client
- C# bytes[]和sting互相轉換C#
- C#呼叫PythonC#Python
- C# 呼叫 C++ 生成的 dll 關鍵實現部分C#C++
- Python呼叫C/C++方式PythonC++
- C均值聚類 C實現 Python實現聚類Python
- python中列表、字典和字串的互相轉換Python字串
- C#位元組陣列byte[]和字串string如何互相轉換C#陣列字串
- 原生實現C#和Lua相互呼叫-Unity3D可用C#Unity3D
- C#如何用最簡單方法呼叫Python?C#Python
- WebAssembly實踐指南——C++和Rust透過wasmtime實現相互呼叫例項WebC++RustASM
- 如何用C/C++實現去除字串頭和尾指定的字元C++字串字元
- TensorFlow 呼叫預訓練好的模型—— Python 實現模型Python
- Java Stram實現Map和字串之間互相轉換| BaeldungJava字串
- 兩個JS之間的函式互相呼叫JS函式
- Cocos Creator iOS 互相呼叫看我的就夠了iOS
- 129、springcloud-eureka-client微服務的互相呼叫SpringGCCloudclient微服務
- Python呼叫C++編寫的方法PythonC++
- VS2012生成C的dll並呼叫以及Python呼叫C的DLLPython
- Python與C/C++呼叫之ctypesPythonC++
- uni-app實現web-view和App之間的互相通訊APPWebView
- C++庫封裝JNI介面——實現java呼叫c++C++封裝Java
- C#/.net程式呼叫pythonC#Python
- C# 呼叫Python程式碼C#Python
- Laravel 如何實現既能靜態呼叫,又能動態呼叫Laravel
- 使用emscripten實現js直接呼叫C程式碼(emscripten的初探)JSC程式
- nacos實現Java和.NetCore的服務註冊和呼叫JavaNetCore