파이썬은 스크립팅 언어로서 개발 효율성이 높지만 성능은 높지 않습니다. 따라서 개발 효율성과 성능을 고려하기 위해 고성능 요구 사항이 있는 모듈은 일반적으로 c 또는 c++로 구현되거나 c에서 Python 스크립트를 실행합니다. 또는 처리를 위한 C++. 전자는 일반적으로 Python으로 일부 모듈을 구현하는 것이고, 후자는 서버 측 프로그램(비즈니스 확장 또는 플러그인 기능 구현) 및 게임 개발(스크립트는 로직만 처리)에서 더 일반적입니다. 본 글에서는 C에서 Python 스크립트를 실행하여 Python과 C 간의 상호 호출을 구현하는 방법을 주로 소개하고, C와 Python 스크립트에서 동일한 메모리 영역을 설정하는 예를 사용합니다.
머리말
최근 업무상 온라인 게임 배틀을 위한 데이터 동기화 프로토콜을 udp 기반으로 만드는 것을 고려 중인데, 초기 단계에서 데이터를 테스트하기 위해 외부 프록시를 만들기로 결정했습니다. 터널 우선 원칙은 서버 측에서 클라이언트와 별도로 네트워크 전달 프록시를 설정합니다. 즉, 원래 C/S 연결이 두 프록시 간의 빠른 데이터 전송으로 변경됩니다. udp 라이브러리는 C++로 작성된 코드이기 때문에 데이터를 테스트할 때 지속적으로 매개변수를 수정하고, 다시 컴파일하고, 출력 통계 데이터를 수정하고 표를 만드는 것은 매우 성가신 일입니다. 마지막으로 내보내기 인터페이스에 대한 논리적 호출을 수행하기 위해 Python 스크립트를 사용하기로 결정했습니다. 아래에서는 별로 할 말이 없지만 자세한 소개를 살펴보겠습니다.
C에서 Python 스크립트를 실행하려면 프로그램이 링크될 때 Python 가상 머신 라이브러리를 여기에 링크해야 합니다. Python 가상 머신 라이브러리는 python 설치 디렉토리의 libs에 있는 python27.lib 파일입니다. 라이브러리를 프로그램에 연결하는 방법은 직접 Google에서 확인할 수 있습니다. C에서는 Python의 일부 메소드와 데이터 구조를 사용하므로 Python 설치 디렉터리 아래의 include 디렉터리를 프로젝트 포함 디렉터리에 추가해야 합니다. 좋습니다. 준비해야 할 것은 이것이 전부입니다. 그런 다음 메모리 영역 설정 예제 구현을 시작할 수 있습니다.
C/C++를 Python으로 내보내는 방법에는 여러 가지가 있습니다. 필요에 따라 다음과 같은 방법을 사용할 수 있습니다.
1. ctypes는 범용 Python 표준 라이브러리 모듈에 포함되어 있으며 런타임에 동적 링크 라이브러리(dll 등)를 로드할 수 있으며 CPython 2.x/3.x 및 PyPy에서 지원됩니다. 이 방법의 장점은 특별히 Python API를 사용하여 내보내기 함수를 작성할 필요가 없으며 동적 링크 라이브러리의 기호 테이블을 직접 로드하고 Python에서 직접 호출할 수 있다는 것입니다.
2. 타사 Python 바인딩. 예로는 일련의 C++ 래퍼 함수를 생성하기 위해 Python/C API를 사용하는 도구 자동화로 구현되는 Boost-python이 있습니다. 특히 대규모 라이브러리나 엔진을 Python으로 내보내는 데 적합합니다.
3. Python 바인딩 기능을 수동으로 작성합니다. Python C API에 익숙하다면 이 방법이 가장 유연할 것이며 API 설명서를 읽은 후 사용할 수 있습니다. 이론적으로는 효율이 가장 좋아야 하는데, 저 같은 파이썬 초보자에게는 시간이 많이 걸릴 수도 있습니다.
C 함수를 Lua 스크립트로 내보내는 이전 경험을 바탕으로 Python C API를 먼저 공부한 다음 반나절 동안 작업해야 완료할 수 있다고 생각했습니다. 나중에 나는 Python 표준 라이브러리 모듈의 ctypes가 이미 매우 강력하다는 것을 발견했습니다. 비록 성능이 세 가지 방법 중 최악이어야 하지만, 최대 60fps의 이 터널에서는 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, data typemapping
ctypes로 정의된 기본 데이터 유형(c_char, c_int, c_double 등) 외에도 포인터 기능을 사용하여 다음을 수행할 수도 있습니다. 포인터 유형으로 변환합니다. 네트워크 라이브러리를 내보내려면 콜백 함수를 설정하는 것이 중요합니다. 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과 C 사이에서 서로 호출하는 방법에 대한 자세한 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!