☰
Linux下Python调用SAP RFC:PyRFC与nwrfcsdk从零部署指南
2026/10/2 21:31:43 网站建设 项目流程

简介:面向有一定Linux基础的程序员与SAP系统集成工程师,本压缩包整合了通过Python的pyrfc库连接SAP所需的nwrfcsdk组件,旨在解决非ABAP代码环境下调用SAP远程函数模块时缺少运行库与开发接口的问题。压缩包采用zip格式封装,共27个文件,大小18.05MB,内含nwrfc750P_5-70002752版本的SDK,文件类型涵盖c/cpp/h源码、so动态链接库、txt/ini配置说明、MF清单文件以及bin目录下的可执行工具等,其中头文件用于接口声明,动态链接库用于运行时调用,源码示例可帮助理解开发方式。该项资源已有1384人学习下载,在SAP接口对接、系统集成与自动化运维场景中具有较强参考价值。借助此包,读者可以省去从官网逐个获取组件的繁琐步骤,结合常见连接示例快速完成环境变量配置、RFC连通性测试与函数调用;同时,基于附带的头文件和示例代码,还能进一步扩展实现读取表数据、触发业务逻辑等工作流开发,为后续二次集成提供可靠基础的支撑。无论是初学SAP接口开发,还是排查已有项目依赖,都能从中获得有效帮助。

1. 项目整体思路:为什么是 PyRFC + nwrfcsdk

1.1 最终要达成的效果

接 SAP 外围系统的需求这几年越来越多,最常见的场景是:物料主数据要不要同步?BOM 要不要定期拉下来?生产订单状态能不能推送到业务中台?抛开业务逻辑不谈,第一步技术动作几乎都一样——让 Python 进程能直接调 SAP 的 RFC 函数模块。PyRFC 是 SAP 官方维护的 Python 绑定库,它不直接实现 RFC 协议,而是封装了 SAP 的底层通信能力,这个底层就是 nwrfcsdk。换句话说,PyRFC 是“方向盘”,nwrfcsdk 是“发动机”,两个缺一不可。

我这篇文章要解决的是 Linux 服务器上从零开始跑通这条链路的完整过程:装 SDK、配环境变量、装 PyRFC、测连接、调业务函数、处理常见报错。适合两类人:一类是刚接手 SAP 接口开发、对 RFC 体系还不太熟的后端工程师;另一类是已经在 Windows 上跑通了 PyRFC、现在要迁移到 Linux 服务器的同学。

1.2 技术选型的几个理由

在选型阶段我其实对比过三条路:

  • PCo(SAP Process Integration/Process Orchestration 能干的活),功能全面但授权成本高,而且部署链路重,对一个只需要拉几张表的项目来说属于杀鸡用牛刀。
  • 直接用 SAP Java Connector(JCo),适合 Java 技术栈,但要在 Python 服务里引 Java 网关,进程管理麻烦,日志也不好统一。
  • PyRFC + nwrfcsdk,Python 生态直接衔接 pandas、定时框架、FastAPI,后面做数据同步或接口服务都很顺。

最后选 PyRFC,核心原因是它和 Python 的亲和性实在好。数据取回来就是 list of dict,转 DataFrame 一行代码,做报表、做接口、做归档都很方便。官方库一路升级到现在,Python 3.7 到 3.11 都有对应 wheel,省掉很多编译折腾。

1.3 完整调用链路

从架构上看,整条链路是这样:

Python 进程 ↓ 导入 pyrfc PyRFC 绑定层 ↓ 加载 libsapnwrfc.so nwrfcsdk 动态库 ↓ RFC 协议通信(基于 SAP NetWeaver 网关) SAP 应用服务器 ↓ 执行远程函数模块 RFC/BAPI 函数

