【问题标题】:any good and simple RPC library for inter-process calls? [closed]用于进程间调用的任何好的和简单的 RPC 库? [关闭]
【发布时间】:2011-07-20 21:34:00
【问题描述】:

我需要使用内置 C++ 类型的参数从客户端进程向服务器进程发送一个(可能是一个)简单的单向命令(因此序列化非常简单)。 C++、Windows XP+。

我正在寻找一个不需要复杂配置、提供简单界面、不需要数小时到数天的学习时间并且没有商业使用限制的库。简单问题的简单解决方案。

Boost.Interprocess 对于这个简单的任务来说太低级了,因为不提供 RPC 接口。套接字也可能是一种过度杀伤,因为我不需要在机器之间进行通信。 DCOM、CORBA 等人也是如此。命名管道?从来没有使用过它们,有什么好的 WinAPI 库吗? OpenMPI?

【问题讨论】:

  • Windows 内置了一些 RPC 支持。您可以使用命名管道以及其他东西作为传输。我不建议将其作为答案,因为“简单”确实不是。 htp//sn.cosftco/en-us/lirary/aa378651(v=VS.85).aspx

标签: c++ rpc interprocess


【解决方案1】:

我不认为套接字真的是矫枉过正。替代方案都有自己的问题,并且套接字比命名管道、共享内存等得到更好的支持,因为几乎每个人都在使用它们。本地系统上的套接字速度可能不是问题。

还有 Apache Thrift:

http://incubator.apache.org/thrift/

Google 的 protobuf 库周围有一些 RPC 实现作为封送机制:

https://github.com/google/protobuf/blob/master/docs/third_party.md#rpc-implementations

有 XML-RPC:

http://xmlrpc-c.sourceforge.net/

如果您的消息真的很简单,我可能会考虑使用 UDP 数据包,那么就没有要管理的连接了。

【讨论】:

  • 是的,如果我找不到更简单的东西,我很可能会为此使用 Boost.Asio(我已经将它用于 网络通信 在这个项目中)
  • 顺便说一句,如果发送到本地进程,是否100%保证UDP数据包不会丢失?
  • @Andy UDP 数据包没有传递保证,因此如果您需要 100% 确定您设计的协议,以便接收方回复并且发送方继续重新发送,直到收到回复。如果你打算这样做,你可能应该只使用 TCP。另一方面,如果 UDP 数据包在本地系统中丢失,我会感到非常惊讶,我认为这只发生在网络连接问题,或者如果您发送的数据包太快并且缓冲区已填满。
  • @Andy UDP 传输也有大小限制,您的消息必须适合单个数据包。如果您必须重新组装数据,那么您可能只想使用 TCP。
  • @Tim Sylvester UDP 数据包丢失即使在 LAN 上也不是很罕见。你的以太网交换机很容易丢包,你的网卡会丢包,你的操作系统会丢包。所需要的只是一些数据包(任何数据包,不仅仅是你的 UDP数据包)通过交换机/网卡/路由器的速度有点过快,有些会被丢弃
【解决方案2】:

您可能会喜欢 ZeroMQ 的类似内容。可能不像一个完整的 RPC,而是一个可以用来制作 RPC 的原始字节消息传递框架。它简单、轻巧且具有令人印象深刻的性能。您可以在其之上轻松实现 RPC。这是直接来自手册的示例服务器:

//
//  Hello World server in C++
//  Binds REP socket to tcp://*:5555
//  Expects "Hello" from client, replies with "World"
//
#include <zmq.hpp>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main () {
    //  Prepare our context and socket
    zmq::context_t context (1);
    zmq::socket_t socket (context, ZMQ_REP);
    socket.bind ("tcp://*:5555");

    while (true) {
        zmq::message_t request;

        //  Wait for next request from client
        socket.recv (&request);
        printf ("Received Hello");

        //  Do some 'work'
        sleep (1);

        //  Send reply back to client
        zmq::message_t reply (5);
        memcpy ((void *) reply.data (), "World", 5);
        socket.send (reply);
    }
    return 0;
}

此示例使用 tcp://*.5555,但如果您使用,则使用更高效的 IPC 技术:

socket.bind("ipc://route.to.ipc");

甚至更快的线程间协议:

socket.bind("inproc://path.for.client.to.connect");

【讨论】:

  • 似乎在从 C 到 C++ 的过程中卡住了一半
【解决方案3】:

如果你只需要支持 Windows 我会使用 Windows 内置的 RPC,我已经写了两篇关于这个的介绍性文章:

http://www.codeproject.com/KB/IP/rpcintro1.aspx
http://www.codeproject.com/KB/IP/rpcintro2.aspx

如果你只需要本地进程间通信,你可以使用ncalrpc协议。

【讨论】:

  • 干得好,你有没有想过在 MS RPC 上开发一个 C++ 库?
  • @Andy T:是的,我们使用内部 C++ 包装库在工作中使用 Windows RPC。但是 Windows RPC 的问题只是,它只是 Windows。我们目前正致力于从 Windows 扩展到其他平台,并寻找其他解决方案。
  • MSRPC 是从 DCE/RPC 派生的,同时它已经在 BSD 许可下发布。两者可以一起工作,见msdn.microsoft.com/en-us/library/aa230583%28v=vs.60%29.aspx
  • @dalle,你的搜索成功率如何?
  • 谢谢@dalle,我用你的文章实现了一个相当完整的64bit到32big dll代理,并且已经完美运行了2年。
【解决方案4】:

Boost.MPI。简单、快速、可扩展。

