eProsima RPC over DDS User Manual翻译,第4章

本文介绍了eProsimaRPCoverDDS的网络传输实现,包括RTPS代理和服务器传输,以及异步调用和单向调用的功能。此外,还讨论了服务端的线程服务策略,如单线程、线程池和每个请求一个线程的模式。
摘要由CSDN通过智能技术生成

4. 高级概念

4.1 网络传输

eProsima RPC over DDS通过eProsima Fast-DDS库提供一种网络传输实现方法。注意,Prosima RPC over DDS也支持RTIDDS,此发行版仅时用于eProsima Fast-DDS。如要使用RTIDDS,请从eProsima网站下载RTIDDS-based发行版。

4.1.1 RTPS传输

利用eProsima Fast-DDS提供的独立的RTPS协议实现(与其竞争对手相反),此传输在RTPS级别的代理和位于同一本地网络中的服务之间创建连接,从而消除了DDS的开销。服务和代理都实现此类项目。

RTPSProxyTransport

RTPSProxyTransport类实现了代理使用的RTPS传输:

class RTPSProxyTransport: public ProxyTransport
{
   public:
      RTPSProxyTransport(std::string remoteServiceName, 
                        std::string instanceName, 
                        int domainId = 0, 
                        long timeout = 10000L);
      virtual ~RTPSProxyTransport();
};

此类有一个构造函数,该构造函数将传输设置为使用 RTPS -level发现机制。此发现机制允许代理在本地网络查找外部元素。有三种潜在的场景:

  • 在本地网络没有其他元素使用提供的服务名。这时,代理不会创建任何连接,直到另一个元素向网络宣布自己。如果客户端试图在这发生前调用远端程序,它会生成ServerNotFoundException异常.
  • 在本地网络中单独的服务使用服务名。当代理创建时,它将找到服务并与它创建一个连接通道。当客户应用程序使用代理去访问远端程序时,此服务将会执行此程序并返回应答。
  • 在本地网络中不止一个服务有相同的服务名。当用户希望拥有冗余服务器以避免系统故障时,可能会发生这种情况。当一个代理被创建时,它将查找所有的服务并与每个服务创建一个连接通道。当客户端应用程序使用代理访问远端程序时,所有的服务都会执行这个程序,但客户端将只收到一个服务端的一个应答。

使用示例中建议的IDL,开发者可以创建在本地网络中连接到特定服务端的代理。

BankProtocol *protocol = NULL;
RTPSProxyTransport *transport = NULL;
BankProxy *proxy = NULL;

try
{
   protocol = new BankProtocol();
   transport = new RTPSProxyTransport("BankService", "Instance");
   proxy = new BankProxy(*transport, *protocol);
}
catch(eprosima::rpc::exception::InitializeException &ex)
{
   std::cout << ex.what() << std::endl;
}

Account ac;
int32_t money;      
ReturnCode depositRetValue;    

try
{
   depositRetValue = proxy->deposit(ac, money);
}
catch(eprosima::rpc::exception::Exception &ex)
{
   std::cout << ex.what() << std::endl;
}

RTPSServerTransport

RTPSServerTransport类实现了一个被服务端使用的RTPS传输。

class RTPSServerTransport: public ServerTransport

{

   public:

      RTPSServerTransport(std:: string serviceName, std::string instanceName, int domainId = 0);

      virtual ~RTPSServerTransport();

};

此类有一个构造函数,该构造函数使用 RTPS 发现机制设置传输。此机制允许服务去发现本地网络中的任何代理。

使用示例中建议的IDL,开发者将使用这些代码创建一个服务:

unsigned int threadPoolSize = 5;

ThreadPoolStrategy *pool = NULL;
BankProtocol *protocol = NULL;
RTPSServerTransport *transport = NULL;

BankServer *server = NULL;
BankServerImplExample servant;

try

{

       pool = new ThreadPoolStrategy(threadPoolSize);

   transport = new RTPSServerTransport("BankService", "Instance");

   protocol = new BankProtocol();

   server = new BankServer(*pool, *transport, *protocol, servant);

   server->serve();

}

catch(eprosima::rpc::exception::InitializeException &ex)

{

   std::cout << ex.what() << std::endl;

}

4.2 Asynchronous异步调用

eProsima RPC over DDS 支持异步调用:客户端应用程序可以在等待回复时调用远端程序而不阻塞执行。

4.2.1 异步调用远端程序

rpcddsgen为每一个远端程序产生一个异步调用方法,使用命名策略<RemoteProcedureName>_async。这些方法有两个参数:请求到达时将调用的对象和远端程序的输入参数。使用IDL示例,rpcddsgen生成如下的异步代理方法:

void deposit_async(Bank_depositCallbackHandler &obj, /*in*/ const Account& ac, /*in*/ int32_t money);

异步版本的远端程序会抛出如下异常:

Exception

Description

eprosima::rpc::exception::ClientException

当客户端出现问题时会抛出此异常。

eprosima::rpc::exception::ServerNotFoundException

当代理找不到服务时会抛出此异常。

Example:

class Bank_depositHandler: public depositCallbackHandler

{

    void deposit(/*out*/ ReturnCode deposit_ret)

    {

        // Client desired behaviour when the reply arrives

    }

   