RFC 协议本质上是 SAP 专有的二进制协议,不是 HTTP、不是 WebService,所以必须有 SDK 帮你在底层做报文组装和解析。nwrfcsdk 在 Linux 上就是一组 .so 动态库,PyRFC 通过 ctypes 调用这些动态库。明白了这条调用链,后面所有环境变量问题、so 文件找不到问题、版本不匹配问题,基本都能看出来是哪一层出了岔子。

2. Linux 下的环境准备:SDK、依赖、变量

2.1 系统与基础软件检查

动手之前先把服务器底子摸一遍。先用几条命令确认环境:

cat /etc/os-release uname -m python3 --version gcc --version ldd --version | head -1

比较理想的环境是 64 位 Linux(x86_64),装好 Python 3.7 以上版本,系统里有 gcc 和 make 备用。SDK 对操作系统没有太强的绑定限制,官方标注支持常见的 SLES、RHEL、Ubuntu,实际操作中 CentOS、Debian、国产 Linux 发行版我也都跑过,结论是只要 glibc 版本不是太老,基本都能用。

如果 Python 是源码编译安装的,建议确认一下编译时的配置是否包含共享库支持,否则后面 import 时会遇到奇怪问题。用发行版自带的 python3-dev / python3-devel 更省心。

2.2 下载并部署 nwrfcsdk

nwrfcsdk 需要从 SAP 官方渠道下载,选择 Linux on x86_64 的版本。登录 SAP Software Center 之后搜索 “NW RFC SDK” 就能找到对应安装包,文件名里通常带有平台和版本标识,比如 nwrfcsdk_xxx_linux_x86_64.tgz。

下载后解压到固定目录,我一般放/opt/sap/nwrfcsdk,统一管理,也方便后续多个项目复用:

sudo mkdir -p /opt/sap sudo tar -xzf nwrfcsdk_xxx_linux_x86_64.tgz -C /opt/sap

解压后目录结构大概是:

/opt/sap/nwrfcsdk ├── include │ └── sapnwrfc.h ├── lib │ ├── libsapnwrfc.so │ ├── libsapucum.so │ ├── libsapcrypto.so │ └── ... └── doc

判断 SDK 是否完整,可以检查 lib 目录下有没有这些核心动态库,以及 include 目录下有没有头文件。如果缺文件,后面 PyRFC 加载必出幺蛾子。

2.3 配置环境变量与 sapnwrfc.ini

环境变量是整个项目里最容易踩坑的地方。Python 进程加载 nwrfcsdk 时,需要能在系统的动态库搜索路径里找到 libsapnwrfc.so 及其依赖的其它 .so 文件,所以必须配置LD_LIBRARY_PATH:

export SAPNWRFC_HOME=/opt/sap/nwrfcsdk export LD_LIBRARY_PATH=$SAPNWRFC_HOME/lib:$LD_LIBRARY_PATH

建议直接把这两行写入/etc/profile.d/sapnwrfc.sh,这样重启或重新登录都会自动生效。写入后记得执行source /etc/profile.d/sapnwrfc.sh或者重新登录 shell,再用echo $LD_LIBRARY_PATH验证。

除了环境变量,PyRFC 还支持通过配置文件指定连接目标。SAP 的 RFC 客户端习惯用sapnwrfc.ini配置一套连接目标,运行时直接用 dest 名称连接,切换系统不用改代码。文件可以放在当前目录、用户主目录或/etc下。示例:

[DEV] dest=DEV ashost=10.1.1.10 sysnr=00 client=100 lang=EN

这里ashost是 SAP 应用服务器的 IP 或主机名,sysnr是系统号,client是客户端。用户名密码我一般不写在 ini 里,而是连接时动态传入,避免泄漏。

2.4 Python 虚拟环境确认

高版本的 Linux 发行版默认会区分系统 Python 和用户 Python,直接 pip 安装容易装到错误环境或碰到 PEP 668 的限制。我的习惯是为每个项目建独立虚拟环境:

python3 -m venv /opt/sap-connector-venv source /opt/sap-connector-venv/bin/activate