#include <boost/mpi/environment.hpp>
#include <boost/mpi/communicator.hpp>
#include <iostream>
#include <sstream>
namespace mpi = boost::mpi;

int main(int argc, char* argv[]) 
{
  mpi::environment env(argc, argv);
  mpi::communicator world;

  std::stringstream ss;
  ss << "Hello, I am process " << world.rank() << " of " << world.size() << ".";

  world.send(1, 0, ss.str());
}

【讨论】:

  • 似乎很容易。据我所知,Boost.MPI 只是 C 接口到 MPI 兼容库的包装器。 OpenMPI 似乎是最受欢迎的一种。是否易于设置和配置?另外这个例子看起来不像 RPC,Boost.MPI 是否有任何 RPC 支持来加速开发? IPC 配置有多难?
【解决方案5】:

如果您只在 Windows 上工作,并且确实需要 C++ 接口,请使用 COM/DCOM。它基于 RPC(又基于 DCE RPC)。

使用起来非常简单——只要您花时间学习基础知识。

【讨论】:

    【解决方案6】:

    您可能甚至不需要图书馆。 Windows 在其核心 API (windows.h) 中内置了一个 IPC 机制。您基本上可以将 Windows 消息发布到不同进程主窗口的消息队列中。 Windows 甚至为此定义了一个标准消息:WM_COPYDATA。


    发送过程基本上是这样的:

    接收过程(窗口):

    【讨论】:

      【解决方案7】:

      我知道我们离易于使用还很遥远。但当然你可以坚持使用 CORBA。例如。 ACE/TAO

      【讨论】:

        【解决方案8】:

        有人告诉我,带有Raknet 的 RPC 既好又简单。

        【讨论】:

        • 我过去用过它,但我不喜欢它。主要是因为我在使用 raknet 时遇到了稳定性问题。其他原因值得单独发布。我需要承认 - raknet 功能集和支持令人印象深刻
        【解决方案9】:

        另外,你可以看看msgpack-rpc

        更新

        我认为,虽然 Thrift/Protobuf 更灵活,但需要以特定格式编写一些代码。例如,Protobuf 需要一些 .proto 文件,可以使用包中的特定编译器进行编译,生成一些类。在某些情况下,代码的其他部分可能更难。 msgpack-rpc 要简单得多。它不需要编写一些额外的代码。这是一个例子:

        #include <iostream>
        
        #include <msgpack/rpc/server.h>
        #include <msgpack/rpc/client.h>
        
        class Server: public msgpack::rpc::dispatcher {
        public:
            typedef msgpack::rpc::request request_;
        
            Server() {};
        
            virtual ~Server() {};
        
            void dispatch(request_ req)
            try {
                std::string method;
                req.method().convert(&method);
        
                if (method == "id") {
                    id(req);
                } else if (method == "name") {
                    name(req);
                } else if (method == "err") {
                    msgpack::type::tuple<> params;
                    req.params().convert(&params);
                    err(req);
                } else {
                    req.error(msgpack::rpc::NO_METHOD_ERROR);
                }
            }
            catch (msgpack::type_error& e) {
                req.error(msgpack::rpc::ARGUMENT_ERROR);
                return;
            }
            catch (std::exception& e) {
                req.error(std::string(e.what()));
                return;
            }
        
            void id(request_ req) {
                req.result(1);
            }
        
            void name(request_ req) {
                req.result(std::string("name"));
            }
        
            void err(request_ req) {
                req.error(std::string("always fail"));
            }
        };
        
        int main() {
            // { run RPC server
            msgpack::rpc::server server;
            std::auto_ptr<msgpack::rpc::dispatcher> dispatcher(new Server);
            server.serve(dispatcher.get());
            server.listen("0.0.0.0", 18811);
            server.start(1);
            // }
        
            msgpack::rpc::client c("127.0.0.1", 18811);
            int64_t id = c.call("id").get<int64_t>();
            std::string name = c.call("name").get<std::string>();
        
            std::cout << "ID: " << id << std::endl;
            std::cout << "name: " << name << std::endl;
        
            return 0;
        }
        

        输出

        ID: 1
        name: name
        

        你可以在这里找到更复杂的例子https://github.com/msgpack/msgpack-rpc/tree/master/cpp/test

        【讨论】:

        • 虽然这在理论上可以回答问题,it would be preferable 在这里包含答案的基本部分,并提供链接以供参考。
        • 而且流媒体功能看起来很不错
        【解决方案10】:

        我正在使用 XmlRpc C++ for Windows found here

        真的很容易使用 :) 但是唯一的副作用就是只是一个客户端!

        【讨论】:

          【解决方案11】:

          还有Microsoft Messaging Queueing,当所有进程都在本地机器上时使用起来相当简单。

          【讨论】:

            【解决方案12】:

            进程间通信最简单的解决方案是使用文件系统。请求和响应可以写为临时文件。您可以为请求和响应文件制定命名约定。

            这不会给你最好的性能,但也许它会足够好。

            【讨论】:

            • 不确定这是否简单,尤其是您需要考虑崩溃的应用程序将临时文件留在磁盘上、文件被另一个应用程序(防病毒软件?)锁定以及其他同样烦人的事情
            • 多进程和写锁定可能是需要解决的问题。这可能会将您带到文件系统之上的抽象层。因此会产生更多的复杂性和依赖性。
            猜你喜欢
            • 1970-01-01
            • 2010-12-21
            • 2011-02-17
            • 2012-03-06
            • 2011-06-27
            • 1970-01-01
            • 2014-02-02
            • 2013-12-21
            • 2012-07-02
            相关资源
            最近更新 更多