简介在Linux服务器上搭建Python与SAP RFC接口的通信链路常受困于SDK编译、环境变量与依赖库配置。这份资料面向Python开发、运维以及SAP系统集成人员提供SAP NetWeaver RFC开发包nwrfc750P_5-70002752的核心组件配合pyrfc绑定库使Python程序能够直接调用SAP远程功能覆盖读取表数据、执行业务逻辑、触发工作流以及连接自检等常见场景。压缩包内含27个文件整体大小18.05MB。文件类型以C/C头文件、源码与动态链接库为主其中头文件.h用于接口声明C/CPP示例源码便于理解调用方式.so动态库负责运行时加载同时附带.ini配置示例、.mf与SIGNATURE.SMF元数据用于环境参数定义、版本完整性校验另有rfcexec、startrfc等可执行工具可直接调用测试。这些文件共同构成可编译、可运行、可验证的完整SDK包。资源保留lib、include、bin、demo、doc等典型目录结构层级清晰便于按include、lib、bin分别定位头文件、链接库与工具程序demo和doc中的示例也有助于梳理连接参数、sapnwrfc.ini配置以及SDK部署路径。当前已有1401人学习下载适合正在部署pyrfc环境、排查SDK缺失或运行时库不匹配问题的Linux开发者。1. Linux 上用 pyrfc 连 SAP一套 nwrfcsdk 就能跑通 RFC 调用在 Linux 服务器上通过 Python 调 SAP某企业级 ERP的 RFC 接口是最容易在环境层面卡住的事情。pyrfc 本身只是胶水真正干活的是 nwrfcsdk——它的编译版本、位数、许可证和系统库路径只要有一个对不上import pyrfc 就会以各种姿势失败。这篇笔记把 linux 下 pyrfc nwrfcsdk 的选型、安装、调通和排障完整走了一遍适用对象是数据工程师、运维和要写 SAP 接口脚本的 Python 开发者。顺手把 nwrfc750P 这个补丁包也验证了一遍踩过的坑都写在后面。2. 把 RFC 调用链路拆开pyrfc、nwrfcsdk 与网关的职责边界2.1 一次 RFC 调用到底经过了哪些环节很多人第一次接触时以为装了 pyrfc 就能连上 SAP结果连 import 都过不去。实际上一次 RFC 调用要经过四层每一层都可能成为故障点链路层级负责的事典型报错Python 脚本组织参数、解析返回值KeyError、TypeErrorpyrfc 扩展把 Python 字典转成 RFC 参数结构ModuleNotFoundErrornwrfcsdk 动态库处理 SAP 协议、鉴权、序列化libsapnwrfc.so: cannot open shared object fileSAP 网关 ABAP执行函数模块返回结果RFC_INVALID_PARAMETER、RFC_SYS_EXCEPTION我一般会先画这个链路再动手Python 报错不代表 Python 代码有问题很可能是 pyrfc 和 nwrfcsdk 之间的 ABI 不匹配SAP 侧报错也不一定是函数不存在可能是参数结构传错了。第一层和第二层之间是 C 扩展的边界第二层和第三层之间是动态库符号的边界第三层和第四层之间才是真正的网络协议。把这三条边界记清楚后面的排障效率能高一半。pyrfc 的角色是桥接它把 Python 的 dict 结构映射成 nwrfcsdk 需要的 RFC 参数结构再把返回的 RFC 结构解包回 Python 对象。它不实现 SAP 协议——协议全在 nwrfcsdk 里。所以 nwrfcsdk 的版本不对pyrfc 表现得再正常也会在 connect 阶段翻车。这个关系理解到位就不会在错误的层浪费时间。2.2 版本匹配是第一道坎nwrfcsdk、pyrfc 与 Python 位数网上能找到的 nwrfcsdk 版本不少常见命名是 nwrfc750P、nwrfc740 之类。750 对应 SAP NetWeaver RFC SDK 7.50P 代表 Patch 级别。选型时先别追新先确认三个维度Linux 发行版与 glibc 版本、Python 位数、pyrfc 版本。先说位数。pyrfc 是 C 扩展只能匹配同一位数的 Python 解释器。如果系统 Python 是 32 位而 nwrfcsdk 是 x86_64 编译的import pyrfc 会直接在加载动态库时报错。CentOS 7 或 Ubuntu 20.04 的官方源默认都是 64 位 Python但有些二次封装的环境会把 Python 编成 32 位这一步可以用一行命令确认python3 -c import struct; print(struct.calcsize(P) * 8)输出 64 说明解释器是 64 位的可以继续输出 32 就得换 Python 环境。位数对齐之后再看 glibc 版本。nwrfcsdk 7.50 需要 glibc 2.14 以上CentOS 6 这类老系统经常卡在这里。检查 glibc 用 ldd --version如果版本太低要么升级系统要么找旧版 SDK别硬编。pyrfc 版本对应关系也要留意。新版 pyrfc 3.x 要求 Python 3.7 以上并且对 nwrfcsdk 的补丁级别有最低要求。我个人习惯固定一套经过验证的组合Python 3.8/3.9 nwrfcsdk 750 pyrfc 2.6 或 3.0。这个组合在 CentOS 7 和 Ubuntu 20.04 上都跑过稳定。版本组合定下来之后目录路径、环境变量、连接参数都围绕这一套来写避免混搭。2.3 为什么选 RFC 而不是 OData / REST很多业务场景其实可以不碰 RFC用 SAP 的 OData 服务或者中间表就能解决。但如果你要调的函数模块是 RFC 使能的或者对实时性要求高OData 反而绕远。SAP 的 RFC 协议是二进制、长连接、面向函数调用的和 OData 的 HTTP JSON 风格差别很大选型时要从三个维度考虑方案适合场景开发成本实时性nwrfcsdk pyrfcABAP 函数模块、BAPI、需要事务控制中高OData / REST数据查询、Web 前端集成低中中间表 / IDoc批量同步、异步数据交换低低如果是一次性把 SAP 数据拉出来做分析用 OData 更省事但如果是写一个长期运行的接口服务要反复调用 BAPI 做创建、修改、提交事务RFC 的稳定性和事务语义更有优势。pyrfc 连的是 RFC 网关走的是 SAP 标准协议不需要在 ABAP 侧额外开发 HTTP service这是它作为接口通道的天然优势。选型别被语言生态带走先看 ABAP 侧暴露出来的接口是 RFC 还是 OData再定技术栈。3. 在 Linux 上把环境搭起来SDK 安装、环境变量与第一个连接3.1 下载并放置 nwrfcsdk目录结构与会话变量拿到 nwrfcsdk 之后第一件事不是解压就完而是规划放置路径。我习惯放在 /opt/sap/nwrfcsdk因为这个路径和设备上的其他应用没有冲突也方便统一做权限管理。解压之后目录结构长这样/opt/sap/nwrfcsdk/ ├── lib/ │ ├── libsapnwrfc.so │ └── ... ├── include/ │ ├── sapnwrfc.h │ └── ... └── doc/注意lib目录下必须有libsapnwrfc.so这个动态库。有些包解压后库文件在更深的子目录里或者是以.so.7.50带版本号的形式存在pyrfc 找的是libsapnwrfc.so这个不带版本号的符号链接。如果只有带版本号的文件要手动建一个软链接ln -s /opt/sap/nwrfcsdk/lib/libsapnwrfc.so.7.50 /opt/sap/nwrfcsdk/lib/libsapnwrfc.so接下来设置环境变量。pyrfc 运行时要通过SAPNWRFC_HOME找到 SDK 根目录LD_LIBRARY_PATH则负责让操作系统找到动态库。这两个变量写进/etc/profile.d/sapnwrfc.sh每次登录自动加载export SAPNWRFC_HOME/opt/sap/nwrfcsdk export LD_LIBRARY_PATH$SAPNWRFC_HOME/lib:$LD_LIBRARY_PATHSAPNWRFC_HOME和LD_LIBRARY_PATH缺一不可。前者是 pyrfc 内部定位头文件和库文件的依据后者是系统加载器找人动态库的依据。只设前者不设后者import 能过但 connect 会报找不到符号只设后者不设前者pyrfc 初始化阶段就可能抛异常。设置完用source /etc/profile.d/sapnwrfc.sh或重新登录让变量生效。3.2 安装 pyrfcpip 安装与源码编译两种路径环境变量就绪后安装 pyrfc 有两条路。优先走 pip 安装预编译 wheel因为 pyrfc 官方在 PyPI 上发布了多个 Linux 平台的 wheel装完即用pip install pyrfc如果 pip 安装时报找不到匹配版本或者下载的是源码包需要本地编译那就走 GitHub 源码安装。源码编译需要 Python 开发头文件和 cmakeDebian/Ubuntu 系先装依赖sudo apt-get install build-essential cmake python3-dev pip install githttps://github.com/SAP/PyRFC.git编译过程会把 nwrfcsdk 的头文件和库文件链接进来所以编译前必须确认SAPNWRFC_HOME已设置否则 cmake 找不到 SDK 会直接报错。pip wheel 和源码编译的差别在于wheel 是官方在特定环境编好的对 glibc 版本有下限要求源码编译是在你自己的机器上编能绕开一些 wheel 的兼容性问题但依赖本机工具链。能不编译就不编译省下的时间够调通一个接口了。安装完验证一下版本和动态库加载python3 -c import pyrfc; print(pyrfc.version)能打印版本号说明动态库加载成功。如果这里报ImportError: libsapnwrfc.so: cannot open shared object file优先查LD_LIBRARY_PATH有没有生效别急着重新安装。3.3 用 config 参数建立连接连接参数表与代码骨架连接 SAP 的参数有五个常用项ashost应用服务器、sysnr系统号、client客户端、user用户名、passwd密码。有些环境还要求 group 和 mshost那是负载均衡场景单机连不需要。配置文件我一般这么写[connection] ashost 10.10.10.10 sysnr 00 client 100 user RFC_USER passwd strong_password lang ZHsystnr是两位字符串00 是默认实例号client是三位客户端号SAP 允许一个实例下多个 client 隔离数据lang用 ZH 表示中文登录语言这直接关系到字段值的中文编码处理。注意 passwd 里如果有特殊字符在 Python 代码里要小心转义。Python 侧建立一个最小连接骨架import pyrfc config { ashost: 10.10.10.10, sysnr: 00, client: 100, user: RFC_USER, passwd: strong_password, lang: ZH, } conn pyrfc.Connection(**config) print(conn.get_system_info()) conn.close()pyrfc.Connection(**config)是标准的连接入口**config把字典展开成关键字参数传给构造函数。get_system_info()是 SDK 内置的查询方法不需要 ABAP 侧额外授权用来验证连接是否打通最合适。conn.close()保证连接归还给网关不关闭连接的话短脚本跑完没事长进程里会慢慢耗尽 SAP 侧允许的连接数。3.4 最小可运行脚本查系统信息并读一张表连接打通之后真正的业务调用长这样。以调用一个简单的 RFC 函数模块为例比如查询系统日期或读取某张自定义表import pyrfc config { ashost: 10.10.10.10, sysnr: 00, client: 100, user: RFC_USER, passwd: strong_password, lang: ZH, } conn pyrfc.Connection(**config) # 调用 RFC_PING 检查网关连通性 result conn.call(RFC_PING) print(ping result:, result) # 调用 BAPI 读取数据传入导入参数 import_params {MAX_ROWS: 10} try: result conn.call(BAPI_MATERIAL_GETLIST, **import_params) for row in result.get(MATLIST, []): print(row.get(MATERIAL), row.get(MAT_DESC)) except pyrfc.RFCError as e: print(RFC call failed:, e) finally: conn.close()conn.call的第一个参数是要调用的 RFC 函数模块名后面的关键字参数对应 ABAP 函数里的导入参数或表参数。BAPI_MATERIAL_GETLIST是一个常见的物料查询 BAPIMAX_ROWS限制返回条数返回结果里的MATLIST是表参数对应 ABAP 侧的内表。RFCError是 pyrfc 抛出的统一异常类所有 ABAP 侧报错都会包装成它打印出来的 e 里通常带着 ABAP 的异常类型和消息文本这个文本是排查业务参数最关键的信息。这个脚本能跑通说明链路四层全部正常。后面要做的事就是把config参数配置化、把conn.call封装成通用函数再考虑连接池和重连逻辑。很多生产环境的坑不是 BAPI 报错而是连接层面的问题被业务代码吃掉所以最小脚本跑通之后先别急着写业务把连接生命周期管好。4. 避坑手册五个高频故障的现象、原因与解决4.1 import 阶段报 libsapnwrfc.so 找不到现象import pyrfc直接抛ImportError: libsapnwrfc.so: cannot open shared object file。原因LD_LIBRARY_PATH没生效或者动态库文件本身缺失。最常见的是用sudo执行 Python 时环境变量被清掉sudo 默认重置环境变量/etc/profile.d 里设的变量到不了 root 会话。解决先手动导出环境变量再跑脚本export LD_LIBRARY_PATH/opt/sap/nwrfcsdk/lib:$LD_LIBRARY_PATH确认能 import 之后再在调用脚本的外层包装一个启动脚本每次执行前强制 source 环境变量文件。我习惯在 Python 代码里用os.environ.setdefault补一次双保险。4.2 nwrfc750P 解压后缺少符号链接现象ls lib/能看到libsapnwrfc.so.7.50但没有libsapnwrfc.so运行时同样报找不到库。原因nwrfc750P 的 Linux 包在部分版本里只带带版本号的库文件pyrfc 通过SAPNWRFC_HOME定位后用系统加载器查找的是无版本号的libsapnwrfc.so软链接缺失导致加载失败。解决手动创建软链接ln -s libsapnwrfc.so.7.50 libsapnwrfc.so。这个操作在验证 nwrfc750P 时一定会遇到建议解压后第一时间检查并补齐。4.3 ABAP 侧报 RFC_INVALID_PARAMETER 但参数名明明没错现象conn.call时 ABAP 返回RFC_INVALID_PARAMETERPython 侧参数名和 RFC 函数模块的导入参数名看起来一致。原因大小写不一致。SAP 函数模块参数名在 ABAP 侧是大写pyrfc 传参时如果写成小写SDK 不会自动转大写直接判定参数不存在。另一个常见原因是参数类型不匹配ABAP 的 NUMC 类型期望字符串传了 int 也会报这个错。解决把参数名统一写成大写并在调用前打印 RFC 函数的参数元数据meta conn.get_function_description(BAPI_MATERIAL_GETLIST) for p in meta.parameters: print(p[name], p[parameter_type], p[type_code])get_function_description返回的参数列表里能看到每个参数精确的名称和类型码。拿到元数据再组织调用参数能避免大部分手写参数名导致的低级错误。这个函数是排障利器遇到参数类报错先用它。4.4 连接数耗尽与半开连接现象脚本跑一段时间后新的连接建立失败SAP 侧报 RFC_NO_AUTHORIZATION 或连接被拒绝。原因长进程里每次调用都新建连接用完没 close或者 close 之后底层 socket 没有立刻释放。SAP 网关默认允许的连接数有限超过上限后新连接会被拒绝。解决做了三层处理。第一层所有调用走 context manager 或用 try/finally 保证 close。第二层做模块级连接复用一个进程只维护一个连接。第三层在 SAP 侧监控连接数发现问题时用事务代码 SMGW 查看当前连接手工清理。生产环境建议直接做一个连接池单连接复用能避开绝大多数连接数问题。4.5 中文字段乱码现象读取到的中文物料描述变成???或乱码但数据库里存的是正常中文。原因连接lang参数没设或者 ABAP 侧返回的非 Unicode 编码没有被正确转换。RFC 协议默认按登录语言编码返回文本langZH缺失时SDK 可能按英文代码页解析中文字节序列。解决连接配置里显式加langZH同时在代码层面要求返回的字符串按 UTF-8 处理。如果乱码依旧检查 SAP 系统是否启用了 Unicode非 Unicode 系统需要额外指定codepage参数。这个问题在 nwrfc750P 上比旧版更敏感因为新 SDK 对代码页的默认行为有变化。5. 验证连通之外把 RFC 调用封装成可复用的数据接口最小脚本跑通只代表链路通离生产可用还差封装。我通常把连接管理和调用逻辑包成一个模块对外暴露一个拉数据的函数业务代码不直接碰 pyrfc。这样做的直接收益是换服务器、换 SDK 版本时只改一个配置文件和一处 import其他代码零改动。# sap_rfc_client.py import os import pyrfc _CONFIG { ashost: os.environ.get(SAP_ASHOST, 10.10.10.10), sysnr: os.environ.get(SAP_SYSNR, 00), client: os.environ.get(SAP_CLIENT, 100), user: os.environ.get(SAP_USER), passwd: os.environ.get(SAP_PASSWD), lang: ZH, } _conn None def get_connection(): global _conn if _conn is None: _conn pyrfc.Connection(**_CONFIG) return _conn def safe_close(): global _conn if _conn is not None: _conn.close() _conn None def call_function(fname, **params): conn get_connection() try: return conn.call(fname, **params) except pyrfc.RFCError: safe_close() # 重连前先释放旧连接 conn get_connection() return conn.call(fname, **params)这个封装里有两个关键设计第一连接全局复用避免反复握手第二调用失败时关闭旧连接并重建一次解决网络抖动导致的半开连接。密码不走配置文件从环境变量注入避免密钥落到代码仓库里。从那以后我每次部署新的接口服务都强制走一遍这个流程先用最小脚本验证四层链路再套封装最后跑一遍异常注入测试——把密码故意改错、把 SAP 服务器地址改成不可达确认报错信息和重连逻辑符合预期。这些步骤看起来繁琐但能挡掉生产环境一半以上的半夜告警。希望帮到你。本文还有配套的精品资源点击获取