虚拟环境的好处是能隔离依赖,后续如果要升级 PyRFC 或者切换 Python 版本,不会影响服务器上其它项目。环境准备好之后,再进入第三步安装 PyRFC。

3. 安装 PyRFC 并跑通首个连接测试

3.1 pip 安装与验证

在虚拟环境里直接安装:

pip install pyrfc

如果网络环境允许,PyRFC 的 Linux wheel 会自动拉取;如果 pip 源里找不到对应平台的 wheel,也可以指定 SAP 官方 Python Package Index 源:pip install pyrfc --index-url https://pypi.org/simple。安装完成先做一个最小验证:

python -c "from pyrfc import Connection; print(Connection)"

能正常打印出类对象,说明 PyRFC 已经被正确导入,但这不代表 nwrfcsdk 加载成功,真正加载是创建连接的时候才发生的。所以下一步直接做连接测试。

3.2 用 RfcPing 验证连通性

创建连接最简单的写法是直接把连接参数以字典形式传入:

from pyrfc import Connection conn = Connection( user='BCUSER', passwd='your_password', ashost='10.1.1.10', sysnr='00', client='100', lang='EN', ) try: result = conn.call('RFC_PING') print("连接成功,RFC_PING 返回:", result) finally: conn.close()

RFC_PING 是 SAP 自带的连通性测试函数,不依赖任何业务配置,只要能调用它,就说明整条链路已经通了——Python → PyRFC → nwrfcsdk → SAP 网关。我第一次跑通时把输出打出来看到的返回是空 dict,但没有任何异常,那一刻心里的石头才落地。

3.3 连接参数拆解

初学者经常被一堆连接参数搞糊涂。我把常用的参数说明放在下表里:

参数含义典型值示例
ashostSAP 应用服务器地址10.1.1.10
sysnr系统号,两位数字00、01
client客户端100、800
user调用账号BCUSER
passwd密码不写死在代码里
lang登录语言EN、ZH
snc_partnernameSNC 配置时的伙伴名p:CN=...
use_snc是否启用安全网络通信0/1

注意sysnr和client都是字符串,不要传成整数,PyRFC 对类型比较敏感。ashost在早期版本的 SDK 里也叫mshost,如果连接报参数不识别,优先检查 SDK 和 PyRFC 版本是否配套。

3.4 在服务器上保存配置的小建议

连接参数里最敏感的是密码。直接在代码里明文写 password 显然不合适,尤其是代码还要提交到仓库。我的做法是读环境变量:

import os from pyrfc import Connection conn = Connection( user=os.environ.get('SAP_USER'), passwd=os.environ.get('SAP_PASSWD'), ashost=os.environ.get('SAP_HOST'), sysnr=os.environ.get('SAP_SYSNR', '00'), client=os.environ.get('SAP_CLIENT', '100'), lang='EN', )

配合.env文件和 python-dotenv 或者 docker secret 都行。另外一个细节是:长连接能力不要太频繁地开关,后面并发部分会再展开。

4. 真实业务函数调用:BAPI 传参与拿结果

4.1 读取物料清单作为示例

连通性测试通过只能证明“能连”,真正干业务还得看函数调用怎么写。我这里用 BAPI_MATERIAL_GETLIST 作为示例,它的作用是按条件查询物料清单。

先看一个完整例子:

import os import pandas as pd from pyrfc import Connection def get_material_list(material_type): conn = Connection( user=os.environ['SAP_USER'], passwd=os.environ['SAP_PASSWD'], ashost=os.environ['SAP_HOST'], sysnr='00', client='100', ) try: result = conn.call( 'BAPI_MATERIAL_GETLIST', MAXROWS=100, MATERIAL_TYPE=material_type, ) rows = [] for item in result['MATLIST']: rows.append({ 'material': item['MATERIAL'], 'description': item['MATL_DESC'], 'material_type': item['MATL_TYPE'], }) return pd.DataFrame(rows) finally: conn.close() if __name__ == '__main__': df = get_material_list('FERT') print(df.head())

