99热99这里只有精品6国产,亚洲中文字幕在线天天更新,在线观看亚洲精品国产福利片 ,久久久久综合网

歡迎加入QQ討論群258996829
麥子學(xué)院 頭像
蘋果6袋
6
麥子學(xué)院

python和C的互相調(diào)用方法步驟詳解

發(fā)布時間:2017-07-17 17:05  回復(fù):0  查看:2705   最后回復(fù):2017-07-17 17:05  
本文和大家分享的是python c 的互相調(diào)用相關(guān)知識,一起來看看吧,希望對大家 學(xué)習(xí)python有所幫助。
  最近在考慮基于udp 做一個用于網(wǎng)游戰(zhàn)斗中的數(shù)據(jù)同步協(xié)議,為了前期測試數(shù)據(jù),決定先做一個外部的代理 tunnel ,原理是在 server 端和 client 端分別建立網(wǎng)絡(luò)轉(zhuǎn)發(fā) proxy ,即原來的 C/S 連接改為兩個 proxy 之間數(shù)據(jù)快速傳輸。因為 udp 庫是用 C++ 寫的代碼,在測試數(shù)據(jù)的時候需要不斷地修改參數(shù),重新編譯,修改輸出統(tǒng)計數(shù)據(jù)制表等,不勝其煩,最終決定導(dǎo)出接口由 python 腳本來進(jìn)行邏輯調(diào)用。
  C/C++ 導(dǎo)出到 python 有多種方法,根據(jù)不同的需求,可以使用下面不同的方式:
  1.ctypes 綁定。 ctypes 就包含在萬能的 python 標(biāo)準(zhǔn)庫模塊里面,它可以運(yùn)行時載入動態(tài)鏈接庫( dll , so ),在 CPython 2.x/3.x PyPy 上都支持。這種方式好處就是不用針對性地用 python api 寫導(dǎo)出函數(shù),可以直接加載動態(tài)鏈接庫的符號表,在 python 中就可以直接調(diào)用了。
  2. 第三方的 python binding 。例子有 boost-python ,實現(xiàn)方式是工具自動化用 Python/C api 生成一系列 C++ wrapper 函數(shù)。特別適用于大型的庫或引擎導(dǎo)出到 python 。
  3. 手動寫 python binding 函數(shù)。如果對 Python C api 熟悉的話,這種方式應(yīng)該是最靈活的,讀一遍 API 文檔就可以使用。理論上效率應(yīng)該是最好的,但對于我這種 python 初學(xué)者,可能需要花上不少時間。
  以之前折騰C 函數(shù)導(dǎo)出到 Lua 腳本的經(jīng)歷,本以為要先研究一番 python c api ,再搞上半天才能搞定。后面發(fā)現(xiàn) python 標(biāo)準(zhǔn)庫模塊的 ctypes 已經(jīng)非常強(qiáng)大,雖然性能應(yīng)該是三種方式里面最差的,但在這個最高 60fps tunnel 里面, C/Python 接口邊界調(diào)用的損耗先忽略。跟其他兩種方式設(shè)計不一樣的是, ctypes 采用的是非入侵式調(diào)用接口的方式,不需要修改原來的 C 接口或者寫一些綁定代碼,直接對編譯出來的動態(tài)庫進(jìn)行調(diào)用。 ctypes 使用過程也是非常愉悅的。
  下面介紹下ctypes 的使用:
  1.  加載 DLL 動態(tài)鏈接庫
  這里需要注意區(qū)分動態(tài)鏈接庫函數(shù)是使用cdecl 還是 stdcall 的調(diào)用約定,分別使用 cdll windll 加載動態(tài)庫。
  例如:
  加載 udp 庫函數(shù)  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.  數(shù)據(jù)類型映射
  除了ctypes 定義的基本數(shù)據(jù)類型( c_char, c_int, c_double 等),還能使用 pointer 函數(shù)轉(zhuǎn)換成指針類型。對于要導(dǎo)出的網(wǎng)絡(luò)庫,設(shè)置回調(diào)函數(shù)是必不可少的,在 C++ 庫里面,回調(diào)函數(shù)是通過設(shè)置一個函數(shù)指針完成的, ctypes 同樣支持函數(shù)指針的聲明。如: recv_cb = CFUNCTYPE( None, c_char_p, c_int ) ,表示一個返回值為 void ,參數(shù)為 char* int 類型的回調(diào)函數(shù)。
   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
  綁定回調(diào)參數(shù)需要注意的是,綁定的回調(diào)函數(shù)需要保存為成員變量(上面的寫法),目的是避免python 垃圾回收導(dǎo)致回調(diào)函數(shù)變成野指針。這算是一個小小的坑吧?;旧弦粋€小小的庫也就用到這些功能。
來源:簡書
您還未登錄,請先登錄

熱門帖子

最新帖子

?