RCF的簡單使用教程以及什麼是回調函數

RCF的使用教程

RCF(Remote Call Framework)是一個使用C++編寫的RPC框架,在底層RCF支持多種傳輸實現方式(transport implementations). 包括TCP,UDP,多播,組播,win32命名管道和unix domain socket。下面我以一個例子講述如何使用TCP完成一次RPC操做。php

須要注意的是,RCF官網上提供的是源碼包,因此在使用時咱們要麼本身將其編譯爲動態庫,要麼將整個源碼加入咱們的項目中。html

1. 定義接口

使用RCF框架,咱們沒必要像CORBA那樣,須要使用IDL去定義接口。直接使用RCF提供的宏就能夠定義。
如下代碼定義了一個名爲I_PrintService的接口,該接口包含了名爲Print的函數,函數返回值爲void,參數是const string &類型。java

值得注意的是RCF_METHOD_V1表示函數返回值爲空且只有一個形參,相似的,RCF_METHOD_V2表示函數返回值爲空且有兩個參數,最多支持15個參數。那麼若是咱們想要函數有返回值呢?好比一個返回值爲int,有一個參數的函數。這時可使用RCF_METHOD_R1宏來聲明該函數。嚴謹一點的表達以下所示,linux

RCF_METHOD_{V|R}{ }() ios

// Define the I_PrintService RCF interface.
RCF_BEGIN(I_PrintService, "I_PrintService")
    RCF_METHOD_V1(void, Print, const std::string &)
RCF_END(I_PrintService)

2. 服務端的編寫

該代碼的目的是在服務端實現一個Print函數,而後客戶端使用本身的參數調用服務端的Print函數。c++

  1. 建立一個初始化對象RcfInit init. RcfInit的默認構造函數會調用init(RcfConfigT *=nullptr)初始化RCF庫的引用計數值。
  2. 實例化一個RCF server,參數是具體的傳輸方式,TCP,UDP,命名管道等等。
  3. 將服務器綁定到聲明的接口
  4. 啓動服務器
#include <iostream>
#include <RCF/RCF.hpp>
// Define the I_PrintService RCF interface.
RCF_BEGIN(I_PrintService, "I_PrintService")
    RCF_METHOD_V1(void, Print, const std::string &)
RCF_END(I_PrintService)
// Server implementation of the I_PrintService RCF interface.
class PrintService
{
public:
    void Print(const std::string & s)
    {
        std::cout << "I_PrintService service: " << s << std::endl;
    }
};

int main()
{
    try
    {
        // Initialize RCF.
        1. RCF::RcfInit rcfInit;
        // Instantiate a RCF server.
        2. RCF::RcfServer server(RCF::TcpEndpoint("127.0.0.1", 50001));
        // Bind the I_PrintService interface.
        3. PrintService printService;
        server.bind<I_PrintService>(printService);
        // Start the server.
        4. server.start();
        std::cout << "Press Enter to exit..." << std::endl;
        std::cin.get();
    }
    catch ( const RCF::Exception & e )
    {
        std::cout << "Error: " << e.getErrorMessage() << std::endl;
    }
    return 0;
}

3. 客戶端的編寫

  1. 聲明接口
  2. 建立一個初始化對象RcfInit init.
  3. 實例化一個RCF客戶端
  4. 調用服務器的函數
RCF_BEGIN(I_PrintService, "I_PrintService")
    RCF_METHOD_V1(void, Print, const std::string &)
RCF_END(I_PrintService)
int main()
{
    try
    {
        // Initialize RCF.
        RCF::RcfInit rcfInit;
        std::cout << "Calling the I_PrintService Print() method." << std::endl;
        
        // Instantiate a RCF client.
        RcfClient<I_PrintService> client(RCF::TcpEndpoint("127.0.0.1", 50001));
        // Connect to the server and call the Print() method.
        client.Print("message from dennis");
    }
    catch ( const RCF::Exception & e )
    {
        std::cout << "Error: " << e.getErrorMessage() << std::endl;
    }
    return 0;
}

4. 編譯運行

編譯時注意添加頭文件的目錄和-luuid編程

g++ server.cpp ../src/RCF/RCF.cpp -lpthread -ldl -std=c++1y -luuid -I ../include/ -o server服務器

參考

http://www.deltavsoft.com/doc/_init_deinit_8hpp.html#a450dd848bd45776c9a277ded406522c1框架

回調函數(callback)

1. 什麼是回調函數

回調函數就是由調用方實現,可是由被調用函數(庫函數)調用的函數。常見於c標準庫和java,c++中的事件處理機制。回調函數可分爲兩種同步回調和異步回調。
dom


2. 同步回調

同步回調函數在調用方(caller)調用後當即執行
下面咱們以一個c實例講解什麼是同步回調,以及使用回調函數的好處。
能夠看到在server.c中,咱們定義的庫函數爲callbk,該函數接受三個參數,前兩個參數是函數指針fp的參數。
在頭文件server.h中咱們聲明瞭一個接口funcp,該接口是一個接受兩個int參數,返回值爲int的函數指針。
---

庫函數的實現

//   server.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "server.h"

int callbk(int a, int b, funcp fp)
{
    return fp(a, b);
}

//   server.h
#ifndef _SERVER_H
#define _SERVER_H
typedef int (*funcp)(int, int); 
int callbk(int, int, funcp);
#endif

咱們能夠將server.c製做成動態庫並將其放置到/usr/lib目錄中

> gcc -shared -fPIC server.c -o libserver.so

調用方的實現

調用方調用庫函數,並將本身實現的函數做爲參數傳遞給庫函數callbk。

#include "server.h"

int add_int(int a, int b)
{
    return (a+b);
}

int main()
{
    int sum = callbk(1, 2, add_int);
    printf("sum=%d\n", sum);
    return 0;
}


以上就是同步回調的實現。


3. 異步回調

異步回調在unix編程,窗口程序,以及須要事件處理機制的程序中被普遍使用。舉幾個例子,

1 pthread建立線程

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                  void *(*start_routine) (void *), void *arg);

2 unix註冊信號處理函數

如下代碼爲信號SIGUSR1註冊了一個用戶自定義的sig_usr函數

if ( signal(SIGUISR1, sig_usr)  == SIG_ERR) 
    perrror("sig err");

3 java swing

如下代碼用戶自定義了回調類MyListener

class MyListener implements ActionListener 
{
    ...
    public void actionPerformed(ActionEvent event) 
    {
            //some operation
    }
}

JButton yButton = new JButton();
yButton.addActionListener(new MyListener);

4. reference

https://www.ibm.com/developerworks/cn/linux/l-callback/
http://www.javashuo.com/article/p-zcdcjgyw-ck.html
http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=26000296&id=5782305
https://en.wikipedia.org/wiki/Callback_(computer_programming)
https://stackoverflow.com/questions/9596276/how-to-explain-callbacks-in-plain-english-how-are-they-different-from-calling-o/9652434#9652434

相關文章
相關標籤/搜索