这里有两个关键点。第一,函数参数名必须和 SAP 函数模块的导入参数名保持一致,大小写也要一致,比如MATERIAL_TYPE不能写成material_type。第二,返回结果是一个 dict,dict 里的键对应函数的导出参数或表参数,比如MATLIST就是物料清单表。

4.2 参数结构:IMPORT/EXPORT/TABLE 与 dict 映射

SAP 的 RFC 函数模块参数大体分四类:导入参数、导出参数、变更参数、表参数。PyRFC 调用时的规则很简单:

  • 导入参数直接作为 call 方法的关键字参数传入。
  • 导出参数不需要传,在返回结果里取。
  • 表参数如果是要传入数据的,传一个 list of dict;如果是返回数据的,在结果里取。
  • 结构体类型参数,传 dict 嵌套。

比如某个函数要求传入一个结构体:

result = conn.call( 'BAPI_SOME_FUNCTION', STRUCTURE_PARAM={ 'FIELD1': 'value1', 'FIELD2': 'value2', }, TABLE_INPUT=[ {'LINE_ID': 1, 'VALUE': 'A'}, {'LINE_ID': 2, 'VALUE': 'B'}, ], )

如果对某个字段的类型不确定,可以先在 SAP 事务代码 SE37 里查看函数模块的“导入/导出/表参数”页签,字段名和数据类型都写得清清楚楚。这是调 BAPI 前必做的功课,比反复试错快得多。

4.3 事务型 BAPI 的提交与回滚

很多 BAPI 本身是事务型的,比如创建采购订单、过账物料移动。这类函数调用成功后,数据并不是立刻落库,还需要显式调用提交函数。常见写法:

try: result = conn.call('BAPI_GOODSMVT_CREATE', ...) ret = result['RETURN'][0] if ret['TYPE'] == 'S': conn.call('BAPI_TRANSACTION_COMMIT', WAIT='X') print('过账成功,凭证号:', ret['MESSAGE_V1']) else: conn.call('BAPI_TRANSACTION_ROLLBACK') print('过账失败:', ret['MESSAGE']) except Exception as e: conn.call('BAPI_TRANSACTION_ROLLBACK') raise

这里有个容易忽略的坑:BAPI_TRANSACTION_COMMIT的WAIT参数要传字符串'X',不是布尔值 True。传错类型在调用期不报错,但可能不会真正提交,留下诡异的“明明成功了却没有数据”的问题。

4.4 大批量数据的性能体感

PyRFC 直连这种方案,单次调用传参和接收数据的效率比 WebService 高不少,但也不能无限制一把梭。我实际遇到过一张 10 万级的 BOM 表,直接一次性取回会占掉大量内存,还容易触发 SAP 侧的资源限制。

经验做法是:先在 SAP 函数里看有没有支持分页的参数。像 BAPI_MATERIAL_GETLIST 可以配合MAXROWS限制行数,每次取一批,批与批之间用游标或条件继续取。如果是更大的量级,建议走 SAP 的 IDoc 或 RFC 接口分批导入导出,而不是在一棵树上吊死。

5. 常见问题排查与避坑实录

5.1 共享库找不到:libsapnwrfc.so 报错

最典型的报错是:

ImportError: libsapnwrfc.so: cannot open shared object file: No such file or directory

看到这个基本可以断定是动态库路径没配置好,或者 SDK 没解压完整。排查步骤按顺序来:

echo $LD_LIBRARY_PATH ls /opt/sap/nwrfcsdk/lib/ ldd /opt/sap/nwrfcsdk/lib/libsapnwrfc.so

