使用thrift实现订阅服务和发布服务
功能:market_subscriber 能够向 market_publisher 请求订阅某些类型的消息,当 market_publisher 有该类型的消息时,需要把它推送给订阅服务。
流程:1. market_publisher 服务启动,监听端口,注册事件处理函数,处理订阅请求消息。
2. market_subscriber 服务启动,监听端口,注册事件处理函数,处理接收推动来的消息。
3. market_subscriber 向 market_publisher 发起订阅请求,market_publisher 根据订阅请求参数,长连接 market_subscriber 提供的消息接收端口。
4. market_publisher 通过长连接向 market_subscriber 推送消息。
注意:1. market_publisher 到 market_subscriber 的长连接的维护:
(1)market_subscriber 一定时间内未收到 market_publisher 的推送消息,尝试重新发起订阅请求。
(2)market_publisher 推送订阅消息时,发现连接断开,尝试重连。 考虑 market_publisher 有重启的情况,收到的订阅请求参数需要做持久化。 ==> TODO:增加一个 market_subscriber 到 market_publisher 的取消订阅的请求。
实现:
1. market_subscriber.thrift -- market_subscriber 实现的服务接口
namespace java market_subscriber
namespace perl market_subscriber
namespace php market_subscriber
struct Snapshot
{
1: i32 nSecurityID; ///< 证券ID
2: i32 nTime; ///< 序号/时间/日期 HHMMSSmmm
3: i32 nTradingPhaseCode; ///< 0:开市前 1:开盘集合竞价 2:连续竞价 3:临时停盘 4:收盘集合竞价 5:集中竞价闭市 6:协议转让结束 7:闭市
4: i32 nPreClosePx; ///< 昨收价 * 10000
5: i32 nOpenPx; ///< 开盘价 ..
6: i32 nHighPx; ///< 最高价 ..
7: i32 nLowPx; ///< 最低价 ..
8: i32 nLastPx; ///< 最新价 ..
9: i64 llTradeNum; ///< 成交笔数
10: i64 llVolume; ///< 成交量
11: i64 llValue; ///< 成交额(*10000)
}
service SubscriberService
{
// 推送消息
// Oneway means the client only makes request and does not listen for any response at all. Oneway methods must be void.
oneway void sendSnapshot(1:list<Snapshot> lstSnapshot);
}
2. market_publisher.thrift -- market_publisher 实现的服务接口
namespace java market_publisher
namespace perl market_publisher
namespace php market_publisher
struct SubscribeMarketParam
{
1: string user_name;
2: string password;
3: i32 type; // 订阅类型
4: string ip; // 接收推送数据的ip
5: i16 port; // 接收推送数据的port
}
struct SubscribeMarketAck
{
1: required i32 error_code; // 0,成功; 其它,失败
2: optional string error_info;
}
struct GetStockBaseInfoParam
{
1: required i32 stock_code;
}
struct GetStockBaseInfoAck
{
1: required i32 error_code;
2: optional string error_info;
3: optional string stock_name;
}
service PublisherService
{
// 订阅请求:订阅行情信息
SubscribeMarketAck subscribeMarket(1:SubscribeMarketParam param);
GetStockBaseInfoAck getStockBaseInfo(1:GetStockBaseInfoParam param);
}
3. subscriber_server.cpp
* Main.cpp
*/
#include "../gen-cpp/SubscriberService.h"
#include "../gen-cpp/PublisherService.h"
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <boost/thread/thread.hpp>
using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;
using boost::shared_ptr;
using namespace ::market_subscriber;
using namespace ::market_publisher;
class SubscriberServiceHandler : virtual public SubscriberServiceIf {
public:
SubscriberServiceHandler() {
// Your initialization goes here
}
void sendSnapshot(const std::vector<Snapshot> & lstSnapshot) {
// Your implementation goes here
printf("sendSnapshot\n");
std::cout << "Received snapshots' number: " << lstSnapshot.size() << std::endl;
for (std::vector<Snapshot>::const_iterator iter = lstSnapshot.begin();
iter != lstSnapshot.end(); iter++)
{
std::cout << "nSecurityID: " << iter->nSecurityID << "\t";
std::cout << "nTime: " << iter->nTime << "\t";
std::cout << std::endl;
}
sleep(10);
}
};
const char* CLIENT_LISTNE_IP = "127.0.0.1";
const short CLIENT_LISTNE_PORT = 9060;
void subscriberServiceThread()
{
shared_ptr<SubscriberServiceHandler> handler(new SubscriberServiceHandler());
shared_ptr<TProcessor> processor(new SubscriberServiceProcessor(handler));
shared_ptr<TServerTransport> serverTransport(new TServerSocket(CLIENT_LISTNE_PORT));
shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
TSimpleServer server(processor, serverTransport, transportFactory,
protocolFactory);
server.serve();
}
int main(int argc, char **argv)
{
boost::thread thrd(&subscriberServiceThread);
// wait for subscriberServiceThread ready
sleep(3);
boost::shared_ptr<TSocket> socket(new TSocket("127.0.0.1", 9090));
boost::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
PublisherServiceClient client(protocol);
try
{
transport->open();
SubscribeMarketAck ack;
SubscribeMarketParam param;
param.__set_user_name("mazhan");
param.__set_password("123456");
param.__set_type(0);
param.__set_ip(CLIENT_LISTNE_IP);
param.__set_port(CLIENT_LISTNE_PORT);
client.subscribeMarket(ack, param);
std::cout << "subscribeMarket(), error code: " << ack.error_code << std::endl;
transport->close();
}
catch (TException& tx)
{
std::cout << "ERROR: " << tx.what() << std::endl;
}
thrd.join();
return 0;
}
4. pubsher_server.cpp
* Main.cpp
*/
#include "../gen-cpp/SubscriberService.h"
#include "../gen-cpp/PublisherService.h"
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/concurrency/ThreadManager.h>
#include <boost/thread/thread.hpp>
using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;
using namespace ::apache::thrift::concurrency;
using boost::shared_ptr;
using namespace ::market_publisher;
using namespace ::market_subscriber;
std::list<boost::shared_ptr<SubscriberServiceClient> > g_lstSubscriberServiceClient;
boost::mutex g_mutexSubscriberServiceClient;
class PublisherServiceHandler : virtual public PublisherServiceIf {
public:
PublisherServiceHandler() {
// Your initialization goes here
}
void subscribeMarket(SubscribeMarketAck& _return, const SubscribeMarketParam& param) {
// Your implementation goes here
std::cout << "subscribeMarket, ip=" << param.ip << ", port=" << param.port << "." << std::endl;
boost::shared_ptr<TSocket> socket(new TSocket(param.ip, param.port));
boost::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
boost::shared_ptr<SubscriberServiceClient> client(new SubscriberServiceClient(protocol));
int error_code = 1; // fail to open
try
{
transport->open();
error_code = 0;
{ // add to subscribes list
boost::mutex::scoped_lock lock(g_mutexSubscriberServiceClient);
g_lstSubscriberServiceClient.push_back(client);
}
}
catch (TException& e)
{
std::cout << "Exception: " << e.what() << std::endl;
_return.__set_error_info(e.what());
}
catch (std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
_return.__set_error_info(e.what());
}
catch (
)
{
char buff[100];
snprintf(buff, 99, "fail to open %s:%d.", param.ip.c_str(), param.port);
std::cout << "Exception: " << buff << std::endl;
_return.__set_error_info(buff);
}
_return.__set_error_code(error_code);
}
void getStockBaseInfo(GetStockBaseInfoAck& _return, const GetStockBaseInfoParam& param) {
// Your implementation goes here
printf("getStockBaseInfo\n");
}
};
int32_t getCurTime()
{
time_t t = time(0);
char tmp[64];
strftime(tmp, sizeof(tmp), "%H%M%S", localtime(&t));
return atoi(tmp);
}
// send markets to subscribers.
void publisherServiceThread()
{
while (1)
{
std::vector<Snapshot> lstSnapshot;
Snapshot snapshot;
snapshot.nSecurityID = 100000001;
snapshot.nTime = getCurTime() * 1000 + rand() % 1000;
snapshot.nTradingPhaseCode = 2;
snapshot.nPreClosePx = 240500;
snapshot.nOpenPx = 250500;
snapshot.nHighPx = 250800;
snapshot.nLowPx = 240800;
snapshot.nLastPx = 250300;
snapshot.llTradeNum = 15000;
snapshot.llVolume = 6000000;
snapshot.llValue = 15030000000;
lstSnapshot.push_back(snapshot);
boost::mutex::scoped_lock lock(g_mutexSubscriberServiceClient);
std::list<boost::shared_ptr<SubscriberServiceClient> >::iterator iter = g_lstSubscriberServiceClient.begin();
while (iter != g_lstSubscriberServiceClient.end())
{
try
{
(*iter)->sendSnapshot(lstSnapshot);
iter++;
}
catch (TException& e)
{
std::cout << "Exception: " << e.what() << std::endl;
iter = g_lstSubscriberServiceClient.erase(iter);
}
catch (std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
iter = g_lstSubscriberServiceClient.erase(iter);
}
catch (
)
{
std::cout << "Exception: fail to call sendSnapshot()." << std::endl;
iter = g_lstSubscriberServiceClient.erase(iter);
}
}
sleep(3);
}
}
int main(int argc, char **argv)
{
int port = 9090;
shared_ptr<PublisherServiceHandler> handler(new PublisherServiceHandler());
shared_ptr<TProcessor> processor(new PublisherServiceProcessor(handler));
shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
shared_ptr<TTransportFactory> transportFactory(
new TBufferedTransportFactory());
shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
TSimpleServer server(processor, serverTransport, transportFactory,
protocolFactory);
boost::thread thrd(&publisherServiceThread);
printf("Starting the server
\n");
server.serve();
printf("done.\n");
return 0;
}
使用thrift实现订阅服务和发布服务的更多相关文章
- 使用dubbo分布式服务框架发布服务及消费服务
什么是DUBBO DUBBO是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案. 准备工作 安装zookeeper ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服 ...
- ServiceStack.Redis订阅发布服务的调用(Z)
1.Redis订阅发布介绍Redis订阅发布是一种消息通信模式:发布者(publisher)发送消息,订阅者(Subscriber)接受消息.类似于设计模式中的观察者模式.发布者和订阅者之间使用频 ...
- ServiceStack.Redis订阅发布服务的调用
1.Redis订阅发布介绍 Redis订阅发布是一种消息通信模式:发布者(publisher)发送消息,订阅者(Subscriber)接受消息.类似于设计模式中的观察者模式. 发布者和订阅者之间使用频 ...
- ASP.NET MVC 学习笔记-2.Razor语法 ASP.NET MVC 学习笔记-1.ASP.NET MVC 基础 反射的具体应用 策略模式的具体应用 责任链模式的具体应用 ServiceStack.Redis订阅发布服务的调用 C#读取XML文件的基类实现
ASP.NET MVC 学习笔记-2.Razor语法 1. 表达式 表达式必须跟在“@”符号之后, 2. 代码块 代码块必须位于“@{}”中,并且每行代码必须以“: ...
- 责任链模式的具体应用 ServiceStack.Redis订阅发布服务的调用
责任链模式的具体应用 1.业务场景 生产车间中使用的条码扫描,往往一把扫描枪需要扫描不同的条码来处理不同的业务逻辑,比如,扫描投入料工位条码.扫描投入料条码.扫描产出工装条码等,每种类型的条码位数 ...
- 通过Nginx、Consul、Upsync实现动态负载均衡和服务平滑发布
前提 前段时间顺利地把整个服务集群和中间件全部从UCloud迁移到阿里云,笔者担任了架构和半个运维的角色.这里详细记录一下通过Nginx.Consul.Upsync实现动态负载均衡和服务平滑发布的核心 ...
- Thrift 个人实战--RPC服务的发布订阅实现(基于Zookeeper服务)
前言: Thrift作为Facebook开源的RPC框架, 通过IDL中间语言, 并借助代码生成引擎生成各种主流语言的rpc框架服务端/客户端代码. 不过Thrift的实现, 简单使用离实际生产环境还 ...
- RPC服务的发布订阅实现Thrift
Thrift 个人实战--RPC服务的发布订阅实现(基于Zookeeper服务) 前言: Thrift作为Facebook开源的RPC框架, 通过IDL中间语言, 并借助代码生成引擎生成各种主流语言的 ...
- .net core编写转发服务(二) 添加服务发布订阅
源设计就单纯完成了把服务转发到特定的服务模块,一定程度上解耦了业务流程 但是我们实际开发过程中会面临服务转发后还有一些列关联的服务 举个例子 你调用了发送邮件的服务,接下来会面临扣费的服务,扣费之后会 ...
随机推荐
- docker仓库harbor搭建
1.安装docker-compose [root@docker02 ~]# yum install epel-release [root@docker02 ~]# pip install docker ...
- Redis AOF、RDB持久化
持久化一:RDB方式 默认配置: save 900 1save 300 10save 60 10000 持久化二:AOF方式 默认配置:appendonly no,appendfilename &qu ...
- HDU - 1272 小希的迷宫(并查集判断环)
https://cn.vjudge.net/problem/HDU-1272 Description 上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardo ...
- npm与yarn命令对比
Yarn是由Facebook.Google.Exponent 和 Tilde 联合推出了一个新的 JS 包管理工具 Yarn 是为了弥补 npm 的一些缺陷而出现的(比如,npm install时候会 ...
- 在 CentOS6 上安装 Zabbix2.4 Server
#!/bin/bash # # .配置无人值守的安装,定义安装过程中需要用到的一些信息 # mysql_root_pw=root_pw mysql_zabbix_pw=zabbix_pw DBPass ...
- spring拦截器中修改响应消息头
问题描述 前后端分离的项目,前端使用Vue,后端使用Spring MVC. 显然,需要解决浏览器跨域访问数据限制的问题,在此使用CROS协议解决. 由于该项目我在中期加入的,主要负责集成shiro框架 ...
- 32. Springboot 系列(八)动态Banner与图片转字符图案的手动实现
使用过 Springboot 的对上面这个图案肯定不会陌生,Springboot 启动的同时会打印上面的图案,并带有版本号.查看官方文档可以找到关于 banner 的描述 The banner tha ...
- ASP.NET MVC之视图传参到控制器的几种形式
1. 传递数组 $(function () { var value = ["C#", "JAVA", "PHP"]; $("inp ...
- 2016-2017-2 20155324实验二《Java面向对象程序设计》实验报告
2016-2017-2 20155324实验二<Java面向对象程序设计>实验报告 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉 ...
- Tensorflow Python 转 Java(一)
一.背景描述 最近python的tensorflow想办法给弄到线上去.网络用的Tensorflow现成的包.写篇博客,记录下过成.数据用kaggle中的数据为例子. 数据地址: https://ww ...