{"id":21899005,"url":"https://github.com/ironsdu/gayrpc","last_synced_at":"2025-07-08T18:32:12.130Z","repository":{"id":30138903,"uuid":"124040602","full_name":"IronsDu/gayrpc","owner":"IronsDu","description":"Full Duplex C++ RPC Library,Use Protobuf, Support HTTP API .","archived":false,"fork":false,"pushed_at":"2023-03-15T10:11:34.000Z","size":533,"stargazers_count":11,"open_issues_count":2,"forks_count":7,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-06-19T10:46:55.644Z","etag":null,"topics":["cpp","protobuf","rpc","rpc-library"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/IronsDu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-03-06T07:45:12.000Z","updated_at":"2025-05-14T03:45:07.000Z","dependencies_parsed_at":"2024-11-28T14:38:16.175Z","dependency_job_id":"4b9c9443-dd09-489f-8ce3-d8bb0949ac45","html_url":"https://github.com/IronsDu/gayrpc","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/IronsDu/gayrpc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IronsDu%2Fgayrpc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IronsDu%2Fgayrpc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IronsDu%2Fgayrpc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IronsDu%2Fgayrpc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/IronsDu","download_url":"https://codeload.github.com/IronsDu/gayrpc/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IronsDu%2Fgayrpc/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264323983,"owners_count":23590780,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","protobuf","rpc","rpc-library"],"created_at":"2024-11-28T14:36:52.618Z","updated_at":"2025-07-08T18:32:12.103Z","avatar_url":"https://github.com/IronsDu.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# gayrpc\n跨平台全双工双向(异步)RPC系统,也即通信两端都可以同时作为RPC服务方和客户端.\n\n[![Platform](https://img.shields.io/badge/Platform-Linux,%20Windows,%20MacOS-green.svg?style=flat-square)](https://github.com/IronsDu/gayrpc)\n\n## Build Status\n[![hosted-ninja-vcpkg-autocache](https://github.com/IronsDu/gayrpc/actions/workflows/build_and_test.yml/badge.svg)](https://github.com/IronsDu/gayrpc/actions/workflows/build_and_test.yml)\n\n## 动机\n目前的RPC系统大多用于互联网行业后端系统，但他们之间更像一个单向图(不存在两个服务彼此依赖/互相调用)，但游戏等行业中则两节点之间可能相互调用。\n因此我们需要一个全双工RPC，在一个\"链接\"的两端均可开启服务和客户端，当然这里的\"链接\"是一个虚拟概念，它不一定基于TCP，也即\"链接\"的两端可以只存在逻辑链接而并没有网络直连。\n\n## 设计准则\n1. RPC支持拦截器，能够对Request或Response做一些处理(比如监控、认证、加解密、分布式跟踪)\n2. RPC核心不依赖网络和网络传输协议，即：我们可以开发任何网络应用和逻辑来开启RPC两端，将\"收到\"的消息丢给RPC核心，并通过某个出站拦截器来实现/决定把Request或Response以何种方式传递给谁。\n3. 此RPC是基于异步回调的，我认为这是目前C++里比较安全和靠谱的方式，虽然没有同步那么舒服……但gayrpc通过使用folly的Promise模式已经足够简便了\n4. RPC系统核心（以及接口）是线程安全的，可以在任意线程调用RPC；且可以在任意线程使用XXXReply::PTR对象返回Response。\n5. RPC是并行的，也即：客户端可以随意发送Request而不必等待之前的完成。 且允许先收到后发出的Request的Response。\n6. RPC系统会为每一个\"链接\"生成一个XXXService对象，这样可以让不同的\"链接\"绑定/持有各自的业务对象(有状态）（而不是像grpc等系统那样，一个服务只存在一个service对象，这类RPC调用类似短链接：收到请求返回数据即可）\n7. 支持HTTP API(同理2,此功能通过具体通信协议和拦截器进行支持,RPC核心本身与此无关).\n\n## 依赖\ngayrpc依赖以下库：\n\n* [protobuf](https://github.com/google/protobuf)\n* [brynet](https://github.com/IronsDu/brynet)\n* [folly](https://github.com/facebook/folly)\n\n注意,请务必根据你的构建系统中的protoc版本对gayrpc_meta.proto和gayrpc_option.proto预先生成代码，这需要你在 src目录里执行: \n```sh\n protoc --cpp_out=. ./gayrpc/core/gayrpc_meta.proto ./gayrpc/core/gayrpc_option.proto\n```\n\n## 测试体验\nWindows下可以安装[vcpkg](https://github.com/microsoft/vcpkg)，然后直接使用Visual Studio 2019/2022打开本代码仓库目录，并在VS 的CMake设置里勾选“从不使用CMake预设”（位置在\"选项\"-\"CMake\"-\"CMake配置文件\"），即不使用仓库目录中的CMakePresets文件！然后再进行生成CMake工程。\n\nLinux下则请按照[vcpkg](https://github.com/microsoft/vcpkg)文档进行构建。\n\n## 代码生成工具\ngayrpc使用protobuf定义服务，并需要使用代码生成工具根据protobuf服务文件生成对应的代码。生成工具的地址是：`https://github.com/IronsDu/protoc-gen-gayrpc`，它由[liuhan](https://github.com/liuhan907)编写完成。\u003c/br\u003e\n首先将插件程序放到系统 PATH路径下(比如Linux下的/usr/bin)，然后执行代码生成，比如（在具体的服务目录里，比如`gayrpc/examples/echo/pb`）:\n```sh\n protoc  -I. -I../../../src --cpp_out=. echo_service.proto\n protoc  -I. -I../../../src --gayrpc_out=. echo_service.proto\n```\n\n## Example\nhttps://github.com/IronsDu/gayrpc/tree/master/examples\n\n## Benchmark\nLatency(single threaded):\n```sh\nconnection num:1000\ncost 16491 ms for 3000000 requests\nthroughput(TPS):187500\nmean:5 ms, 5274983 ns\nmedian:5 ms, 5132642 ns\nmax:57 ms, 57525470 ns\nmin:0 ms, 17231 ns\np99:19 ms, 19198630 ns\n```\n\nThroughput(two threaded):\n```sh\nUbuntu 18.04 (i5 CPU)下，echo 300k QPS，当并发echo时 1000K QPS.\n```\n\n## 协议\n目前实现的RPC通信协议底层采用两层协议.(注意!RPC核心库并不依赖具体通信协议!)\n第一层采用二进制协议,且字节序统一为大端.\n通信格式如下:\n\n    [data_len | op | data]\n    字段解释:\n    data_len : uint64_t;\n    op       : uint32_t;\n    data     : char[data_len];\n\n当`op`值为1时表示RPC消息,此为第二层协议!这时第一层协议中的data的内存布局则为:\n    \n    [meta_size | data_size | meta | data]\n    字段解释:\n    meta_size  : uint32_t;\n    data_size  : uint64_t;\n    meta       : char[meta_size];\n    data       : char[data_size];\n\n其中`meta`为 `RpcMata`的binary.`data`为某业务上的Protobuf Request或Response类型对象的binary或JSON.\n\n`RpcMata`的proto定义如下:\n```protobuf\nsyntax = \"proto3\";\n\npackage gayrpc.core;\n\nmessage RpcMeta {\n    enum Type {\n        REQUEST = 0;\n        RESPONSE = 1;\n    };\n\n    enum DataEncodingType {\n        BINARY = 0;\n        JSON = 1;\n    };\n\n    message Request {\n        // 请求的服务函数\n        uint64  method = 1;\n        // 请求方是否期待服务方返回response\n        bool    expect_response = 2;\n        // 请求方的序号ID\n        uint64  sequence_id = 3;\n    };\n\n    message Response {\n        // 请求方的序号ID\n        uint64  sequence_id = 1;\n        // 执行是否成功\n        bool    failed = 2;\n        // (当failed为true)错误码\n        int32   error_code = 3;\n        // (当failed为true)错误原因\n        string  reason = 4;\n    };\n    \n    // Rpc类型(请求、回应)\n    Type    type = 1;\n    // RpcData的编码方式\n    DataEncodingType encoding = 2;\n    // 请求元信息\n    Request request_info = 3;\n    // 回应元信息\n    Response response_info = 4;\n}\n```\n\n## 服务描述文件范例\n以下面的服务定义为例:\n```protobuf\nsyntax = \"proto3\";\n\npackage dodo.test;\n\nmessage EchoRequest {\n    string message = 1;\n}\n\nmessage EchoResponse {\n    string message = 1;\n}\n\nservice EchoServer {\n    rpc Echo(EchoRequest) returns(EchoResponse){\n        option (gayrpc.core.message_id)= 1 ;//设定消息ID,也就是rpc协议中request_info的method\n    };\n}\n```\n\n## 处理请求或Response的实现原理\n1. 编写第一层通信协议的编解码\n2. 将第一层中的`data`作为第二层协议数据,反序列化其中的`meta`作为`RpcMeta`对象\n3. 判断`RpcMata`中的`type`\n    1. 如果为`REQUEST`则根据`request_info`中的元信息调用`method`所对应的服务函数.\n        此时第二层协议中的`data`则为服务函数的请求请求对象(比如`EchoRequest`).\n    2. 如果为`RESPONSE`则根据`response_info`中的元信息调用`sequence_id`对应的回调函数.\n        此时第二层协议中的`data`则为服务方返回的Response(比如`EchoResponse`)\n\n## 发送请求的实现原理\n以`client-\u003eecho(echoRequest, responseCallback)`为例\n参考代码:[GayRpcClient.h](https://github.com/IronsDu/gayrpc/blob/master/include/GayRpcClient.h#L34)\n\n1. 客户端分配 sequence_id,以它为key将 responseCallback保存起来.\n2. 将echoRequest序列化为binary作为第二层协议中的`data`\n3. 构造RpcMeta对象,将echo函数对应的id号作为request_info的method,并设置sequence_id.\n4. 将RpcMeta对象的binary作为第二层协议中的`meta`\n5. 用第二层协议的数据写入第一层协议进行发送给服务端.\n\n## 发送Response的实现原理\n以`replyObj-\u003ereply(echoResponse)`为例\n参考代码:[GayRpcReply.h](https://github.com/IronsDu/gayrpc/blob/master/include/GayRpcReply.h#L31)\n\n1. 首先replyObj里(拷贝)储存了来自于请求中的RpcMata对象.\n2. 将echoResponse序列化为binary作为第二层协议中的`data`\n3. 构造RpcMeta对象,将备份的RpcMeta对象中的sequence_id设置到前者中response_info的sequence_id.\n4. 将RpcMeta对象的binary作为第二层协议中的`meta`\n5. 用第二层协议的数据写入第一层协议进行发送给服务端.\n\n## 编解码参考\nhttps://github.com/IronsDu/gayrpc/tree/master/src/gayrpc/protocol\n\n## 注意点\n* RPC核心并不依赖通信采用的协议,而且网络传输可以是TCP、UDP、WebSocket等等，亦或消息队列等等。\n* RPC服务方的reply顺序与客户端的调用顺序无关,也就是可能后发起的请求先得到返回.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fironsdu%2Fgayrpc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fironsdu%2Fgayrpc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fironsdu%2Fgayrpc/lists"}