
简介面向在 Linux 环境中用 Python 对接 SAP 系统的开发与运维人员这份 SDK 资源包为 pyrfc 连接 SAP 提供了必备的 nwrfcsdk 依赖对应构建版本 nwrfc750P_5-70002752可避免自行寻找、编译底层 C 库的繁琐过程。压缩包共 27 个文件整体 18.05MB内容围绕 nwrfc750P 主压缩包展开解压后涵盖 include、lib、demo、doc 等典型目录文件类型包括 6 个 h 头文件、5 个 c 源文件、3 个 so 动态库以及 cpp 示例、txt 说明、ini 参数和 SMF 签名文件基本满足 SDK 部署、编译配置与运行验证需求。已有 1384 人学习下载适合需要做 SAP 集成、自动化数据交换或 RFC 接口调用的 Python 开发者。借助包内 SDK、示例代码与配置说明读者不仅可以完成 nwrfcsdk 解压安装、LD_LIBRARY_PATH 及 sapnwrfc.ini 设置还可以参考演示代码调用 STFC_CONNECTION 等函数测试连接从而在实际项目中快速打通 Linux 到 SAP 的 RFC 通信链路。若需处理常见依赖缺失、路径配置和版本匹配问题这份材料也能提供直观的参考。 搞了这么多年Linux环境下的业务系统对接我越来越确信一件事很多项目里最难的不是业务逻辑本身而是那些“看起来只要装个库就行”的底层依赖。前阵子有个项目需要把外围系统的物料主数据实时同步到SAP技术选型时绕了一圈最后还是回到经典的Python pyrfc nwrfcsdk这条路上。这套方案本身不复杂但如果你没在Linux上走过一遍完整流程大概率会被SDK的安装位置、动态库搜索路径、SAP连接参数这几个环节卡住。这篇文章就把我从零开始部署、调通、排错的全过程拆开来讲包括方案选型的原因、每一步操作背后的原理以及那些文档里不会写的坑。1. Python连SAP的方案选型为什么绕不开RFC和nwrfcsdkSAP系统与外部交互的方式其实不少RFC/BAPI、IDoc、Web Service、OData、中间件表同步等等。但在实际项目里RFC仍然是最高频、最底层的通信方式。原因很现实老系统的自定义函数模块大多是RFC类型的BAPI底层也跑在RFC协议上甚至很多OData服务最终还是转发到RFC函数模块上处理的。所以只要你想稳定、高效地和SAP做数据交换理解并且会用RFC基本是绕不开的。Python这边连接RFC的库最主流的就是pyrfc。它不是SAP官方出品的独立工具而是SAP官方提供的RFC SDK就是nwrfcsdk的Python绑定层。也就是说pyrfc本身不做通信它只是一个翻译层真正干活的是libsapnwrfc.so这套动态库。这个关系非常重要很多人在安装时出错就是因为没搞明白pyrfc和nwrfcsdk是两个东西前者是pip包后者是SAP的二进制SDK两者缺一不可。为什么不直接用Web Service或者中间件在我这个场景里SAP侧早就写好了大量RFC函数模块比如物料创建、BOM维护重新封装成Web Service成本太高而且业务部门对现有交互逻辑很满意。用RFC直连外围系统发起调用SAP网关处理后直接返回结果实时性和事务性都更有保障。相比之下中间件表同步适合大数据量的异步场景但实时性差Web Service适合跨平台但性能和调试成本都不如RFC直接。整体架构可以概括成一条链Python业务代码发起调用pyrfc把Python字典翻译成RFC协议的数据结构nwrfcsdk负责和SAP网关通信最终在SAP端执行对应的函数模块并返回结果。理解这条链路后后续所有排查工作都有了方向问题要么出在调用参数上要么出在动态库加载上要么出在SAP端权限配置上。适用人群方面这套方案特别适合两类场景一是已有SAP系统需要做外围系统集成的开发二是做数据迁移、报表抽取、自动化运维的工程师。如果你连SAP GUI都还没装过建议先找个SAP测试环境熟悉一下事务码SE37函数模块查看和SE80对象导航再来碰RFC。2. nwrfcsdk安装与目录规划第一个最容易翻车的环节nwrfcsdk的获取方式比较特殊它不在pip里也不在apt源里必须从SAP官网下载。在SAP Support Portal搜索“NW RFC SDK”登录S-user后就能找到对应Linux版本的压缩包。下载时注意两点一是选择跟你系统架构匹配的版本x86_64服务器就下Linux x86_64版ARM服务器要单独找对应版本二是看清是tar.gz格式还是RPM格式我习惯用tar.gz因为解压后放哪、环境变量怎么配都自己可控。SAP账号问题经常卡住很多初学者如果公司有SAP服务合同可以找BASIS同事帮忙下载这个SDK虽然没有额外费用但必须有能进Support Portal的账号。解压位置建议统一规划不要随手扔在/tmp或者home目录。我一般放在/opt/sap/nwrfcsdk这样权限和路径都清晰。解压后目录里有三个关键的组成部分lib目录存放libsapnwrfc.so和libsapucum.so等动态库include目录是SAP提供的C头文件pyrfc安装时编译要用demo目录里有一些示例程序可以用于快速验证SDK本身是否正常。环境变量配置是这一环节的重中之重。需要设置两个变量export SAPNWRFC_HOME/opt/sap/nwrfcsdk export LD_LIBRARY_PATH$SAPNWRFC_HOME/lib:$LD_LIBRARY_PATHSAPNWRFC_HOME是给pyrfc找头文件和库文件用的LD_LIBRARY_PATH则是给系统运行期加载动态库用的。很多人在安装时明明一切都正常一运行import pyrfc却报RFC_LIBRARY_NOT_FOUND99%的原因就是LD_LIBRARY_PATH没设对。为了省心建议直接写进全局配置文件sudo tee /etc/profile.d/sapnwrfc.sh EOF export SAPNWRFC_HOME/opt/sap/nwrfcsdk export LD_LIBRARY_PATH$SAPNWRFC_HOME/lib:$LD_LIBRARY_PATH EOF source /etc/profile.d/sapnwrfc.sh设置完之后先做一次基础验证ls -l $SAPNWRFC_HOME/lib/libsapnwrfc.so echo $LD_LIBRARY_PATH如果文件存在且路径正确再用ldd检查一下SDK自身的依赖是否满足ldd $SAPNWRFC_HOME/lib/libsapnwrfc.so这一步很多人会跳过但实际上很关键。SDK本身依赖一些系统库比如libssl等如果缺失后续pyrfc调用时会出现诡异崩溃。看到not found就要先解决系统依赖再继续往前走。3. Linux环境依赖与pyrfc安装把动态库问题扼杀在摇篮里在装pyrfc之前先把系统的编译工具链和基础依赖准备好。不同发行版包名略有差异我以Ubuntu/Debian和CentOS/RHEL两套体系分别说明。Ubuntu下需要这些sudo apt update sudo apt install -y build-essential python3-dev libssl-devCentOS下对应的是sudo yum groupinstall -y Development Tools sudo yum install -y python3-devel openssl-develpython3-dev或python3-devel是必须的因为pyrfc在安装时需要通过Cython把Python调用编译绑定到SDK上没有Python头文件会直接编译失败。有些人喜欢用虚拟环境完全没问题但记得虚拟环境是基于带python3-dev的系统Python创建的否则一样会踩坑。接下来安装pyrfcpip install pyrfc新版本的pyrfc通常直接提供预编译的wheel包安装速度很快。如果你安装的是老版本或特殊平台pip会现场拉取源码编译此时需要确保SAPNWRFC_HOME已经正确设置否则编译时找不到头文件。判断安装是否成功的标准很简单python -c import pyrfc; print(pyrfc.version)输出版本号就说明pyrfc本身没问题。但注意这一步成功不代表能连SAP只代表Python绑定层和SDK的动态库都能正常加载。真正验证连接需要SAP侧的网络和账号信息。还有一个容易忽略的文件叫sapnwrfc.ini。pyrfc官方文档里提到它主要用于配置RFC连接的默认参数和日志级别但实际使用中你完全可以在代码里直接传全部连接参数这个ini文件不是必须的。不过如果你想开启RFC跟踪日志或者统一配置trace级别就可以在项目目录放一个sapnwrfc.ini内容大致如下[connection] trace3设置trace3会生成比较完整的RFC通信日志排错时很有用但生产环境不建议开日志量太大。4. 连接参数与最小可用代码先跑通一次RFC调用环境都准备好后接下来就是建立连接。RFC连接参数这几个字段每个都很关键先逐个说清楚参数名含义示例ashostSAP应用服务器IP或主机名192.168.1.100sysnrSAP系统编号两位字符串00client客户端编号三位字符串800userSAP用户RFCUSERpasswd密码******lang登录语言EN或ZHashost是应用服务器地址不是数据库地址也不是网关地址。SAP系统通常用SAPGUI登录时看到的服务器地址就是ashost。sysnr和ashost共同决定了RFC通信端口端口号的计算方式是33xx其中xx就是系统编号。比如sysnr是00RFC端口就是3300sysnr是10端口就是3310。一个常见的操作失误是把sysnr写成数字0注意这里必须传字符串00。另外密码字段的键名是passwd不是password差一个字母连接就会报参数错误。最小可用代码如下from pyrfc import Connection conn Connection( ashost192.168.1.100, sysnr00, client800, userRFCUSER, passwdPssw0rd, langEN ) print(连接正常alive , conn.alive) conn.close()第一次跑通时我建议先调用一个最基础的RFC函数模块RFC_PING它不做任何业务操作纯粹验证通信链路from pyrfc import Connection conn Connection( ashost192.168.1.100, sysnr00, client800, userRFCUSER, passwdPssw0rd, langEN ) result conn.call(RFC_PING) print(RFC_PING返回, result) conn.close()如果RFC_PING能正常返回无异常说明SAP网关注册、账号认证、RFC权限全都通过了。这个时候再往后做业务调用心里就有底了。如果RFC_PING就报错那问题大概率不在业务层面而在网络或账号配置上。这里要特别强调不要在代码里硬编码密码。我习惯把连接信息放到环境变量或外部配置文件中代码里用os.environ读取。这不只是安全问题还有一个现实好处不同环境的SAP服务器IP、客户端号不一样用环境变量隔离测试环境、生产环境切换起来非常方便不用改一行代码。5. 真实调用RFC函数从查询物料到写入数据连接通了以后调用真实业务函数才是重头戏。pyrfc的call()方法设计得很直观函数模块名作为第一个参数后续关键字参数就是该函数模块的导入参数。返回值是一个字典对应函数模块的导出参数和表参数。先看一个查询物料的例子。SAP里查物料列表的经典BAPI是BAPI_MATERIAL_GETLIST它有几个关键导入参数MAXROWS控制最大返回行数MATERIAL_TYPE按物料类型过滤。代码很像这样from pyrfc import Connection conn Connection( ashost192.168.1.100, sysnr00, client800, userRFCUSER, passwdPssw0rd, langEN ) result conn.call( BAPI_MATERIAL_GETLIST, MAXROWS10, MATERIAL_TYPEFERT ) materials result.get(MATERIAL_LIST, []) for idx, mat in enumerate(materials, 1): material_code mat.get(MATERIAL) material_desc mat.get(MATL_DESC) print(f{idx}. {material_code} - {material_desc}) conn.close()注意MATERIAL_LIST是表参数所以返回的是列表里面每个元素是一个字典。pyrfc会把SAP的RFC结构自动映射成Python字典结构字段名和SAP里一致用get()方法取值更安全避免某些行缺少字段时报KeyError。再看写入类的操作。这类操作通常需要调用BAPI创建或修改数据然后显式提交或回滚事务。以创建物料主数据为例核心逻辑是调用BAPI_MATERIAL_SAVEDATA填充物料基础数据然后调用BAPI_TRANSACTION_COMMIT提交事务from pyrfc import Connection conn Connection( ashost192.168.1.100, sysnr00, client800, userRFCUSER, passwdPssw0rd, langEN ) header_data { MATERIAL: M001, INDUSTRY_SECTOR: M, MATL_TYPE: FERT, MATL_DESC: 测试物料A, BASE_UOM: PC, MATL_GROUP: 0101 } response conn.call( BAPI_MATERIAL_SAVEDATA, HEADDATAheader_data ) if RETURN in response: for msg in response[RETURN]: if msg.get(TYPE) E: # 出现错误回滚事务 conn.call(BAPI_TRANSACTION_ROLLBACK) raise Exception(f创建失败: {msg.get(MESSAGE)}) # 无错误提交事务 commit conn.call(BAPI_TRANSACTION_COMMIT, WAITX) print(提交成功) conn.close()这里有个关键点SAP的BAPI事务模型要求你在创建或修改数据后必须显式调用BAPI_TRANSACTION_COMMIT才会真正落库。忘记提交函数模块本身可能返回成功但业务数据其实没写进SAP这种问题排查起来非常隐蔽务必养成“改完必提交”的习惯。另外这里示例中的INDUSTRY_SECTOR、MATL_TYPE等都是SAP端必填字段具体有哪些必填项最优的办法是在SE37里查看BAPI的导入参数说明或者先调一次接口看返回的错误消息SAP的错误消息会非常明确地告诉你哪个字段缺失。还有一种情况需要注意有的RFC函数模块存在结构嵌套pyrfc里表示方式就是字典套字典。比如导入参数里有一个结构里面又包含一个明细表那么外层是字典内层表是列表套字典。理解这个映射关系后基本所有RFC函数模块都能用同一种模式调用。6. 报错排查链路从libsapnwrfc.so到授权失败的完整案例我之前在这套环境上踩过的报错类型不少这里直接整理成一个排查链路帮你少走弯路。RFC相关的错误信息虽然五花八门但归纳起来就几类按排查优先级来看。第一层导入阶段报错。如果运行import pyrfc直接报RFC_LIBRARY_NOT_FOUND问题一定出在动态库加载上。按这些顺序排查先确认SAPNWRFC_HOME是否指向正确目录再确认LD_LIBRARY_PATH里有没有包含$SAPNWRFC_HOME/lib还可以直接用find搜索libsapnwrfc.so确认文件存在。用一句话判断这个阶段报错跟SAP系统无关别去怀疑账号密码。第二层连接阶段报错。Connection()构造函数报RFC_CONNECTION_FAILURE时问题出在SAP系统侧的网络或服务可用性上。先用ping ashost确认服务器能通再用telnet ashost 3300测试RFC端口是否开放。SAP网关注册正常时3300端口应该是通的如果端口不通有可能是sysnr填错导致端口算错也可能是SAP系统的RFC服务没启动或者防火墙拦截了。第三层调用阶段报错。conn.call()时报权限相关错误比如RFC_NOT_AUTHORIZED问题出在SAP用户没有调用对应函数模块的权限。解决方法是让BASIS或SAP管理员在事务码SU01里给用户分配相应角色或者在PFCG里调整角色权限总之要确保用户对目标函数模块有执行权限。还有一种容易忽略的情况用户能调用普通的RFC_PING但调用BAPI时报权限错误就是因为SAP对RFC授权对象S_RFC控制得比较细可以单独限制每个函数模块的授权范围。把一个完整的排查案例写在这里供参考。我之前部署时遇到过一次诡异情况pyrfc安装成功SDK环境变量也对但连接SAP总是报RFC_CONNECTION_FAILURE。当时先ping通了服务器但telnet ashost 3300显示Connection refused。用SAP GUI却能正常登录同一个系统和客户端。后来才反应过来问题出在SAP应用服务器的配置文件里网关进程的回访地址指向了一个内部域名Linux服务器解析不了。最后在/etc/hosts里加了一条固定解析记录才解决。这提醒我们RFC连接虽然走TCP/IP但SAP网关在某些场景下会做回访DNS解析不正确一样会导致连接失败。下面这个表格对常见报错做了总结可以直接收藏备用报错所属阶段常见原因解决办法RFC_LIBRARY_NOT_FOUNDimportLD_LIBRARY_PATH未设置或错误检查环境变量确认lib路径RFC_CONNECTION_FAILUREConnection网络不通、端口不通、DNS解析失败ping、telnet、检查hostsRFC_INVALID_PARAMETERcall参数名、参数类型与SAP定义不符在SE37确认函数模块参数定义RFC_NOT_AUTHORIZEDcall用户没有函数模块的RFC授权在PFCG配置S_RFC授权对象RFC_SYS_EXCEPTIONcall业务逻辑异常或SAP端错误检查RETURN消息内容RFC_INVALID_TABLEcall表参数格式错误确认表参数是列表套字典排查时总原则是不要一跳就跳到“代码写错了”的结论。先验证SDK加载再验证网络链路最后验证权限和参数。每一层都有清晰的表现特征逐步缩小范围5分钟内就能定位多数问题。7. 工程化收尾编码、连接复用与调试技巧连接和调用跑通后接下来就是让它能稳定跑在生产环境里的工程化问题。有几个点值得重点说。第一是中文编码。SAP系统侧的中文字段比如物料描述返回给Python后如果打印出来是乱码通常是Python环境和SAP代码页之间的转换没对齐。在连接参数里把lang设置成ZH是最常见的做法同时保证Python解释器使用UTF-8编码。在Linux下可以在运行程序前设置环境变量export PYTHONIOENCODINGutf-8如果这样还乱码检查一下SAP系统实例的代码页配置常见的SAP非Unicode系统代码页是1100Unicode系统则是4103RFC调用时会自动做转换但前提是SDK能够识别出正确的代码页。多数情况下保持系统和Python都是UTF-8就没问题。第二是连接的复用与并发。不要在每个业务请求里都新建一个Connection()SAP侧建立RFC会话是有开销的频繁创建释放会对网关造成不必要的压力。简单的做法是使用单例连接在进程生命周期内复用。但要注意pyrfc的连接对象不是线程安全的同一个连接同时被多个线程调用会出错。如果程序是多线程架构推荐用连接池方案用queue.Queue维护一组连接线程取用时借出用完后归还。原理不复杂核心代码大致如下import queue from pyrfc import Connection class RFCPool: def __init__(self, conn_params, size5): self._pool queue.Queue(maxsizesize) for _ in range(size): self._pool.put(Connection(**conn_params)) def get_conn(self): return self._pool.get() def return_conn(self, conn): self._pool.put(conn) def close_all(self): while not self._pool.empty(): conn self._pool.get_nowait() conn.close()如果业务量不大也不用建池子单连接复用就够了。真实场景里大量物料同步这种任务通常用队列消费模型每个消费者线程持有自己的连接即可。第三是RFC调用日志与监控。pyrfc支持设置trace级别比如在连接参数中加trace: 3SDK会在当前目录生成RFC跟踪文件详细记录每一次调用的入参、出参和通信耗时。这个功能在联调阶段非常有价值因为SAP端的ST05事务码可以同时跟踪RFC调用两边的trace一对比问题定位效率直接翻倍。生产环境不建议开trace日志文件增长很快。最后分享一个小技巧在写任何RFC调用代码前先在SAP GUI里用事务码SE37找到对应的函数模块点“测试”按钮亲自执行一次。这样你能确认两点一是函数模块本身在SAP端能跑通二是你理解了它的参数结构。只要SAP端函数模块能正常返回pyrfc这边无非就是把参数翻译成Python字典而已。我踩过的所有“代码看着没问题但就是报错”的坑最后追溯下来都是因为没先去SE37里看一眼真实参数定义。养成这个习惯你在RFC开发上的效率会高出不止一个档位。本文还有配套的精品资源点击获取