如果 LD_LIBRARY_PATH 没输出,说明环境变量没生效,重新 source profile 文件。如果 ldd 输出里有not found的行,说明 SDK 依赖的其他系统库缺失,按缺失的库名安装对应系统包即可。这个报错还有一个变体是运行在 systemd 服务里,服务启动时没有继承 profile 里的环境变量,需要在 service 文件里显式加Environment=LD_LIBRARY_PATH=/opt/sap/nwrfcsdk/lib。

5.2 SAP 连接失败:网络、端口与账号

另一个高频报错是:

RFC_CONNECTION_ERROR: connection refused

这通常是网络层问题。SAP 的 RFC 通信走的是网关端口,端口号由系统号计算得出:系统号为 00 时,网关端口一般是 3300,系统号为 01 时是 3301。如果中间有防火墙,记得放通这些端口。排查时先在服务器上测试端口通不通:

telnet 10.1.1.10 3300

端口通了还报错,就检查账号权限。调用 RFC 需要账号有S_RFC授权对象,很多新手拿了一个只允许登录的账号,SE37 里能看到函数,但外网调用被拒绝,报错信息反而不明显。建议在 SAP 侧用事务代码 PFCG 给账号配置 RFC 服务权限的角色。

5.3 pip 安装或导入失败:Python 版本不匹配

PyRFC 版本和 Python 版本强相关。如果你用的 Python 是 3.12 而当前 PyRFC 版本还不支持,pip install 可能直接报错或找不到 wheel。这时候有两条路:一是把 Python 降回 PyRFC 支持的版本,二是从源码编译安装pyrfc,但源码编译要求系统具备 Python 头文件和编译工具链,成本更高。我一般在生产环境选用发行版自带的 Python 3.8 或 3.10,稳定,wheel 也全。

5.4 连接泄漏与并发调用的处理

刚开始写脚本经常犯一个毛病:每调一个函数就 new 一个 Connection,用完即抛弃。这样在并发量上去之后,SAP 侧的会话数会瞬间被打爆,而且频繁建立连接本身也很耗时。我的做法是做一个线程级连接复用:

import threading class SapConnectionFactory: _local = threading.local() @classmethod def get_connection(cls): conn = getattr(cls._local, 'conn', None) if conn is None: conn = Connection(...) cls._local.conn = conn return conn

这样同一个线程内复用连接,不同线程各持一个连接,既避免了连接风暴,也规避了 PyRFC 连接对象跨线程使用可能带来的死锁问题。定时任务场景下,我还会在每次调用前先 ping 一下,连接断了就重建,保证任务长期稳定运行。

5.5 密码安全与多系统配置

生产环境往往不止一套 SAP 系统,开发、测试、生产各一套,连接参数各不相同。我建议把每个系统的连接参数放进独立的配置文件或环境变量组,用 dest 区分。密码管理可以用系统的 keyring 或专门的密钥管理服务,至少不要写在代码仓库里。配置变更时只改环境变量,代码不动,后续交接也清晰。

我还留了一个小习惯:每个连接脚本最后一定在 finally 里调用 conn.close(),或者用上下文管理器包一层。虽然 Python 程序退出后系统会回收资源,但 SAP 侧的会话不会立刻释放,堆积多了会影响整个 SAP 系统性能。做接口服务长期运行时,这个问题尤其突出。

最后再分享一点个人经验

我在这条链路上踩得最多的坑,不是 PyRFC 本身,而是环境变量和版本匹配。第一次在国产 Linux 服务器上部署时,明明按照官方文档配好了,import 就是不通过,最后发现是系统 glibc 版本比 SDK 要求的低了一截。后来我养成一个习惯:拿到新服务器先跑一遍 ldconfig,再跑一遍最小的 RfcPing 测试,确认底色没问题再上业务代码。这个思维也建议你保留——先小步快跑,再展开做功能。后面你想把这个方案扩展成 FastAPI 接口服务,或者加上定时同步任务,都是在已验证的连接基础上做包装,不会再有“基础链路不靠谱导致业务代码白写”的风险。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询