简介:面向需要在 Linux 环境下用 Python 调用 SAP RFC 接口的开发人员,这是一份配套的 nwrfcsdk 资源包,对应 nwrfc750P_5-70002752 版本,解决 pyrfc 依赖的 C 库缺失、版本不匹配等安装与连接问题。压缩包共 27 个文件,约 18.05MB,以头文件、C/C++ 源码、动态库、配置文件等形式为主——其中 h/cpp/c 用于 SDK 编译与二次封装,so 动态库和 ini 配置用于运行时加载与连接参数设定,txt 文档则说明编译安装和环境变量配置要点。资源已由 1401 人学习下载。拿到后可按官方说明解压并配置 LD_LIBRARY_PATH 与 sapnwrfc.ini,随后通过 pip 安装 pyrfc,即可与 SAP NetWeaver 系统建立连接,调用 STFC_CONNECTION 等远程函数,读取表数据或触发业务逻辑。对从事 SAP 集成、自动化脚本开发或运维排障的工程师,这份打包好的 SDK 能省去四处收集匹配版本的麻烦,并支撑从环境搭建到代码联调的全过程。
1. 为什么一个 Python 进程要抱着 SAP 的 C 基础库不放
SAP 系统的 RFC 接口从来不是 Python 免费送的。想象这种场景:你在一台连内网的 Linux 服务器上部署数据采集服务,上游业务方只给了一个 SAP 账号和几个 RFC 函数名,要求你半夜跑批读取物料主数据或过账凭证。面前有三条路:买 JCo 中间件、让顾问导 CSV、或用 Python 直接调 RFC。真正试过第三条路的人都知道,第一步不是pip install,而是先弄到那份叫 NW RFC SDK 的 C 库。没有它,pyRFC 连 import 都过不去。这篇文章就讲清楚:在 Linux 上把 NW RFC SDK 装对、把 pyRFC 编译出来、把第一个 RFC 调用跑通,顺手告诉你哪些错误换一台机器就能复现。适合已经拿到 RFC 授权、准备在 Linux 服务器上用 Python 对接 SAP 的开发或运维工程师。
2. RFC 调用原理与方案选型:为什么必须要有 nwrfcsdk
RFC 不是一个普通的网络协议,它是 SAP 私有的远程函数调用规范。消息头里携带 ABAP 数据字典的元信息,所以 Python 这类外部语言不能凭一个 TCP 连接就把参数丢过去。真正干活的是 SAP 提供的 C 语言 SDK,它负责把高层的调用请求翻译成 ABAP 工作进程能理解的报文。pyRFC 只是给这份 SDK 包了一层 Python 接口。
2.1 RFC 协议里,SDK 和 pyRFC 各自扮演什么角色
RFC 链路由三部分构成:SAP 应用服务器上的 ABAP 工作进程、网关进程(gateway)、以及外部程序一侧的 RFC 客户端库。SDK 就是那个客户端库。它实现了会话管理、数据序列化、类型转换和错误处理,对外提供一组 C API,核心的libsapnwrfc.so里包含RfcOpenConnection、RfcInvoke、RfcCloseConnection这些函数。pyRFC 用 Cython 将这些函数封装成 Python 类,所以你看到的是一个pyrfc.Connection对象,它内部其实持有一个指向 SDK 会话的指针。
换句话说,pyRFC 不是另一个 RFC 实现,它只是绑定器。运行时的行为完全由 SDK 决定。为什么不自己写一个纯 Python 的 RFC 客户端?因为 RFC 协议没有公开的协议文档,SAP 也没有开放抓包接口,贸然去实现会碰上大量黑匣子问题,比如 Unicode 大端序、ABAP 结构体对齐等。用官方 SDK 是最快且唯一可靠的路。
2.2 方案选型:对比 JCo、sapnwrfc 和 REST 桥
我这里直接给结论:如果你的应用是 Python 写的,并且部署在 Linux 上,选 pyRFC 加 NW RFC SDK 是最契合的组合。对比 JCo,JCo 需要企业版 Java 许可和大量 JVM 内存,部署单元体积动辄几百 MB,在容器化场景里显得笨重。对比第三方库sapnwrfc,那个库只封装了老版 SDK 的部分函数,没有持续兼容新版 SDK 的承诺,遇到 SDK 更新后就容易失效。用 SAP Gateway 发 OData 用于轻量查询还行,但高频、事务性强、返回值是深层嵌套结构体的场景,RFC 的效率和稳定性还是高出一截。
选型时还有一个识别要点:真正能连 SAP 的 pyRFC 包名在 PyPI 上是pypyrfc,导入名才是pyrfc。有些同名不同命的包会让人装上之后报ModuleNotFoundError,所以安装时不要只看项目名,要看安装包内是否依赖SAPNWRFC_HOME。这个识别方式能帮你避开大量假库。
2.3 完整调用链:从 Linux 进程到 ABAP 工作进程
我们顺着一条调用请求走一遍,看它在链路上经过哪些节点。首先,pyRFC 初始化时调用RfcInitialize,它创建 SDK 的运行时环境,加载配置文件并初始化加密组件。然后pyrfc.Connection构造阶段调用RfcOpenConnection,根据ashost、sysnr等参数向 SAP 网关发起 TCP 连接。网关进程监听在 33 加上系统号的端口,比如系统号00对应 3300。连接建立后,conn.call('STFC_CONNECTION', REQUTEXT=...)会触发RfcInvoke,SDK 把参数序列化成 RFC 消息报文,经网关分发到某个 ABAP 工作进程执行。ABAP 端执行完,把返回结构体序列化回传,SDK 再还原成 Python 字典。
这条链路每一步都有各自的失败模式:TCP 不通报CPIC_ERROR;ABAP 执行异常报SYSTEM_FAILURE;SDK 与后端版本不匹配报INVALID_STATE。知道这些错在哪一层,后面排查就能少走弯路。
3. 在 Linux 上安装 NW RFC SDK:目录布局、环境变量与依赖检查
SDK 不是 pip 能直接装的东西,它需要你到 SAP 支持门户手动下载。下载之前有两个决定成败的检查项:平台架构和版本对齐。这两个问题如果一开始没想清楚,后面会埋下很多隐性问题。
3.1 下载前准备:平台架构与版本选择
打开 SAP 支持门户,搜索 "SAP NW RFC SDK",进入下载页后选择 Linux 平台的x86_64版本。在服务器上执行uname -m,确认系统是 64 位。如果是 ARM 机器,SAP 虽然近几年也在试水,但生产环境建议别碰,因为 SDK 里的加密库和外部工具可能有小端序假设。版本选择上,我的原则是“跟着后端 SAP 系统走”:如果后端 ECC 系统比较老,选一个新版 SDK 可能因为加密算法或协议细节不兼容而连不上;反过来,如果后端是新版 S/4HANA,选太老的 SDK 又会缺加密套件。一般你可以在 SAP 官网看到 SDK 与 NetWeaver 版本的建议匹配关系,没有明确说明的,就选一个发布时间与后端系统维护期接近的稳定版。
下载下来的文件通常是一个nwrfcsdk_*.tar.gz,里面有完整目录和权限位。如果你的 SAP 账号权限有限,也可以让 Basis 团队帮你下载后上传到内网源,这在合规严格的客户现场很常见。
3.2 解压 SDK 并理解目录结构
解压之前先规划好安装根目录。我通常放在/opt/sap/nwrfcsdk,用版本号子目录区分多版本,再通过符号链接固定当前版本。这样以后升级时只需改链接,不需要改任何环境变量和 pyRFC 指向。
mkdir -p /opt/sap tar -xzf nwrfcsdk_*.tar.gz -C /opt/sap/ cd /opt/sap/nwrfcsdk find . -maxdepth 2 -type d | sort知识库解压后的典型目录包括lib、include、bin、doc。lib里面有libsapnwrfc.so、libsapucum.so、libsapcrypto.so、libicudata.so等,include里有sapnwrfc.h。注意,有些发行版解压后文件权限会丢,尤其当压缩包是从 Windows 编辑过的,共享库文件可能没有读权限。建议执行一次批量补权限:
chmod -R u+rX /opt/sap/nwrfcsdk find /opt/sap/nwrfcsdk -type f -name "*.so" -exec chmod 755 {} \;u+rX的意思是对文件加读权限,对目录加执行权限,避免把可执行文件权限改得太随意。find那行是给所有共享库补上执行位,虽然 Linux 加载.so不要求执行位,但部分部署工具会检查,补上无害。
3.3 设置环境变量并检查动态链接依赖
SDK 装完后最关键的是让系统和 pyRFC 都能找到它。两个环境变量必须设置:SAPNWRFC_HOME指向 SDK 根目录,LD_LIBRARY_PATH指向 SDK 的lib目录。SAPNWRFC_HOME是 pyRFC 构建脚本读取 SDK 位置的唯一标准,LD_LIBRARY_PATH是 Linux 动态加载器在运行时搜索共享库的开关。
export SAPNWRFC_HOME=/opt/sap/nwrfcsdk export LD_LIBRARY_PATH=/opt/sap/nwrfcsdk/lib:$LD_LIBRARY_PATH echo 'export SAPNWRFC_HOME=/opt/sap/nwrfcsdk' >> /etc/profile.d/sapnwrfcsdk.sh echo 'export LD_LIBRARY_PATH=/opt/sap/nwrfcsdk/lib:$LD_LIBRARY_PATH' >> /etc/profile.d/sapnwrfcsdk.sh source /etc/profile.d/sapnwrfcsdk.sh提示:如果用 systemd 部署 Python 服务,记得在 service 文件里加
Environment=SAPNWRFC_HOME=/opt/sap/nwrfcsdk和Environment=LD_LIBRARY_PATH=/opt/sap/nwrfcsdk/lib,因为 systemd 不会自动读 profile 文件。这一个细节能省去线上服务重启后莫名其妙ImportError的麻烦。
设置完成后,用ldconfig刷新缓存,然后检查 SDK 自身的依赖:
ldconfig /opt/sap/nwrfcsdk/lib ldd /opt/sap/nwrfcsdk/lib/libsapnwrfc.soldd输出里如果出现not found,必须把缺失的系统库安装上。常见缺失项包括libgssapi_krb5.so.2、libuuid.so.1、libstdc++.so.6。清掉这些not found再往后走,否则 pyRFC 编译可能成功,运行时却崩在libsapnwrfc.so的加载阶段,而且报错非常隐晦。
4. 编译安装 pyRFC:构建选项、最小连接脚本与参数说明
SDK 装好后,开始处理 Python 侧。pyRFC 的安装不建议直接图省事装老版本 wheel,因为在不同 Linux 发行版和 glibc 版本上,预编译包经常因为 ABI 不匹配而报illegal instruction或直接崩溃,源码编译反而更可控。
4.1 准备编译工具链和虚拟环境
先建虚拟环境,避免把依赖撒得到处都是。很多线上服务器用的是 Python 3.6 或 3.8,但 pyRFC 对新版 Python 的支持相对滞后,建议优先用 3.10 或 3.11。
python3.11 -m venv /opt/rfc_demo/venv source /opt/rfc_demo/venv/bin/activate pip install --upgrade pip setuptools wheel yum install -y gcc python3.11-devel cython39 # CentOS/RHEL 示例 apt install -y gcc python3.11-dev cython3 # Debian/Ubuntu 示例cython不是必须预装的,因为 pyRFC 自带的 C 文件可以直接编译,但预装可以避免某些特殊情况下的重编译失败。注意 Python 版本要和 dev 包对应,否则编译时找不到Python.h。
4.2 用 SAPNWRFC_HOME 编译安装 pyRFC
如果在安装前没有设置SAPNWRFC_HOME,setup.py 会直接报错退出;如果设置了但路径写错,会在编译后 import 阶段才暴露,所以先手工确认环境变量。
export SAPNWRFC_HOME=/opt/sap/nwrfcsdk export CFLAGS="-I$SAPNWRFC_HOME/include" export LDFLAGS="-L$SAPNWRFC_HOME/lib" pip install pypyrfc编译过程中你会看到cythonize和gcc的日志。出现Successfully installed pypyrfc后,先验证 import:
import pyrfc print(pyrfc.__version__)如果报ImportError: libsapnwrfc.so: cannot open shared object file,说明运行时路径不对,再次确认/etc/profile.d的变量有没有被当前 shell 加载。如果报ModuleNotFoundError,检查是否装成了别的同名包,用pip uninstall pyrfc pypyrfc清干净重来。
4.3 最小连接测试脚本:STFC_CONNECTION 的完整代码
一切就绪,写第一个连接脚本。STFC_CONNECTION是 SAP 自带的 RFC 测试函数,几乎不需要额外授权,能跑通就说明链路是通的。
import pyrfc config = { 'ashost': '192.168.100.10', # SAP 应用服务器地址,不要填消息服务器 'sysnr': '00', # 系统号,两位字符串 'client': '100', # 客户端,三位字符串 'user': 'RFCUSER', 'passwd': 'your_password', 'lang': 'EN' } conn = pyrfc.Connection(**config) try: ret = conn.call('STFC_CONNECTION', REQUTEXT='hello from linux python') print(ret['ECHOTEXT']) finally: conn.close()逻辑很简单:构造连接参数,创建连接,调用STFC_CONNECTION回显输入字符串,最后关闭连接。注意sysnr和client必须写成字符串形式,sysnr为'00'时不能写成'0',否则 SDK 拼接端口和客户端时会少一位,直接导致CPIC_ERROR。lang不写默认用系统默认语言,如果系统默认是中文,回显时要用repr()看内容,避免控制台乱码。
4.4 运行测试并理解返回结果与常见异常
运行时,如果打印出了ECHOTEXT,恭喜你,链路是通的。如果报错,先看异常类型再分析:RFC_CPIC_ERROR是网络或端口问题;RFC_INVALID_STATE是 SDK 版本和 SAP 系统不匹配;RFC_SYS_EXCEPTION是 ABAP 侧抛了异常,比如权限或参数值不合法。还有一类少见的MemoryError,常发生在数据缓冲区不匹配时,这时检查 SDK 与 pyRFC 的位数一致性即可。
返回结果永远是一个字典或嵌套字典,SAP 的表类型结构体会被解析成 list of dict。这个约定从 pyRFC 早期版本到现在一直稳定,所以后面写业务代码时,完全可以用 JSON 序列化结果做落库。
5. 避坑:Linux 下 pyRFC 连 SAP 的 5 个翻车现场
这一章写的是血泪经验。以下错误几乎每个项目里都会遇到,报错信息又短又抽象,不还原现场很难看明白。我按阶段整理,每条按现象、原因、解决步骤列出。
5.1 导入阶段:ImportError 与初始化失败
现象一:import pyrfc直接报ImportError: libsapnwrfc.so: cannot open shared object file,没有任何其他上下文。原因:运行时动态加载器找不到 SDK 库,通常是LD_LIBRARY_PATH没有被正确导出,或者 systemd 服务没有继承 profile 里的变量。解决:在命令行执行echo $LD_LIBRARY_PATH,没有输出就 source 一次;如果是 systemd 服务,必须在 service 文件里用Environment=显式声明。
现象二:导入成功,但pyrfc.Connection构造时报RuntimeError: Initialization of the RFC library failed。原因:SDK 初始化时依赖的时间同步、加密库或本地配置出问题。解决:检查系统时间与 SAP 应用服务器偏差,安装libsapcrypto.so的依赖(用ldd查看),必要时清理/opt/sap/nwrfcsdk下残留的旧版本库文件。
5.2 连接阶段:sysnr 格式和网关端口
现象:pyrfc.Connection抛RFC_CPIC_ERROR,错误码里包含LOCATION: CPIC (TCP/IP)。原因:第一嫌疑是sysnr填了'0'而不是'00',导致 SAP 网关端口拼接错误;第二嫌疑是防火墙只放行了业务网络端口,没放行33xx网关端口。解决:先把sysnr改成两位字符串;然后用nc -zv <ashost> 3300测试端口通不通,不通就找网络管理员。
另外,如果应用服务器前面有负载均衡设备,把ashost配成 VIP 地址很可能连接超时,因为 RFC 协议不遵循 HTTP 那种静态负载均衡的转发方式。解决是直接配置实际的应用服务器主机名或 IP,让 SDK 自己完成会话管理。
5.3 调用阶段:权限、接口和 Unicode
现象:连接成功,但conn.call('BAPI_MATERIAL_GETLIST')报RFC_AUTHORIZATION_FAILURE。原因:RFC 账号缺少该 BAPI 的授权对象,最常见的是S_RFC授权缺失。解决:在 SAP 的 SU01 事务里给账号加授权,授权的内容可以明确到功能组或函数名。授权不是看一遍代码就能绕过的,必须由 SAP 管理员操作。
现象:调用成功但返回的中文变成乱码,或字符串长度不对。原因:连接参数没有显式设置lang,且 SDK 和 SAP 之间的字符集协商用了非 Unicode。解决:连接参数里加'lang': 'ZH'或'EN';确认 SAP 系统是 Unicode 模式;在 pyRFC 较新版本里,还可以传参数RFC_INTERNAL控制内部编码转换。
5.4 编译阶段:Cython 版本和 Python 版本
现象:pip install pypyrfc报cythonize相关错误,堆栈里出现AttributeError: module。原因:Cython 版本过新或过旧,与 pyRFC 的源码构建不兼容。解决:固定 Cython 版本再重新编译,比如指定一个与当前 Python 兼容的版本,然后再次执行pip install pypyrfc --no-binary :all:。如果系统自带 Python 3.12,建议换到 3.10 或 3.11,很多扩展到 3.12 才出现的编译问题可以立刻消失。
5.5 架构一致性:Python 位数和 SDK 位数
现象:import pyrfc成功,但pyrfc.Connection初始化时进程直接崩溃,SIGSEGV 或Fatal Python error,不留下 Python traceback。原因:SDK 是 64 位,但 Python 解释器是 32 位,SDK 的指针运算在 32 位进程中越界。解决:用file命令确认 SDK 中的.so是 64 位,用python -c "import platform; print(platform.architecture())"确认解释器是 64 位,两边对齐后问题消失。
6. 进阶:多 SAP 系统配置管理、线程安全与调用前健康检查
最后分享一个我养成的习惯:永远把连接配置从代码里拆出去。尤其在生产环境要对接开发、测试、生产三套 SAP 系统时,代码里写死ashost和账号是过一天就翻车的写法。常见做法是维护一个systems.json,按环境名存连接参数,密码从环境变量里取,不落盘。
import json, os, socket, pyrfc def load_system(name): with open('/opt/rfc_demo/systems.json') as f: systems = json.load(f) cfg = systems[name].copy() cfg['passwd'] = os.environ.get('SAP_PASSWORD', cfg.get('passwd')) return cfg def rfc_port(sysnr): return 3300 + int(sysnr) def system_ok(cfg, timeout=3): with socket.create_connection((cfg['ashost'], rfc_port(cfg['sysnr'])), timeout=timeout): return True return False cfg = load_system('DEV') if system_ok(cfg): conn = pyrfc.Connection(**cfg) try: ret = conn.call('STFC_CONNECTION', REQUTEXT='healthcheck') print(ret['ECHOTEXT']) finally: conn.close()这套脚本的价值是:部署完先跑一次,能立即定位 SDK 路径、网络、权限三层问题;日常批处理启动前也建议先调用健康检查,避免把整个任务拖进超时重试。还有一个线程安全的点:pyRFC 的连接对象不能跨线程共用,每个线程必须独立创建Connection。如果要并发批量调用,可以在线程池里对每个线程初始化连接,而不是共享一个连接对象。
我在一个临时方案里因为贪图方便共享了连接,结果数据量大了之后偶发报错,最后定位到是 RFC 会话的线程安全问题。现在我的习惯是每个线程持有自己的连接,用完立刻关闭,宁可多几次建连,也不拿数据完整性冒险。希望帮到你——和 SAP 打交道,把环境变量和连接生命周期管好,这一层稳定了,后面的业务代码才值得信赖。
本文还有配套的精品资源,点击获取