服务:订阅服务 market_subscriber 和 发布服务 market_publisher
功能: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 cpp 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 cpp 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实现订阅服务和发布服务的更多相关文章

  1. 使用dubbo分布式服务框架发布服务及消费服务

    什么是DUBBO DUBBO是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案. 准备工作 安装zookeeper ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服 ...

  2. ServiceStack.Redis订阅发布服务的调用(Z)

      1.Redis订阅发布介绍Redis订阅发布是一种消息通信模式:发布者(publisher)发送消息,订阅者(Subscriber)接受消息.类似于设计模式中的观察者模式.发布者和订阅者之间使用频 ...

  3. ServiceStack.Redis订阅发布服务的调用

    1.Redis订阅发布介绍 Redis订阅发布是一种消息通信模式:发布者(publisher)发送消息,订阅者(Subscriber)接受消息.类似于设计模式中的观察者模式. 发布者和订阅者之间使用频 ...

  4. ASP.NET MVC 学习笔记-2.Razor语法 ASP.NET MVC 学习笔记-1.ASP.NET MVC 基础 反射的具体应用 策略模式的具体应用 责任链模式的具体应用 ServiceStack.Redis订阅发布服务的调用 C#读取XML文件的基类实现

    ASP.NET MVC 学习笔记-2.Razor语法   1.         表达式 表达式必须跟在“@”符号之后, 2.         代码块 代码块必须位于“@{}”中,并且每行代码必须以“: ...

  5. 责任链模式的具体应用 ServiceStack.Redis订阅发布服务的调用

    责任链模式的具体应用   1.业务场景 生产车间中使用的条码扫描,往往一把扫描枪需要扫描不同的条码来处理不同的业务逻辑,比如,扫描投入料工位条码.扫描投入料条码.扫描产出工装条码等,每种类型的条码位数 ...

  6. 通过Nginx、Consul、Upsync实现动态负载均衡和服务平滑发布

    前提 前段时间顺利地把整个服务集群和中间件全部从UCloud迁移到阿里云,笔者担任了架构和半个运维的角色.这里详细记录一下通过Nginx.Consul.Upsync实现动态负载均衡和服务平滑发布的核心 ...

  7. Thrift 个人实战--RPC服务的发布订阅实现(基于Zookeeper服务)

    前言: Thrift作为Facebook开源的RPC框架, 通过IDL中间语言, 并借助代码生成引擎生成各种主流语言的rpc框架服务端/客户端代码. 不过Thrift的实现, 简单使用离实际生产环境还 ...

  8. RPC服务的发布订阅实现Thrift

    Thrift 个人实战--RPC服务的发布订阅实现(基于Zookeeper服务) 前言: Thrift作为Facebook开源的RPC框架, 通过IDL中间语言, 并借助代码生成引擎生成各种主流语言的 ...

  9. .net core编写转发服务(二) 添加服务发布订阅

    源设计就单纯完成了把服务转发到特定的服务模块,一定程度上解耦了业务流程 但是我们实际开发过程中会面临服务转发后还有一些列关联的服务 举个例子 你调用了发送邮件的服务,接下来会面临扣费的服务,扣费之后会 ...

随机推荐

  1. linux 配置本地光盘YUM源

    1.挂载光盘到 /media下 [root@localhost ~]# mount /dev/cdrom /media 2.直接配置文件了. [root@localhost ~]# cd /etc/y ...

  2. nginx之代理websocket

    nginx代理websocket:NGINX通过允许一个在客户端和后端服务器之间建立的隧道来支持WebSocket.为了NGINX发送来至于客户端Upgrade请求到后端服务器,Upgrade和Con ...

  3. 【SqlServer】SqlServer中的计算列

    计算列区别于需要我们手动或者程序给予赋值的列,它的值来源于该表中其它列的计算值.比如,一个表中包含有数量列Number与单价列Price,我们就可以创建计算列金额Amount来表示数量*单价的结果值, ...

  4. Docker笔记一:Docker介绍

    目录 什么是Docker? Docker的核心概念 Docker镜像命令 Docker容器命令 Docker实战 查看我的镜像 启动Redis Docker中国镜像加速 血与泪的教训 什么是Docke ...

  5. Oracle DataBase 编码格式

    sqlplus 查询 Oracle 数据库结果乱码或显示 ? 则需要设置字符集 一.客户端字符集 格式:NLS_LANG=language_territory.charset Language: 指定 ...

  6. C++回顾day02---<拷贝构造函数:重点>

    一:补充---无参构造函数(默认无参构造函数)在实例化对象时注意点 (一)若没有写构造函数,则类会含有一个默认无参构造函数 (二)若自定义一个构造函数,则类不会提供默认构造函数 class A { p ...

  7. C语言复习---矩形法求定积分函数

    一:分析: 大一学习积分的时候,我们学习过,可以通过矩形法来求定积分. 思路就是将积分区间划分成n等份,然后将这n等份近似看成矩形(或梯形),然后对所有的矩形(或梯形)的面积进行求和. 二:简单的例子 ...

  8. python dom操作

    1.DOM介绍 (1)什么是DOM DOM:文档对象模型.DOM 为文档提供了结构化表示,并定义了如何通过脚本来访问文档结构.目的其实就是为了能让js操作html元素而制定的一个规范. DOM就是由节 ...

  9. JS事件委托应用场景

    给列表元素添加点击事件: 在javaScript中,添加到页面上的事件处理程序的数量,将直接关系到页面的整体运行性能. <li>标签的数量很大时,循环为每个子元素添加事件,绝非好方法. 有 ...

  10. source命令导入大数据速度慢优化

    XX市邮政微商城的项目数据库,300多M,约220万条数据,source命令导入花了20个小时左右,太不可思议. 速度慢原因:220多万条数据,就 insert into 了220多万次,下图: 这是 ...