`

浅谈Thrift内部实现原理

阅读更多

Thrift由两部分组成:编译器(在compiler目录下,采用C++编写)和服务器(在lib目录下),其中编译器的作用是将用户定义的thrift文件编译生成对应语言的代码,而服务器是事先已经实现好的、可供用户直接使用的RPC Server(当然,用户也很容易编写自己的server)。同大部分编译器一样,Thrift编译器(采用C++语言编写)也分为词法分析、语法分析等步骤,Thrift使用了开源的flex和Bison进行词法语法分析(具体见thrift.ll和thrift.yy),经过语法分析后,Thrift根据对应语言的模板(在compiler\cpp\src\generate目录下)生成相应的代码。对于服务器实现而言,Thrift仅包含比较经典的服务器模型,比如单线程模型(TSimpleServer),线程池模型(TThreadPoolServer)、一个请求一个线程(TThreadedServer)和非阻塞模型(TNonblockingServer)等。本文将以C++为例进行一个实例分析。

 

假设用户编写了以下Thrift文件:

struct LogInfo {

1: required string name,

2: optional string content,

}

service LogSender {

void SendLog(1:list<LogInfo> loglist);

}

用户使用命令“thrift –gen cpp example.thrift”可生成C++代码,该代码包含以下文件:

example_constants.h

example_constants.cpp

example_types.h  //struct定义

example_types.cpp  //struct实现

LogSender.h  //service定义

LogSender.cpp  //service实现和LogSenderClient实现

LogSender_server.skeleton.cpp //一个实例RPC Server

用户可以这样编写Client:

shared_ptr socket(new TSocket(“8.8.8.8″, 9090));

shared_ptr transport(new TBufferedTransport(socket));

shared_ptr protocol(new TBinaryProtocol(transport));

LogSenderClient client(protocol);

try {

transport->open();

vector<LogInfo> logInfos;

LogInfo logInfo(“image”, “10:9:0 visit:xxxxxx”);

logInfos.push_back(logInfo);

…..

client.SendLog(logInfos);

transport->close();

} catch (TException &tx) {

printf(“ERROR: %s\n”, tx.what());

}

为了深入分析这段代码,我们看一下client.SendLog()函数的内部实现(在LogSender.cpp中):

void LogSenderClient::SendLog(const std::vector<LogInfo> & loglist)

{

send_SendLog(loglist);

recv_SendLog();

}

void LogSenderClient::send_SendLog(const std::vector<LogInfo> & loglist)

{

int32_t cseqid = 0;

oprot_->writeMessageBegin(“SendLog”, ::apache::thrift::protocol::T_CALL, cseqid);

LogSender_SendLog_pargs args;

args.loglist = &loglist;

args.write(oprot_);

oprot_->writeMessageEnd();

oprot_->getTransport()->flush();

oprot_->getTransport()->writeEnd();

}

void LogSenderClient::recv_SendLog()

{

int32_t rseqid = 0;

std::string fname;

::apache::thrift::protocol::TMessageType mtype;

iprot_->readMessageBegin(fname, mtype, rseqid);

if (mtype == ::apache::thrift::protocol::T_EXCEPTION) {

…..

}

if (mtype != ::apache::thrift::protocol::T_REPLY) {

……

}

if (fname.compare(“SendLog”) != 0) {

……

}

LogSender_SendLog_presult result;

result.read(iprot_);

iprot_->readMessageEnd();

iprot_->getTransport()->readEnd();

return;

}

阅读上面的代码,可以看出,RPC函数SendLog()实际上被转化成了两个函数:send_SendLog和recv_SendLog,分别用于发送数据和接收结果。数据是以消息的形式表示的,消息头部是RPC函数名,消息内容是RPC函数的参数。

我们再进一步分析RPC Server端,一个server的编写方法(在LogSender.cpp中)如下:

shared_ptr protocolFactory(new TBinaryProtocolFactory());

shared_ptr handler(new LogSenderHandler());

shared_ptr processor(new LogSenderProcessor(handler));

shared_ptr serverTransport(new TServerSocket(9090));

shared_ptr transportFactory(new TBufferedTransportFactory());

TSimpleServer server(processor,

serverTransport,

transportFactory,

protocolFactory);

printf(“Starting the server…\n”);

server.serve();

Server端最重要的类是LogSenderProcessor,它内部有一个映射关系processMap_,保存了所有RPC函数名到函数实现句柄的映射,对于LogSender而言,它只保存了一个RPC映射关系:

processMap_[" SendLog"] = &LogSenderProcessor::process_SendLog;

其中,process_SendLog是一个函数指针,它的实现如下:

void LogSenderProcessor::process_SendLog(int32_t seqid, ::apache::thrift::protocol::TProtocol* iprot, ::apache::thrift::protocol::TProtocol* oprot)

{

LogSender_SendLog_args args;

args.read(iprot);

iprot->readMessageEnd();

iprot->getTransport()->readEnd();

LogSender_SendLog_result result;

try {

iface_->SendLog(args.loglist);//调用用户编写的函数

} catch (const std::exception& e) {

……

}

oprot->writeMessageBegin(“SendLog”, ::apache::thrift::protocol::T_REPLY, seqid);

result.write(oprot);

oprot->writeMessageEnd();

oprot->getTransport()->flush();

oprot->getTransport()->writeEnd();

}

LogSenderProcessor中一个最重要的函数是process(),它是服务器的主体函数,服务器端(socket server)监听到客户端有请求到达后,会检查消息类型,并检查processMap_映射,找到对应的消息处理函数,并调用之(注意,这个地方可以采用各种并发模型,比如one-request-one-thread,thread pool等)。

通过上面的分析可以看出,Thrift最重要的组件是编译器(采用C++编写),它为用户生成了网络通信相关的代码,从而大大减少了用户的编码工作。

分享到:
评论

相关推荐

    thrift实现http协议案例

    首先,让我们了解一下Thrift的基本工作原理。Thrift基于接口描述语言(IDL),开发者可以在IDL文件中定义服务接口和数据类型。例如: ```thrift service MyService { string echo(1: string msg) } ``` 这个服务...

    qt 实现thrift的一个例子

    在这个例子中,我们将探讨如何使用Qt来实现一个基于Thrift的C++客户端和服务端的RPC(远程过程调用)连接。 首先,Thrift IDL文件(.thrift)是整个服务的核心,它定义了服务接口和数据结构。例如,我们可能会有一...

    Thrift中实现Java与Python的RPC互相调用示例代码.rar

    Thrift是一种跨语言的服务开发框架,由Facebook开源,主要用于构建可扩展且高效的分布式服务。它通过定义一种中间语言(IDL,...通过理解Thrift的工作原理和实践示例,你可以更好地应用于自己的分布式系统设计中。

    Java中使用Thrift实现RPC示例代码.rar

    首先,我们需要理解Thrift的工作原理。Thrift通过定义一种中间表示(IDL,Interface Description Language)来描述服务接口和数据结构。这个IDL文件类似于接口声明,定义了服务的方法和参数类型。然后,Thrift编译器...

    thrift环境配置方法

    配置好环境后,开发者可以使用 Thrift 实现高性能的服务之间的远程过程调用,提高系统的整体性能。 Thrift 环境配置步骤 ------------------------- ### 步骤 1:安装 MacPorts MacPorts 是一个用于 macOS 的包...

    Thrift-java学习小结

    本文将基于Thrift的Java实现,总结学习过程中的一些关键知识点,旨在帮助理解Thrift的工作原理以及如何在Java环境中应用。 一、Thrift简介 Thrift是一种远程过程调用(RPC)框架,它通过定义一种中间描述文件(....

    Thrift初探:简单实现C#通讯服务程序

    首先,我们需要了解Thrift的基本工作原理。Thrift通过定义一种中间描述文件(.thrift)来指定服务接口、数据结构和通信协议。这个文件被编译器解析,生成不同语言的客户端和服务端代码。对于C#,它会生成服务接口、...

    thrift通过openssl加密证书实现双向通信

    thrift框架通过vs2013编译好的静态库,然后通过vs2013实现双向通信代码,通信协议利用openssl加密证书的方式来实现,本资源给出了完整的实现代码,证书可以在网上百度一下,看看如何生成客户端和服务端的,然后编译...

    thrift包及其源码

    9. **源码分析**:通过查看源码,我们可以学习Thrift的内部实现,包括编译器生成代码的模板、各种协议的实现细节以及服务器和客户端的运行机制。 10. **应用场景**:Thrift广泛应用于分布式系统,如大数据处理、...

    thrift-Demo

    这个"thrift-Demo"应该是一个演示如何使用Thrift的实例,包含了一系列的步骤和文件,帮助初学者理解Thrift的工作原理和使用方法。 在Thrift中,我们首先需要创建一个`.thrift`文件,这个文件定义了服务的接口和数据...

    Java通过Thrift框架实现通讯的示例代码

    技术分享:Java通过Thrift框架实现通讯的示例代码

    Golang通过Thrift框架完美实现跨语言调用

    Golang通过Thrift框架完美实现跨语言调用

    thrift安装

    Thrift是一种开源的跨语言服务开发框架,由Facebook于2007年开源,现在由Apache软件基金会维护。它的主要功能是定义数据结构和服务...通过理解Thrift的工作原理和安装过程,你可以更好地利用它来解决实际的开发问题。

    Thrift RPC客户端的服务化框架代码

    在`mmxf.rpc`这个压缩包中,可能包含了Thrift服务的客户端和服务端实现代码,以及相关的配置文件。解压并分析这些文件,可以帮助我们更好地理解和使用这个服务化框架。在实际应用中,可能还需要考虑线程安全、错误...

    thrift介绍、各种server的比较、多接口服务实现

    thrift特性、不支持的特性、对各个语言的支持情况、语法参考、Thrift 架构、协议、传输层、服务端类型、各种thriftServer实现的比较、Thrift对多接口服务的支持

    thrift实现的实例程序

    在这个实例程序中,我们将深入探讨Thrift的工作原理,以及如何通过它来构建客户端和服务端的交互。 Thrift的核心是一个接口定义语言(IDL),它允许开发者定义服务接口和数据结构。这些定义会被编译成各种目标语言...

    thrift样例操作实例

    Thrift是一种开源的跨语言服务开发框架,由Facebook开发并贡献给Apache基金会。它通过定义一种中间语言(IDL,Interface ...通过实践这些样例,你可以深入理解Thrift的工作原理,并能够运用到自己的分布式系统中。

    基于thrift的RPC调用实例

    RPC(远程过程调用)是一种在分布式系统中执行远程计算的方法,使得客户端可以在不理解远程服务器内部实现的情况下,像调用本地函数一样调用远程服务器上的服务。在本实例中,我们将关注一个基于Thrift的RPC调用实现...

    thrift例子

    Thrift是一种开源的跨语言服务开发框架,由Facebook于2007年设计并开源,后来成为Apache软件基金会的顶级项目。...通过学习和实践这个例子,可以深入了解Thrift的工作原理和优势,为构建分布式系统提供强大的工具支持。

    thrift通讯的例子

    Thrift通过定义一种中间描述语言(IDL,Interface Description Language)来描述服务接口,允许开发者在不同的编程语言中方便地实现客户端和服务端,实现数据序列化和远程过程调用(RPC)。 首先,我们来看Thrift的...

Global site tag (gtag.js) - Google Analytics