Thrift结构分析及增加取客户端IP功能实现
来源:互联网 发布:foxmail邮件导入到mac 编辑:程序博客网 时间:2024/05/29 11:18
1. 前言
分析Thrift的结构动机是为了实现服务端能取到客户端的IP,因此需要对它的结构、调用流程有些了解。另外,请注意本文针对的是TNonblockingServer,不包含TThreadPoolServer、TThreadedServer和TSimpleServer。
2. 示例Service
service EchoService
{
void hello();
}
class EchoHandler: public EchoServiceIf
{
private:
virtual void hello();
};
3. 网络部分类图
Thrift线程模型为若干IO线程TNonblockingIOThread(负责收发TCP连接的数据),以及主线程(负责监听TCP连接及接
受连接请求)组成。
主线程不一定就是进程的主线程,哪个线程调用了TServer::run()或TServer::serve()就是本文所说的主线程。就当前最新版本(0.9.2)的Thrift而言,调用TServer::run()或TServer::serve()均可以,原因是TServer::run()除无条件的调用外TServer::serve(),没有做任何其它事。对TServer::serve()的调用实际是对TServer的实现类TNonblockingServer的serve()的调用。
简而言之,TNonblockingIOThread负责数据的收发,而TNonblockingServer负责接受连接请求。
在使用中需要注意,调用TServer::run()或TServer::serve()的线程或进程会被阻塞,阻塞进入libevent的死循环,Linux上是死循环调用epoll_wait()。
4.1. 启动准备
准备的工作包括:
1) 启动监听连接
2) 启动收发数据线程
3) 初始化运行环境
在这里,可以看到第一次对TServerEventHandler的回调:
4.2. 接受连接
从接受连接的时序过程可以看出:在该连接TConnection接收数据之前,先调用了TServerEventHandler::createContext(),这个就是获取客户端IP的机会之一,但是当前的实现没有将相关的信息作为参数传递给TServerEventHandler::createContext()。
4.3. 收发数据:执行调用
这过程中对TServerEventHandler::processContext(connectionContext_, getTSocket())进行了回调,并传递了TSocket。
5. 取客户端IP
为取得客户端的IP,有三个办法:
1) 网上博文http://blog.csdn.net/hbuxiaoshe/article/details/38942869介绍的方法也是可行的,不过让人有些纠结;
2) 修改Thrift的实现,为TServerEventHandler::createContext()增加一个参数,将TSocket作为参数传递,这样就可以非常轻易的取得客户端的IP了。最简单的修改为:
class TServerEventHandler {
public:
virtual void* createContext(boost::shared_ptr<TProtocol> input,
boost::shared_ptr<TProtocol> output,
TTransport* transport); // 对于TNonblockingServer实际传递为TSocket
};
3) 不修改Thrift的实现。
在“收发数据:执行调用”的流程中,可以发现有对TServerEventHandler::processContext()的调用,而这里真好将TSocket作为第二个参数进行了传递,因此可以直接利用。
TServerEventHandler::createContext()和TServerEventHandler::processContext()的不同在于:前者只在建立连接时被调用一次,而后者每一个RPC调用时都会调用一次。
// 封装对thrift服务端的公共操作
// ThriftHandler就是Thrift应用实现的,如前述出现的EchoHandler
// ServiceProcessor是由Thrift编译器生成的,如前前述中的EchoServiceProcessor
// EventHanlder则是本文的主角
template <class EventHandler, class ThriftHandler, class ServiceProcessor>
class CThriftServerHelper
{
public:
// 启动rpc服务,请注意该调用是同步阻塞的,所以需放最后调用
bool serve(uint16_t port);
bool serve(uint16_t port, uint8_t num_threads);
bool serve(const std::string& ip, uint16_t port, uint8_t num_threads);
void stop();
private:
boost::shared_ptr<ThriftHandler> _handler;
boost::shared_ptr<thrift::TProcessor> _processor;
boost::shared_ptr<thrift::protocol::TProtocolFactory> _protocol_factory;
boost::shared_ptr<thrift::server::ThreadManager> _thread_manager;
boost::shared_ptr<thrift::concurrency::PosixThreadFactory> _thread_factory;
boost::shared_ptr<thrift::server::TServerEventHandler> _event_handler;
boost::shared_ptr<thrift::server::TServer> _server;
};
template <class EventHandler, class ThriftHandler, class ServiceProcessor>
bool CThriftServerHelper<ThriftHandler, ServiceProcessor>::serve(
const std::string& ip, uint16_t port, uint8_t num_threads)
{
try
{
_handler.reset(new ThriftHandler);
_processor.reset(new ServiceProcessor(_handler));
_protocol_factory.reset(new thrift::protocol::TBinaryProtocolFactory());
_thread_manager = thrift::server::ThreadManager::newSimpleThreadManager(num_threads);
_thread_factory.reset(new thrift::concurrency::PosixThreadFactory());
_thread_manager->threadFactory(_thread_factory);
_thread_manager->start();
_server.reset(new thrift::server::TNonblockingServer(
_processor, _protocol_factory, port, _thread_manager));
_event_handler.reset(new EventHandler());
_handler->setServerEventHandler(_event_handler); // 加这一句,使用就非常方便了
_server->setServerEventHandler(_event_handler);
_server->serve(); // 根据前面的分析,这里其实也可调用run(),而且调用run()更为合理,因为万一run()有变化,则不能调用serve()
}
catch (thrift::TException& ex)
{
LOG(ERROR) << "Start thrift failed: " << ex.what();
return false;
}
LOG(INFO) << "Start thrift successfully";
return true;
}
附:问题
如何让Thrift只在指定的IP上监听,而不是监听0.0.0.0?
- Thrift结构分析及增加取客户端IP功能实现
- Thrift结构分析及增加取客户端IP功能实现
- 一个电子商务网站的系统结构及功能实现分析
- C#取真实IP地址及分析
- C#取真实IP地址及分析
- C#取真实IP地址及分析
- java 取客户端ip
- 用新浪jS接口取客户端IP 及位置
- 用新浪jS接口取客户端IP 及位置
- 实现Thrift客户端连接池
- thrift通过TServerEventHandler获取客户端ip
- thrift服务端获取客户端ip地址。
- thrift server端获取客户端ip python
- [RK3288][Android6.0] AT24C02驱动分析及功能增加小结
- 取客户端IP地址代码
- 为ZooKeeper增加一个小功能:指定IP进行受限客户端过滤
- 为ZooKeeper增加一个小功能:指定IP进行受限客户端过滤
- Thrift交流(二)thrift服务端和客户端实现 Nifty
- Hash Table -- Leetcode problem349. Intersection of Two Arrays
- PHP实现阶乘的原理与代码分析
- 标准C语言 IO
- 判断Bigdecimal类型是否等于0的方法
- java集合Map
- Thrift结构分析及增加取客户端IP功能实现
- mac 下使用 iTerm 终端工具无法使用 alt+b 和 alt+f 快捷键的解决方法
- 那些我在Android开发中所喜爱的Kotlin特性
- 简单的算法题,包括1.打印100——200之间的的素数2.输出乘法口诀表3.判断1000年——2000年之间的闰年,给出完整代码
- MainActivity
- Oracle 基本操作
- Android开发中的小积累
- 高校机器人课程(ROS)教学的思、辨、行
- ueditor ie8兼容性问题