
Apache Thrift netstd 跨语言实战在 .NET 环境下构建、运行并联动 Python 的 Calculator 教程【免费下载链接】thriftApache Thrift项目地址: https://gitcode.com/GitHub_Trending/thr/thrift本指南以仓库中的 tutorial/netstd/README.md 为核心系统讲解 Apache Thrift 在 .NETnetstd平台上的完整落地流程从环境准备、命令行构建到 Server/Client 可执行程序的多传输tcp/namedpipe/http/tcptls、多缓冲none/buffered/framed与多协议binary/compact/json组合运行再到与 Python 端进行真实的跨语言 RPC 联调。读完本文你将能够独立完成一个 netstd 示例工程的构建与调参并借助源码理解 Thrift 分层传输层、协议层、处理层在 .NET 端的实际装配方式。一、示例工程概述tutorial/netstd是 Apache Thrift 仓库中面向 .NET 的官方入门示例基于tutorial.thrift中定义的Calculator服务继承自shared.thrift的SharedService构建。整个示例由三个 C# 工程组成统一收录在 tutorial/netstd/Tutorial.slnx 解决方案中Interfaces承载由 Thrift IDL 生成的服务接口与数据契约代码tutorial、shared命名空间Server实现CalculatorAsyncHandler并启动异步 Thrift 服务端Client连接服务端并依次调用ping / add / calculate / getStruct / zip等方法验证通信。三个工程均通过ProjectReference直接引用核心库 lib/netstd/Thrift/Thrift.csproj服务端额外引用 lib/netstd/Thrift.AspNetCore/Thrift.AspNetCore.csproj用于 HTTP 宿主场景。接口契约则来源于 tutorial/tutorial.thrift 与 tutorial/shared.thrift。二、环境要求与前置准备按原文档要求构建与运行本示例需要满足.NET Core Standard 3.1LTS运行时或 SDKSDK 仅在需要编译程序时必须安装仅运行已编译产物时安装运行时即可支持 netstd 代码生成的thrift.exe编译器并将其所在目录加入PATH环境变量供生成代码阶段调用。需要说明的是原文档撰写时以 .NET Core 3.1 为基线从当前仓库源码看核心库 lib/netstd/Thrift/Thrift.csproj 已多目标编译netstandard2.1;netstandard2.0;net8.0;net9.0;net10.0示例工程 Client/Client.csproj 与 Server/Server.csproj 的目标框架为net10.0因此实际操作中建议安装较新的 .NET SDK以同时满足最低要求与当前仓库的实际构建需求。三、构建步骤按照原文档构建流程非常简洁下载并安装适用于你平台的 .NET Core SDK官方 .NET 下载页此处不展开外部链接确认拥有支持 netstd 的thrift.exe且已加入PATH进入tutorial/netstd目录运行 build.shLinux/macOS或 build.cmdWindows检查src/Tests下的测试仓库中对应的集成测试位于 test/netstd继续阅读 tutorial/netstd/README.md 完成后续运行步骤。两个构建脚本的内容完全一致仅做了两件事dotnet --info dotnet build其中dotnet build会自动拾取当前目录下的 Tutorial.slnx 解决方案。此外 tutorial/netstd/Makefile.am 也提供了 automake 接入方式$(DOTNETCORE) build -c Release说明该示例可被纳入 Apache Thrift 的整体构建体系。代码生成是如何触发的一个值得关注的源码细节是Interfaces工程在编译前会自动调用 thrift 编译器生成契约代码。在 tutorial/netstd/Interfaces/Interfaces.csproj 中定义了一个PreBuildTarget其命令本质为thrift -out 项目目录 -gen netstd:wcf,union,serial,net10 -r ./../../tutorial.thrift其中-gen netstd指定生成 .NETnetstd语言代码wcf,union,serial为附加的生成选项-r表示递归处理include的 IDL 文件此处会一并生成shared.thrift的代码脚本会依次尝试PATH中的thrift、仓库内 compiler/cpp/thrift 等位置找到可用的编译器即执行。也就是说只要满足“thrift 编译器可用”这一前置条件dotnet build会自动完成 IDL → C# 代码生成 → 编译的整条链路无需手工先跑一次thrift。四、运行示例编译完成后输出目录中会生成可执行文件Linux 下名为Client/ServerWindows 下名为Client.exe/Server.exe。运行方式为先启动服务端再从第二个控制台启动客户端。运行顺序与命令示例# 控制台 1启动服务端使用默认 tcp binary ./Server # 控制台 2启动客户端 ./Client若目标机器只安装了运行时而未安装 SDK直接运行上述可执行文件即可SDK 仅在编译时需要。五、NetCore Server 命令行详解服务端支持通过命令行参数自由组合传输、缓冲与协议。完整用法Server -help 将显示帮助信息 Server -tr:transport -pr:protocol 以指定参数运行服务端默认使用 tcp 传输与 binary 协议传输选项-tr取值说明tcp默认TCP 传输host 为localhost端口9090namedpipe命名管道传输管道地址为.testhttpHTTP 传输地址为localhost:9090tcptls基于 TLS 的 TCP 传输host 为localhost端口9090缓冲选项-bf取值说明none默认不启用传输工厂buffered启用缓冲传输工厂framed启用帧传输工厂客户端必须与此一致协议选项-pr取值说明binary默认二进制协议compact紧凑二进制协议jsonJSON 协议multiplexed多路复用协议源码层面的更新原文档将multiplexed列为-pr的可选值但当前 Server/Program.cs 中GetProtocol()仅解析binary/compact/json三者Server/Program.cs多路复用改由独立的-multiplex开关控制Server/Program.cs 中通过TMultiplexedProcessor注册Calculator处理器实现。这是仓库演进带来的差异以源码为准。命令行示例Server -tr:tcpTcpTls 模式注意事项启用tcptls时证书文件ThriftTest.pfx必须位于可执行文件所在目录命令行方式运行或位于工程目录从 IDE 调试运行。证书密码为ThriftTest。从源码看Server/Program.cs 的GetCertificate()使用X509CertificateLoader.LoadPkcs12FromFile(certFile, ThriftTest)加载证书且GetCertPath()会从当前目录向上最多回溯 6 级父目录递归查找ThriftTest.pfx——这正是“证书放在项目根附近即可被找到”的实现原因。服务端通过TTlsServerSocketTransport启用 TLSServer/Program.cs。六、NetCore Client 命令行详解客户端在服务端参数的基础上额外支持多客户端并发Client -help 将显示帮助信息 Client -tr:transport -pr:protocol -mc:numClients 以指定参数运行客户端默认 tcp 传输与 binary 协议1 个客户端传输选项-tr取值说明tcp默认TCP 传输host 为localhost端口9090namedpipe命名管道传输管道地址为.testhttpHTTP 传输地址为http://localhost:9090tcptls基于 TLS 的 TCP 传输host 为localhost端口9090缓冲选项-bf取值说明none默认不启用传输工厂buffered启用缓冲传输工厂framed启用帧传输工厂客户端必须与此一致协议选项-pr取值说明binary默认二进制协议compact紧凑二进制协议jsonJSON 协议multiplexed多路复用协议同服务端一致当前源码中多路复用通过-multiplex开关控制参见 Client/Program.cs。多客户端选项-mc取值说明numClients并发连接服务端的客户端数量最大 100默认 1客户端主流程会依据-mc创建对应数量的并发任务同时执行 RPC 调用Client/Program.cs可用于简单的并发压测。参数解析有严格的合法性校验GetNumberOfClients()仅接受0 numClients 100的值否则回退为 1Client/Program.cs。命令行示例Client -tr:tcp -pr:binary -mc:10上述命令将以 TCP 二进制协议启动 10 个并发客户端访问本地 9090 端口。TcpTls 模式注意事项与服务端相同ThriftTest.pfx需位于可执行文件目录命令行方式或工程目录IDE 调试证书密码为ThriftTest。客户端通过TTlsSocketTransport建立安全连接且CertValidator回调直接返回trueClient/Program.cs表明示例中未做严格的证书链校验仅用于演示 TLS 通道的搭建方式。七、传输、缓冲与协议的源码装配逻辑理解 Server/Client 的-tr/-bf/-pr参数如何落到 Thrift 分层架构上是掌握 netstd 用法的关键。以服务端 Server/Program.cs 为例装配过程分为四步端点传输Endpoint Transport根据-tr选择TServerSocketTransporttcp、TNamedPipeServerTransportnamedpipe管道名.test最大实例数 64、TTlsServerSocketTransporttcptls分层传输工厂Layered Transport Factory根据-bf可选地包上TBufferedTransport.Factory或TFramedTransport.Factory协议工厂Protocol Factory根据-pr选择TBinaryProtocol.Factory、TCompactProtocol.Factory或TJsonProtocol.Factory服务端装配将CalculatorAsyncHandlerCalculator.AsyncProcessor经TSingletonProcessorFactory包装与上述传输、协议一起交给TSimpleAsyncServer最后调用ServeAsync()启动。客户端 Client/Program.cs 的MakeTransport()对称地构造端点传输TSocketTransport/TNamedPipeTransport/THttpTransport/TTlsSocketTransport再按需叠加TBufferedTransport或TFramedTransportMakeProtocol()则直接new TBinaryProtocol(transport)等Client/Program.cs。若传入-multiplex客户端还会用TMultiplexedProtocol包装协议并指定服务名CalculatorClient/Program.cs与服务端的TMultiplexedProcessor一一对应。这些类分别位于核心库的 lib/netstd/Thrift/Transport/Client、lib/netstd/Thrift/Transport/Server、lib/netstd/Thrift/Transport/Layered、lib/netstd/Thrift/Protocol 与 lib/netstd/Thrift/Server/TSimpleAsyncServer.cs 中读者可以对照阅读。HTTP 模式的服务端实现当-tr:http时服务端走独立的HttpServerSample分支Server/Program.cs使用 ASP.NET Core Kestrel 监听http://localhost:9090通过THttpServerTransport中间件把 HTTP 请求转换为 Thrift 调用。中间件本体位于 lib/netstd/Thrift.AspNetCore/Transport/Server/THttpServerTransport.cs。需要注意示例代码目前不允许http与-multiplex同时使用Server/Program.cs虽然 Thrift 本身支持但示例未做演示。八、客户端调用序列与异步处理模型客户端对每个 RPC 的调用集中在ExecuteCalculatorClientOperations()Client/Program.cs完整复现了教程服务的典型调用场景OpenTransportAsync()打开传输通道ping()最简 void 方法add(1, 1)整数运算并返回结果calculate(1, work)构造Work { Op DIVIDE, Num1 1, Num2 0 }触发服务端抛出InvalidOperation异常客户端捕获并打印——验证跨进程异常传播改为SUBTRACT运算再次calculate验证15-105getStruct(1)读取服务端内存日志结构体zip()调用oneway单向方法服务端Task.Delay(100)模拟耗时后立即返回客户端不等响应。对应的服务端异步处理器CalculatorAsyncHandlerServer/Program.cs实现了Calculator.IAsync接口方法签名统一携带CancellationToken体现了 netstd 强制async/await模型的特性——在 lib/netstd/README.md 的迁移说明中明确指出netstd 不再支持同步模型async是必选项。这也是 lib/netstd/Thrift/Processor 目录下ITAsyncProcessor、TMultiplexedProcessor等异步处理器存在的根本原因。九、跨语言联调NetCore 与 Python原文档专门给出了 netstd 与 Python 互通的完整流程这是验证 Thrift 跨语言能力最直接的方式。操作步骤如下使用最新版thrift工具生成 Python 代码确保存在gen-py目录内含tutorial与shared等生成包将下方client.py与server.py保存到gen-py所在目录分别启动 netstd 示例Client/Server与 Python 示例client/server即可互通。注意事项示例中的客户端/服务端代码使用了与.thrift生成契约一致的方法operations与字段properties跨语言时务必保证 IDL 一致Windows 10 上若 Python 服务端以主机名testserver监听需要在C:\Windows\System32\drivers\etc\hosts文件中添加记录127.0.0.1 testserver否则名称解析会失败。Python Clientclient.pyimport sys import glob sys.path.append(gen-py) from tutorial import Calculator from tutorial.ttypes import InvalidOperation, Operation, Work from thrift import Thrift from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol def main(): # Make socket transport TSocket.TSocket(127.0.0.1, 9090) # Buffering is critical. Raw sockets are very slow transport TTransport.TBufferedTransport(transport) # Wrap in a protocol protocol TBinaryProtocol.TBinaryProtocol(transport) # Create a client to use the protocol encoder client Calculator.Client(protocol) # Connect! transport.open() client.Ping() print(ping()) sum client.Add(1, 1) print((11%d % (sum))) work Work() work.Op Operation.Divide work.Num1 1 work.Num2 0 try: quotient client.Calculate(1, work) print(Whoa? You know how to divide by zero?) print(FYI the answer is %d % quotient) except InvalidOperation as e: print((InvalidOperation: %r % e)) work.Op Operation.Substract work.Num1 15 work.Num2 10 diff client.Calculate(1, work) print((15-10%d % (diff))) log client.GetStruct(1) print((Check log: %s % (log.Value))) client.Zip() print(zip()) # Close! transport.close() if __name__ __main__: try: main() except Thrift.TException as tx: print(%s % tx.message)Python Serverserver.pyimport glob import sys sys.path.append(gen-py) from tutorial import Calculator from tutorial.ttypes import InvalidOperation, Operation from shared.ttypes import SharedStruct from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol from thrift.server import TServer class CalculatorHandler: def __init__(self): self.log {} def Ping(self): print(ping()) def Add(self, n1, n2): print(add(%d,%d) % (n1, n2)) return n1 n2 def Calculate(self, logid, work): print(calculate(%d, %r) % (logid, work)) if work.Op Operation.Add: val work.Num1 work.Num2 elif work.Op Operation.Substract: val work.Num1 - work.Num2 elif work.Op Operation.Multiply: val work.Num1 * work.Num2 elif work.Op Operation.Divide: if work.Num2 0: raise InvalidOperation(work.Op, Cannot divide by 0) val work.Num1 / work.Num2 else: raise InvalidOperation(work.Op, Invalid operation) log SharedStruct() log.Key logid log.Value %d % (val) self.log[logid] log return val def GetStruct(self, key): print(getStruct(%d) % (key)) return self.log[key] def Zip(self): print(zip()) if __name__ __main__: handler CalculatorHandler() processor Calculator.Processor(handler) transport TSocket.TServerSocket(hosttestserver, port9090) tfactory TTransport.TBufferedTransportFactory() pfactory TBinaryProtocol.TBinaryProtocolFactory() server TServer.TSimpleServer(processor, transport, tfactory, pfactory) print(Starting the server...) server.serve() print(done.) # You could do one of these for a multithreaded server # server TServer.TThreadedServer(processor, transport, tfactory, pfactory) # server TServer.TThreadPoolServer(processor, transport, tfactory, pfactory)注意两端在栈结构上的对应关系Python 客户端使用TSocket TBufferedTransport TBinaryProtocolnetstd 客户端默认的tcp传输恰好也是未启用分层缓冲的裸 socket——因此若 Python 端启用了缓冲而 netstd 端未启用反而会影响吞吐但协议层binary必须一致才能互通。这正是文档强调“framed 必须与客户端匹配”的深层原因传输栈任一端不匹配都会导致协议解析错位。十、已知问题与运行提示Trace 日志中的内部异常以 Trace 级别记录日志时可能看到一些无关紧要的内部异常如连接关闭时的预期异常属正常现象不影响功能仅运行时环境没有 SDK 的机器只需安装 .NET Core 运行时即可运行已编译的 Client/ServerSDK 仅用于编译阶段服务端日志服务端启动时会打印所选传输、缓冲、协议与 multiplex 配置Server/Program.cs可用作运行配置的即时核对。十一、延伸阅读netstd 命名体系与迁移要点若你希望进一步了解 netstd 库本身的组织方式lib/netstd/README.md 是官方补充文档其中要点包括核心库发布为两个 NuGet 包ApacheThrift协议、传输、处理器与TSimpleAsyncServer/TThreadPoolAsyncServer服务端仅依赖Microsoft.Extensions.Logging.Abstractions与ApacheThrift.AspNetCoreASP.NET Core HTTP 中间件THttpServerTransport仅做 HTTP 宿主时需要额外引用命名体系相较旧版 netcore/csharp 库有系统性调整T*ClientTransport更名为T*Transport、TBaseServer更名为TServer、SingletonTProcessorFactory更名为TSingletonProcessorFactory、AsyncBaseServer更名为TSimpleAsyncServer、TServerSocket更名为TServerSocketTransport、Serve()更名为ServeAsync()等代码生成命令统一为thrift -gen netstd旧的hashcode/nullable/async生成标志已不再需要。结合本教程的 tutorial/tutorial.thriftCalculator服务、Operation枚举、Work结构体、InvalidOperation异常与 tutorial/shared.thriftSharedStruct、SharedService两份 IDL即可完整串起“IDL 定义 → 代码生成 → 服务实现 → 多传输/多协议运行 → 跨语言联调”的 Thrift 全流程为后续在自己的 .NET 项目中集成 Thrift 提供可直接照搬的工程模板。【免费下载链接】thriftApache Thrift项目地址: https://gitcode.com/GitHub_Trending/thr/thrift创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考