    virtual void on_exception(const eprosima::rpc::exception::Exception &ex)

    {

        // Client desired behaviour on exception

    }

}

void main()

{

   RTPSProxyTransport *transport = NULL;

   BankProtocol *protocol = NULL;

   BankProxy *proxy = NULL;

   try

   {

      transport = new RTPSProxyTransport("BankService", "Instance");

      protocol = new BankProtocol();

      proxy = new BankProxy(*transport, *protocol);

   }

   catch(eprosima::rpc::exception::InitializeException &ex)

   {

      std::cout << ex.what() << std::endl;

   }

  

   Account ac;

   int32_t money = 0;  

   Bank_depositHandler deposit_handler;

   try

   {

      proxy->deposit_async(deposit_handler, ac, money);

   }

   catch(eprosima::rpc::exception::Exception &ex)

   {

      std::cout << ex.what() << std::endl;

   }

}

4.2.2 应答回调对象

当服务端通过对象(开发者传递一个参数给异步调用的对象)进行回复时,客户端会收到通知。rpcddsgen为每个远端程序生成一个支持异步调用的抽象类。这些类的命名策略是<InterfaceName>_<RemoteProcedureName>CallbackHandler。

在这些类中会创建两个抽象方法:

  • 成功的应答到达时调用的回调,使用来自服务端的返回值作为输入参数
  • 异常和错误管理的回调。

用户必须创建一个继承<InterfaceName>_<RemoteProcedureName>CallbackHandler的类才能实现这两个方法。

使用IDL示例,rpcddsgen生成如下代码:

class Bank_depositCallbackHandler

{

public:

    virtual void deposit( /*out*/ ReturnCode deposit_ret) = 0;  

    virtual void error(const eprosima::rpc::exception::Exception &ex) = 0;

};

发生异常时调用的函数应该能够管理以下异常:

Error code

Description

eprosima::rpc::exception::ClientInternalException

客户端发生异常。

eprosima::rpc::exception::ServerTimeoutException

超过等待服务端应答的最大时间。

eprosima::rpc::exception::ServerInternalException

服务端发生异常。

4.3 单向调用

有时远端程序不需要服务端的应答。这时,eProsima RPC over DDS 支持单向调用。

开发者可以定义远端程序为单向调用,当客户端程序调用远端程序时,线程不会等待任何应答。

若要创建单向调用,必须在 IDL 文件中使用以下规则定义远端程序:

  • oneway保留字必须放在函数定义之前。
  • 函数的返回值必须是void类型。
  • 函数不能有inout或out参数。

下面示例显示了如何使用 IDL 定义单向程序:

interface Bank

{

    oneway void deposit(in Account ac, in long money);

};

4.4 线程服务策略

eProsima RPC over DDS 库为服务端提供若干个线程策略。

4.4.1 单线程策略

在此策略中,服务端仅使用一个线程进行请求管理。服务端一次仅执行一个请求。服务端用于处理请求的线程与接收线程相同。若要使用单线程策略,创建的服务的构造函数参数含有 SingleThreadStrategy对象。

SingleThreadStrategy *single = NULL;
BankProtocol *protocol = NULL;
TPCServerTransport *transport = NULL;

BankServer *server = NULL;
BankServerImplExample servant;

try

{

   single = new SingleThreadStrategy();

   transport = new TCPServerTransport("127.0.0.1:8080");

   protocol = new BankProtocol();

   server = new BankServer(*single, *transport, *protocol, servant);

   server->serve();

}

catch(eprosima::rpc::exception::InitializeException &ex)

{

   std::cout << ex.what() << std::endl;

}

4.4.2 线程池策略

在这种情况下,服务端管理用于处理传入请求的线程池。每次请求到达时,服务器都会将其分配给线程池中的空闲线程。

若要使用线程池策略,创建的服务的构造函数参数含有 ThreadPoolStrategy 对象。

unsigned int threadPoolSize = 5;

ThreadPoolStrategy *pool = NULL;
BankProtocol *protocol = NULL;
TCPServerTransport *transport = NULL;

BankServer *server = NULL;
BankServerImplExample servant;

try

{

   pool = new ThreadPoolStrategy(threadPoolSize);

   transport = new TCPServerTransport("127.0.0.1:8080");

   protocol = new BankProtocol();

   server = new BankServer(*pool, *transport, *protocol, servant);

   server->serve();

}

catch(eprosima::rpc::exception::InitializeException &ex)

{

   std::cout << ex.what() << std::endl;

}

4.4.3 每个请求一个线程策略

在这种情况下,服务端为每一个到来的请求创建一个新线程。这是资源最密集的备选方案。

若使用这种策略,创建的服务的构造函数参数含有ThreadPerRequestStrategy对象。

ThreadPerRequestStrategy *perRequest = NULL;
BankProtocol *protocol = NULL;
TCPerverTransport *transport = NULL;

BankServer *server = NULL;
BankServerImplExample servant;

try

{

   perRequest = new ThreadPerRequestStrategy();

   transport = new TCPServerTransport("127.0.0.1:8080");

   protocol = new BankProtocol();

   server = new BankServer(*perRequest, *transport, *protocol, servant);

   server->serve();

}

catch(eprosima::rpc::exception::InitializeException &ex)

{

   std::cout << ex.what() << std::endl;

}

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值