├── .ycm_extra_conf.py ├── LICENSE ├── README.md ├── easyrpc ├── client │ ├── result.h │ ├── rpc_client.cpp │ ├── rpc_client.h │ ├── task.h │ ├── task_dispatcher.cpp │ └── task_dispatcher.h ├── codec │ ├── client_codec.cpp │ ├── client_codec.h │ ├── codec.cpp │ ├── codec.h │ ├── server_codec.cpp │ └── server_codec.h ├── easyrpc.h ├── net │ ├── io_service_pool.cpp │ ├── io_service_pool.h │ ├── tcp_client.cpp │ ├── tcp_client.h │ ├── tcp_server.cpp │ ├── tcp_server.h │ ├── tcp_session.cpp │ ├── tcp_session.h │ ├── tcp_session_cache.cpp │ └── tcp_session_cache.h ├── server │ ├── request.h │ ├── response.h │ ├── router.cpp │ ├── router.h │ ├── rpc_server.cpp │ └── rpc_server.h └── utility │ ├── logger.cpp │ ├── logger.h │ ├── protobuf_serialize.cpp │ ├── protobuf_serialize.h │ ├── shared_mutex.h │ ├── task_timer.h │ ├── thread_pool.cpp │ ├── thread_pool.h │ ├── threadsafe_list.h │ ├── utiltiy.cpp │ └── utiltiy.h └── test ├── protoc ├── build_proto.sh ├── code │ ├── common.pb.cc │ └── common.pb.h └── common.proto ├── rpc_client ├── CMakeLists.txt ├── main.cpp ├── rpc_client_test.cpp └── rpc_client_test.h └── rpc_server ├── CMakeLists.txt ├── main.cpp ├── rpc_server_test.cpp └── rpc_server_test.h /.ycm_extra_conf.py: -------------------------------------------------------------------------------- 1 | # This file is NOT licensed under the GPLv3, which is the license for the rest 2 | # of YouCompleteMe. 3 | # 4 | # Here's the license text for this file: 5 | # 6 | # This is free and unencumbered software released into the public domain. 7 | # 8 | # Anyone is free to copy, modify, publish, use, compile, sell, or 9 | # distribute this software, either in source code form or as a compiled 10 | # binary, for any purpose, commercial or non-commercial, and by any 11 | # means. 12 | # 13 | # In jurisdictions that recognize copyright laws, the author or authors 14 | # of this software dedicate any and all copyright interest in the 15 | # software to the public domain. We make this dedication for the benefit 16 | # of the public at large and to the detriment of our heirs and 17 | # successors. We intend this dedication to be an overt act of 18 | # relinquishment in perpetuity of all present and future rights to this 19 | # software under copyright law. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 25 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | # OTHER DEALINGS IN THE SOFTWARE. 28 | # 29 | # For more information, please refer to 30 | 31 | import os 32 | import ycm_core 33 | 34 | # These are the compilation flags that will be used in case there's no 35 | # compilation database set (by default, one is not set). 36 | # CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR. 37 | flags = [ 38 | '-Wall', 39 | '-Wextra', 40 | '-Werror', 41 | '-Wno-long-long', 42 | '-Wno-variadic-macros', 43 | '-fexceptions', 44 | '-DNDEBUG', 45 | # You 100% do NOT need -DUSE_CLANG_COMPLETER in your flags; only the YCM 46 | # source code needs it. 47 | '-DUSE_CLANG_COMPLETER', 48 | # THIS IS IMPORTANT! Without a "-std=" flag, clang won't know which 49 | # language to use when compiling headers. So it will guess. Badly. So C++ 50 | # headers will be compiled as C headers. You don't want that so ALWAYS specify 51 | # a "-std=". 52 | # For a C project, you would set this to something like 'c99' instead of 53 | # 'c++11'. 54 | '-std=c++14', 55 | # ...and the same thing goes for the magic -x option which specifies the 56 | # language that the files to be compiled are written in. This is mostly 57 | # relevant for c++ headers. 58 | # For a C project, you would set this to 'c' instead of 'c++'. 59 | '-x', 60 | 'c++', 61 | 62 | # c/c++ include path 63 | '-isystem', 64 | '/usr/include/c++/4.8', 65 | '-isystem', 66 | '/usr/include/c++/4.8.5', 67 | '-isystem', 68 | '/usr/include/c++/4.9.3', 69 | '-isystem', 70 | '/usr/include/c++/5', 71 | '-isystem', 72 | '/usr/include/c++/6', 73 | '-isystem', 74 | '/usr/include/c++/7', 75 | '-isystem', 76 | '/usr/include/c++/8', 77 | '-isystem', 78 | '/usr/include', 79 | '-isystem', 80 | '/usr/local/include', 81 | 82 | # 3rdparty 83 | '-isystem', 84 | '/usr/local/3rdparty/include', 85 | 86 | # project 87 | '-isystem', 88 | './', 89 | 90 | #'-isystem', 91 | #'../BoostParts', 92 | #'-isystem', 93 | # This path will only work on OS X, but extra paths that don't exist are not 94 | # harmful 95 | #'/System/Library/Frameworks/Python.framework/Headers', 96 | #'-isystem', 97 | #'../llvm/include', 98 | #'-isystem', 99 | #'../llvm/tools/clang/include', 100 | #'-I', 101 | #'.', 102 | #'-I', 103 | #'./ClangCompleter', 104 | #'-isystem', 105 | #'./tests/gmock/gtest', 106 | #'-isystem', 107 | #'./tests/gmock/gtest/include', 108 | #'-isystem', 109 | #'./tests/gmock', 110 | #'-isystem', 111 | #'./tests/gmock/include', 112 | ] 113 | 114 | 115 | # Set this to the absolute path to the folder (NOT the file!) containing the 116 | # compile_commands.json file to use that instead of 'flags'. See here for 117 | # more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html 118 | # 119 | # You can get CMake to generate this file for you by adding: 120 | # set( CMAKE_EXPORT_COMPILE_COMMANDS 1 ) 121 | # to your CMakeLists.txt file. 122 | # 123 | # Most projects will NOT need to set this to anything; you can just change the 124 | # 'flags' list of compilation flags. Notice that YCM itself uses that approach. 125 | compilation_database_folder = '' 126 | 127 | if os.path.exists( compilation_database_folder ): 128 | database = ycm_core.CompilationDatabase( compilation_database_folder ) 129 | else: 130 | database = None 131 | 132 | SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ] 133 | 134 | def DirectoryOfThisScript(): 135 | return os.path.dirname( os.path.abspath( __file__ ) ) 136 | 137 | 138 | def IsHeaderFile( filename ): 139 | extension = os.path.splitext( filename )[ 1 ] 140 | return extension in [ '.h', '.hxx', '.hpp', '.hh' ] 141 | 142 | 143 | def GetCompilationInfoForFile( filename ): 144 | # The compilation_commands.json file generated by CMake does not have entries 145 | # for header files. So we do our best by asking the db for flags for a 146 | # corresponding source file, if any. If one exists, the flags for that file 147 | # should be good enough. 148 | if IsHeaderFile( filename ): 149 | basename = os.path.splitext( filename )[ 0 ] 150 | for extension in SOURCE_EXTENSIONS: 151 | replacement_file = basename + extension 152 | if os.path.exists( replacement_file ): 153 | compilation_info = database.GetCompilationInfoForFile( 154 | replacement_file ) 155 | if compilation_info.compiler_flags_: 156 | return compilation_info 157 | return None 158 | return database.GetCompilationInfoForFile( filename ) 159 | 160 | 161 | def FlagsForFile( filename, **kwargs ): 162 | if not database: 163 | return { 164 | 'flags': flags, 165 | 'include_paths_relative_to_dir': DirectoryOfThisScript() 166 | } 167 | 168 | compilation_info = GetCompilationInfoForFile( filename ) 169 | if not compilation_info: 170 | return None 171 | 172 | # Bear in mind that compilation_info.compiler_flags_ does NOT return a 173 | # python list, but a "list-like" StringVec object. 174 | final_flags = list( compilation_info.compiler_flags_ ) 175 | 176 | # NOTE: This is just for YouCompleteMe; it's highly likely that your project 177 | # does NOT need to remove the stdlib flag. DO NOT USE THIS IN YOUR 178 | # ycm_extra_conf IF YOU'RE NOT 100% SURE YOU NEED IT. 179 | try: 180 | final_flags.remove( '-stdlib=libc++' ) 181 | except ValueError: 182 | pass 183 | 184 | return { 185 | 'flags': final_flags, 186 | 'include_paths_relative_to_dir': compilation_info.compiler_working_dir_ 187 | } 188 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 chxuan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | A modern RPC framework based on protobuf 2 | =============================================== 3 | 4 | > easyrpc是采用C++开发的,使用方便的RPC库。 5 | 6 | ![License][1] 7 | 8 | ## Tutorial 9 | 10 | * **Simple server** 11 | 12 | ```cpp 13 | #include "easyrpc/easyrpc.h" 14 | #include "common.pb.h" 15 | 16 | using namespace easyrpc; 17 | using namespace std::placeholders; 18 | 19 | void echo(const std::shared_ptr& req, const std::shared_ptr& res) 20 | { 21 | res->set_response(req->message); 22 | } 23 | 24 | int main() 25 | { 26 | // 1.创建rpc服务器对象 27 | // 服务端将采用1个io线程和2个work线程服务 28 | auto server = std::make_shared("0.0.0.0:8888", 1, 2); 29 | 30 | // 2.设置路由 31 | server->route(echo_message::descriptor()->full_name(), std::bind(echo, _1, _2)); 32 | 33 | // 3.启动事件循环(非阻塞) 34 | server->run(); 35 | 36 | std::cin.get(); 37 | return 0; 38 | } 39 | ``` 40 | 41 | * **Simple client** 42 | ```cpp 43 | #include "easyrpc/easyrpc.h" 44 | #include "common.pb.h" 45 | 46 | using namespace easyrpc; 47 | 48 | int main() 49 | { 50 | // 1.创建rpc客户端对象 51 | // 配置连接地址并设置请求超时为3秒 52 | auto client = std::make_shared("127.0.0.1:8888", 3); 53 | 54 | // 2.启动事件循环(非阻塞) 55 | client->run(); 56 | 57 | auto req = std::make_shared(); 58 | req->set_str("Hello world"); 59 | req->set_num(1024); 60 | 61 | // 3.异步调用echo函数 62 | client->call(message, [](const std::shared_ptr& ret) 63 | { 64 | log_info << ret->message->DebugString(); 65 | }); 66 | 67 | std::cin.get(); 68 | return 0; 69 | } 70 | ``` 71 | 72 | ## 开发平台 73 | 74 | * Ubuntu17.10 gcc7.2.0 75 | 76 | ## 依赖性 77 | 78 | * boost 79 | * protobuf 80 | * c++11 81 | 82 | ## DONE 83 | 84 | * TCP长连接。 85 | * rpc异步调用。 86 | * 日志记录。 87 | * worker线程池处理任务。 88 | * 客户端请求超时处理。 89 | * 支持主动推送模式。 90 | 91 | ## License 92 | This software is licensed under the [MIT license][2]. © 2017 chxuan 93 | 94 | 95 | [1]: http://img.shields.io/badge/license-MIT-blue.svg?style=flat-square 96 | [2]: https://github.com/chxuan/easyrpc/blob/master/LICENSE 97 | -------------------------------------------------------------------------------- /easyrpc/client/result.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file result.hpp 3 | * @brief 存放返回结果 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-11-05 7 | */ 8 | #pragma once 9 | 10 | #include "easyrpc/codec/codec.h" 11 | 12 | namespace easyrpc 13 | { 14 | 15 | struct result 16 | { 17 | result(int serial, message_model mod, const std::shared_ptr& msg) 18 | : serial_num(serial), model(mod), message(msg) {} 19 | int serial_num; 20 | message_model model; 21 | std::shared_ptr message; 22 | }; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /easyrpc/client/rpc_client.cpp: -------------------------------------------------------------------------------- 1 | #include "rpc_client.h" 2 | #include "easyrpc/utility/logger.h" 3 | #include "easyrpc/codec/client_codec.h" 4 | #include "task_dispatcher.h" 5 | 6 | namespace easyrpc 7 | { 8 | 9 | rpc_client::rpc_client(const std::string& address, int request_timeout) 10 | : tcp_client(address) 11 | { 12 | dispatcher_ = std::make_shared(request_timeout); 13 | codec_ = std::make_shared(std::bind(&task_dispatcher::dispatch, dispatcher_, std::placeholders::_1)); 14 | } 15 | 16 | rpc_client::~rpc_client() 17 | { 18 | stop(); 19 | } 20 | 21 | bool rpc_client::run() 22 | { 23 | if (tcp_client::run()) 24 | { 25 | dispatcher_->run(); 26 | return true; 27 | } 28 | 29 | return false; 30 | } 31 | 32 | void rpc_client::stop() 33 | { 34 | tcp_client::stop(); 35 | dispatcher_->stop(); 36 | } 37 | 38 | int rpc_client::call(const std::shared_ptr& message, const result_handler& handler) 39 | { 40 | if (message) 41 | { 42 | int serial_num = make_serial_num(); 43 | dispatcher_->add_result_handler(serial_num, handler); 44 | 45 | auto network_data = codec_->encode(serial_num, message_model::rpc, message); 46 | if (network_data) 47 | { 48 | async_write(network_data); 49 | return serial_num; 50 | } 51 | } 52 | 53 | return -1; 54 | } 55 | 56 | void rpc_client::bind(const sub_handler& handler) 57 | { 58 | dispatcher_->bind(handler); 59 | } 60 | 61 | int rpc_client::make_serial_num() 62 | { 63 | static std::atomic serial_num{ -1 }; 64 | if (++serial_num < 0) 65 | { 66 | serial_num = 0; 67 | } 68 | 69 | return serial_num; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /easyrpc/client/rpc_client.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file rpc_client.h 3 | * @brief 异步rpc客户端 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-11-06 7 | */ 8 | #pragma once 9 | 10 | #include "easyrpc/net/tcp_client.h" 11 | #include "result.h" 12 | #include "task.h" 13 | 14 | namespace easyrpc 15 | { 16 | 17 | class task_dispatcher; 18 | 19 | class rpc_client : public tcp_client 20 | { 21 | public: 22 | rpc_client(const std::string& address, int request_timeout = 10); 23 | virtual ~rpc_client(); 24 | 25 | virtual bool run(); 26 | virtual void stop(); 27 | int call(const std::shared_ptr& message, const result_handler& handler); 28 | void bind(const sub_handler& handler); 29 | 30 | private: 31 | int make_serial_num(); 32 | 33 | private: 34 | std::shared_ptr dispatcher_; 35 | }; 36 | 37 | } 38 | -------------------------------------------------------------------------------- /easyrpc/client/task.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file task.h 3 | * @brief rpc任务类 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-11-10 7 | */ 8 | #pragma once 9 | 10 | #include 11 | #include 12 | 13 | namespace easyrpc 14 | { 15 | 16 | class result; 17 | 18 | using result_handler = std::function&)>; 19 | using sub_handler = std::function&)>; 20 | 21 | struct task 22 | { 23 | result_handler handler; 24 | time_t begin_time; 25 | }; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /easyrpc/client/task_dispatcher.cpp: -------------------------------------------------------------------------------- 1 | #include "task_dispatcher.h" 2 | #include "result.h" 3 | #include "easyrpc/utility/logger.h" 4 | 5 | namespace easyrpc 6 | { 7 | 8 | task_dispatcher::task_dispatcher(int request_timeout) 9 | : request_timeout_(request_timeout) 10 | { 11 | 12 | } 13 | 14 | task_dispatcher::~task_dispatcher() 15 | { 16 | stop(); 17 | } 18 | 19 | void task_dispatcher::run() 20 | { 21 | threadpool_.init_thread_size(1); 22 | timer_.bind([this]{ check_request_timeout(); }); 23 | timer_.start(1); 24 | } 25 | 26 | void task_dispatcher::add_result_handler(int serial_num, const result_handler& handler) 27 | { 28 | lock_shared lock(mutex_); 29 | tasks_.emplace(serial_num, task{ handler, time(nullptr) }); 30 | } 31 | 32 | void task_dispatcher::bind(const sub_handler& handler) 33 | { 34 | sub_handler_ = handler; 35 | } 36 | 37 | void task_dispatcher::stop() 38 | { 39 | timer_.destroy(); 40 | threadpool_.stop(); 41 | clear(); 42 | } 43 | 44 | void task_dispatcher::clear() 45 | { 46 | lock_shared lock(mutex_); 47 | tasks_.clear(); 48 | } 49 | 50 | void task_dispatcher::dispatch(const std::shared_ptr& ret) 51 | { 52 | threadpool_.add_task(std::bind(&task_dispatcher::dispatch_thread, this, ret)); 53 | } 54 | 55 | void task_dispatcher::dispatch_thread(const std::shared_ptr& ret) 56 | { 57 | if (ret->model == message_model::rpc) 58 | { 59 | deal_rpc_result(ret); 60 | } 61 | else 62 | { 63 | deal_sub_result(ret); 64 | } 65 | } 66 | 67 | void task_dispatcher::deal_rpc_result(const std::shared_ptr& ret) 68 | { 69 | task t; 70 | if (get_task(ret->serial_num, t)) 71 | { 72 | remove_task(ret->serial_num); 73 | t.handler(ret); 74 | } 75 | else 76 | { 77 | log_warn << "Dispatch failed, serial num: " << ret->serial_num 78 | << ", message name: " << ret->message->GetDescriptor()->full_name(); 79 | } 80 | } 81 | 82 | void task_dispatcher::deal_sub_result(const std::shared_ptr& ret) 83 | { 84 | if (sub_handler_) 85 | { 86 | sub_handler_(ret); 87 | } 88 | } 89 | 90 | void task_dispatcher::check_request_timeout() 91 | { 92 | lock_shared lock(mutex_); 93 | time_t current_time = time(nullptr); 94 | auto begin = tasks_.begin(); 95 | auto end = tasks_.end(); 96 | 97 | while (begin != end) 98 | { 99 | if (current_time - begin->second.begin_time >= request_timeout_) 100 | { 101 | log_warn << "Request timeout, serial_num: " << begin->first; 102 | begin = tasks_.erase(begin); 103 | } 104 | else 105 | { 106 | ++begin; 107 | } 108 | } 109 | } 110 | 111 | bool task_dispatcher::get_task(int serial_num, task& t) 112 | { 113 | lock_shared lock(mutex_, true); 114 | auto iter = tasks_.find(serial_num); 115 | if (iter != tasks_.end()) 116 | { 117 | t = iter->second; 118 | return true; 119 | } 120 | 121 | return false; 122 | } 123 | 124 | void task_dispatcher::remove_task(int serial_num) 125 | { 126 | lock_shared lock(mutex_); 127 | tasks_.erase(serial_num); 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /easyrpc/client/task_dispatcher.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file task_dispatcher.h 3 | * @brief rpc任务调度器 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-11-07 7 | */ 8 | #pragma once 9 | 10 | #include 11 | #include "task.h" 12 | #include "easyrpc/utility/task_timer.h" 13 | #include "easyrpc/utility/thread_pool.h" 14 | #include "easyrpc/utility/shared_mutex.h" 15 | 16 | namespace easyrpc 17 | { 18 | 19 | class task_dispatcher 20 | { 21 | public: 22 | task_dispatcher(int request_timeout); 23 | ~task_dispatcher(); 24 | 25 | void run(); 26 | void add_result_handler(int serial_num, const result_handler& handler); 27 | void bind(const sub_handler& handler); 28 | void stop(); 29 | void clear(); 30 | void dispatch(const std::shared_ptr& ret); 31 | 32 | private: 33 | void dispatch_thread(const std::shared_ptr& ret); 34 | void deal_rpc_result(const std::shared_ptr& ret); 35 | void deal_sub_result(const std::shared_ptr& ret); 36 | void check_request_timeout(); 37 | bool get_task(int serial_num, task& t); 38 | void remove_task(int serial_num); 39 | 40 | private: 41 | time_t request_timeout_; 42 | std::unordered_map tasks_; 43 | shared_mutex mutex_; 44 | task_timer timer_; 45 | thread_pool threadpool_; 46 | sub_handler sub_handler_; 47 | }; 48 | 49 | } 50 | -------------------------------------------------------------------------------- /easyrpc/codec/client_codec.cpp: -------------------------------------------------------------------------------- 1 | #include "client_codec.h" 2 | #include "easyrpc/utility/protobuf_serialize.h" 3 | #include "easyrpc/client/result.h" 4 | 5 | namespace easyrpc 6 | { 7 | 8 | client_codec::client_codec(const result_handler& func) 9 | : func_(func) 10 | { 11 | 12 | } 13 | 14 | void client_codec::deal_decode_data(const packet_body& body, const std::shared_ptr& session) 15 | { 16 | 17 | (void)session; 18 | auto message = protobuf_serialize::unserialize(body.message_name, body.message_data); 19 | if (message) 20 | { 21 | auto ret = std::make_shared(body.serial_num, body.model, message); 22 | func_(ret); 23 | } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /easyrpc/codec/client_codec.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file client_codec.h 3 | * @brief 客户端编解码器 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-11-10 7 | */ 8 | #pragma once 9 | 10 | #include "codec.h" 11 | 12 | namespace easyrpc 13 | { 14 | 15 | class result; 16 | 17 | using result_handler = std::function&)>; 18 | 19 | class client_codec : public codec 20 | { 21 | public: 22 | client_codec(const result_handler& func); 23 | 24 | protected: 25 | virtual void deal_decode_data(const packet_body& body, const std::shared_ptr& session); 26 | 27 | private: 28 | result_handler func_; 29 | }; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /easyrpc/codec/codec.cpp: -------------------------------------------------------------------------------- 1 | #include "codec.h" 2 | #include "easyrpc/utility/protobuf_serialize.h" 3 | #include "easyrpc/utility/logger.h" 4 | 5 | namespace easyrpc 6 | { 7 | 8 | codec::codec() 9 | { 10 | reset(); 11 | } 12 | 13 | std::shared_ptr codec::encode(int serial_num, message_model model, 14 | const std::shared_ptr& message) 15 | { 16 | auto body = encode_body(serial_num, model, message); 17 | if (!body.message_data.empty()) 18 | { 19 | auto header = encode_header(body); 20 | return make_network_data(header, body); 21 | } 22 | 23 | return nullptr; 24 | } 25 | 26 | void codec::decode(const std::vector& buffer, const std::shared_ptr& session) 27 | { 28 | if (decode_header_) 29 | { 30 | decode_header(buffer); 31 | } 32 | else 33 | { 34 | decode_body(buffer, session); 35 | } 36 | } 37 | 38 | void codec::reset() 39 | { 40 | prepare_decode_header(); 41 | } 42 | 43 | int codec::get_next_recv_bytes() 44 | { 45 | return next_recv_bytes_; 46 | } 47 | 48 | packet_header codec::encode_header(const packet_body& body) 49 | { 50 | packet_header header; 51 | header.message_name_len = body.message_name.size(); 52 | header.message_data_len = body.message_data.size(); 53 | 54 | return header; 55 | } 56 | 57 | packet_body codec::encode_body(int serial_num, message_model model, 58 | const std::shared_ptr& message) 59 | { 60 | packet_body body; 61 | body.serial_num = serial_num; 62 | body.model = model; 63 | body.message_name = message->GetDescriptor()->full_name(); 64 | body.message_data = protobuf_serialize::serialize(message); 65 | 66 | return body; 67 | } 68 | 69 | std::shared_ptr codec::make_network_data(const packet_header& header, const packet_body& body) 70 | { 71 | auto network_data = std::make_shared(); 72 | 73 | copy_to_buffer(header, network_data); 74 | copy_to_buffer(body.serial_num, network_data); 75 | copy_to_buffer(body.model, network_data); 76 | copy_to_buffer(body.message_name, network_data); 77 | copy_to_buffer(body.message_data, network_data); 78 | 79 | return network_data; 80 | } 81 | 82 | void codec::decode_header(const std::vector& buffer) 83 | { 84 | copy_from_buffer(header_, buffer); 85 | if (is_vaild_header(header_.message_name_len, header_.message_data_len)) 86 | { 87 | prepare_decode_body(); 88 | } 89 | else 90 | { 91 | reset(); 92 | log_error << "invaild header, message_name_len: " << header_.message_name_len << 93 | ", message_data_len: " << header_.message_data_len; 94 | } 95 | } 96 | 97 | void codec::decode_body(const std::vector& buffer, const std::shared_ptr& session) 98 | { 99 | int pos = 0; 100 | 101 | copy_from_buffer(body_.serial_num, pos, buffer); 102 | copy_from_buffer(body_.model, pos, buffer); 103 | copy_from_buffer(body_.message_name, pos, header_.message_name_len, buffer); 104 | copy_from_buffer(body_.message_data, pos, header_.message_data_len, buffer); 105 | 106 | prepare_decode_header(); 107 | deal_decode_data(body_, session); 108 | } 109 | 110 | void codec::prepare_decode_header() 111 | { 112 | decode_header_ = true; 113 | next_recv_bytes_ = sizeof(packet_header); 114 | } 115 | 116 | void codec::prepare_decode_body() 117 | { 118 | decode_header_ = false; 119 | next_recv_bytes_ = sizeof(int) + sizeof(message_model) + header_.message_name_len + header_.message_data_len; 120 | } 121 | 122 | void codec::copy_from_buffer(std::string& str, int& pos, int len, const std::vector& buffer) 123 | { 124 | str.assign(&buffer[pos], len); 125 | pos += len; 126 | } 127 | 128 | void codec::copy_to_buffer(const std::string& str, std::shared_ptr& buffer) 129 | { 130 | buffer->append(str); 131 | } 132 | 133 | bool codec::is_vaild_header(int message_name_len, int message_data_len) 134 | { 135 | static const int max_message_name_len = 256; 136 | static const int max_message_data_len = 20 * 1024 * 1024; 137 | 138 | if (message_name_len >= 0 && message_name_len < max_message_name_len && 139 | message_data_len >= 0 && message_data_len < max_message_data_len) 140 | { 141 | return true; 142 | } 143 | 144 | return false; 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /easyrpc/codec/codec.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file codec.h 3 | * @brief 编解码器基类 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-11-10 7 | */ 8 | #pragma once 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace easyrpc 16 | { 17 | 18 | class tcp_session; 19 | 20 | struct packet_header 21 | { 22 | int message_name_len; 23 | int message_data_len; 24 | }; 25 | 26 | enum class message_model : unsigned char 27 | { 28 | rpc, 29 | pub_sub 30 | }; 31 | 32 | struct packet_body 33 | { 34 | int serial_num; 35 | message_model model; 36 | std::string message_name; 37 | std::string message_data; 38 | }; 39 | 40 | class codec 41 | { 42 | public: 43 | codec(); 44 | virtual ~codec() = default; 45 | 46 | std::shared_ptr encode(int serial_num, message_model model, 47 | const std::shared_ptr& message); 48 | void decode(const std::vector& buffer, const std::shared_ptr& session); 49 | void reset(); 50 | int get_next_recv_bytes(); 51 | 52 | protected: 53 | virtual void deal_decode_data(const packet_body& body, const std::shared_ptr& session) = 0; 54 | 55 | private: 56 | packet_header encode_header(const packet_body& body); 57 | packet_body encode_body(int serial_num, message_model model, 58 | const std::shared_ptr& message); 59 | std::shared_ptr make_network_data(const packet_header& header, const packet_body& body); 60 | 61 | void decode_header(const std::vector& buffer); 62 | void decode_body(const std::vector& buffer, const std::shared_ptr& session); 63 | 64 | void prepare_decode_header(); 65 | void prepare_decode_body(); 66 | 67 | template 68 | void copy_from_buffer(T& t, int& pos, const std::vector& buffer); 69 | template 70 | void copy_from_buffer(T& t, const std::vector& buffer); 71 | void copy_from_buffer(std::string& str, int& pos, int len, const std::vector& buffer); 72 | 73 | template 74 | void copy_to_buffer(T& t, std::shared_ptr& buffer); 75 | void copy_to_buffer(const std::string& str, std::shared_ptr& buffer); 76 | 77 | bool is_vaild_header(int message_name_len, int message_data_len); 78 | 79 | private: 80 | int next_recv_bytes_ = 0; 81 | bool decode_header_ = true; 82 | packet_header header_; 83 | packet_body body_; 84 | }; 85 | 86 | template 87 | void codec::copy_from_buffer(T& t, int& pos, const std::vector& buffer) 88 | { 89 | memcpy(&t, &buffer[pos], sizeof(t)); 90 | pos += sizeof(t); 91 | } 92 | 93 | template 94 | void codec::copy_from_buffer(T& t, const std::vector& buffer) 95 | { 96 | memcpy(&t, &buffer[0], sizeof(t)); 97 | } 98 | 99 | template 100 | void codec::copy_to_buffer(T& t, std::shared_ptr& buffer) 101 | { 102 | buffer->append(reinterpret_cast(&t), sizeof(t)); 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /easyrpc/codec/server_codec.cpp: -------------------------------------------------------------------------------- 1 | #include "server_codec.h" 2 | #include "easyrpc/utility/protobuf_serialize.h" 3 | #include "easyrpc/net/tcp_session.h" 4 | #include "easyrpc/server/request.h" 5 | #include "easyrpc/server/response.h" 6 | 7 | namespace easyrpc 8 | { 9 | 10 | server_codec::server_codec(const request_handler& func) 11 | : func_(func) 12 | { 13 | 14 | } 15 | 16 | void server_codec::deal_decode_data(const packet_body& body, const std::shared_ptr& session) 17 | { 18 | auto message = protobuf_serialize::unserialize(body.message_name, body.message_data); 19 | if (message) 20 | { 21 | auto req = std::make_shared(message, session->get_session_id()); 22 | auto res = std::make_shared(session, body.serial_num); 23 | func_(req, res); 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /easyrpc/codec/server_codec.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file server_codec.h 3 | * @brief 服务端编解码器 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-11-10 7 | */ 8 | #pragma once 9 | 10 | #include "codec.h" 11 | 12 | namespace easyrpc 13 | { 14 | 15 | class request; 16 | class response; 17 | 18 | using request_handler = std::function&, const std::shared_ptr&)>; 19 | 20 | class server_codec : public codec 21 | { 22 | public: 23 | server_codec(const request_handler& func); 24 | 25 | protected: 26 | virtual void deal_decode_data(const packet_body& body, const std::shared_ptr& session); 27 | 28 | private: 29 | request_handler func_; 30 | }; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /easyrpc/easyrpc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "easyrpc/utility/logger.h" 4 | #include "easyrpc/client/rpc_client.h" 5 | #include "easyrpc/server/request.h" 6 | #include "easyrpc/server/response.h" 7 | #include "easyrpc/server/rpc_server.h" 8 | -------------------------------------------------------------------------------- /easyrpc/net/io_service_pool.cpp: -------------------------------------------------------------------------------- 1 | #include "io_service_pool.h" 2 | 3 | namespace easyrpc 4 | { 5 | 6 | io_service_pool::io_service_pool(int size) 7 | { 8 | for (int i = 0; i < size; ++i) 9 | { 10 | auto ios = std::make_shared(); 11 | auto work = std::make_shared(*ios); 12 | ios_pool_.emplace_back(ios); 13 | work_pool_.emplace_back(work); 14 | } 15 | } 16 | 17 | io_service_pool::~io_service_pool() 18 | { 19 | stop(); 20 | } 21 | 22 | void io_service_pool::run() 23 | { 24 | for (std::size_t i = 0; i < ios_pool_.size(); ++i) 25 | { 26 | auto t = std::make_shared(boost::bind(&boost::asio::io_service::run, ios_pool_[i])); 27 | threads_.emplace_back(t); 28 | } 29 | } 30 | 31 | void io_service_pool::stop() 32 | { 33 | stop_io_services(); 34 | stop_threads(); 35 | } 36 | 37 | boost::asio::io_service& io_service_pool::get_io_service() 38 | { 39 | boost::asio::io_service& ios = *ios_pool_[next_io_service_]; 40 | ++next_io_service_; 41 | if (next_io_service_ == ios_pool_.size()) 42 | { 43 | next_io_service_ = 0; 44 | } 45 | 46 | return ios; 47 | } 48 | 49 | void io_service_pool::stop_io_services() 50 | { 51 | for (auto& ios : ios_pool_) 52 | { 53 | if (ios) 54 | { 55 | ios->stop(); 56 | } 57 | } 58 | } 59 | 60 | void io_service_pool::stop_threads() 61 | { 62 | for (auto& t : threads_) 63 | { 64 | if (t && t->joinable()) 65 | { 66 | t->join(); 67 | } 68 | } 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /easyrpc/net/io_service_pool.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file io_service_pool.h 3 | * @brief io service池 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-11-05 7 | */ 8 | #pragma once 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace easyrpc 17 | { 18 | 19 | class io_service_pool 20 | { 21 | public: 22 | io_service_pool(int size); 23 | ~io_service_pool(); 24 | 25 | void run(); 26 | void stop(); 27 | boost::asio::io_service& get_io_service(); 28 | 29 | private: 30 | void stop_io_services(); 31 | void stop_threads(); 32 | 33 | private: 34 | std::vector> ios_pool_; 35 | std::vector> work_pool_; 36 | std::vector> threads_; 37 | std::size_t next_io_service_ = 0; 38 | }; 39 | 40 | } 41 | -------------------------------------------------------------------------------- /easyrpc/net/tcp_client.cpp: -------------------------------------------------------------------------------- 1 | #include "tcp_client.h" 2 | #include "tcp_session.h" 3 | #include "io_service_pool.h" 4 | #include "easyrpc/utility/utiltiy.h" 5 | #include "easyrpc/utility/logger.h" 6 | #include "easyrpc/codec/codec.h" 7 | 8 | namespace easyrpc 9 | { 10 | 11 | tcp_client::tcp_client(const std::string& address) 12 | : address_(address), 13 | pool_(std::make_shared(1)) 14 | { 15 | 16 | } 17 | 18 | tcp_client::~tcp_client() 19 | { 20 | stop(); 21 | } 22 | 23 | void tcp_client::set_connection_notify(const std::function& func) 24 | { 25 | notify_func_ = func; 26 | } 27 | 28 | bool tcp_client::run() 29 | { 30 | pool_->run(); 31 | 32 | if (!parse_connect_address()) 33 | { 34 | return false; 35 | } 36 | 37 | session_ = std::make_shared(codec_, pool_->get_io_service(), 38 | std::bind(&tcp_client::deal_connection_closed, this, std::placeholders::_1)); 39 | if (connect(session_->get_socket())) 40 | { 41 | session_->run(); 42 | deal_connection_created(); 43 | return true; 44 | } 45 | 46 | return false; 47 | } 48 | 49 | void tcp_client::stop() 50 | { 51 | session_->close(); 52 | pool_->stop(); 53 | } 54 | 55 | void tcp_client::async_write(const std::shared_ptr& network_data) 56 | { 57 | session_->async_write(network_data); 58 | } 59 | 60 | bool tcp_client::parse_connect_address() 61 | { 62 | std::string ip; 63 | unsigned short port = 0; 64 | if (utiltiy::get_ip_and_port(address_, ip, port)) 65 | { 66 | boost::asio::ip::tcp::resolver resolver(pool_->get_io_service()); 67 | boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), ip, std::to_string(port)); 68 | endpoint_iter_ = resolver.resolve(query); 69 | return true; 70 | } 71 | 72 | log_warn << "Parse address failed, address: " << address_; 73 | return false; 74 | } 75 | 76 | bool tcp_client::connect(boost::asio::ip::tcp::socket& socket) 77 | { 78 | try 79 | { 80 | boost::asio::connect(socket, endpoint_iter_); 81 | } 82 | catch (std::exception& e) 83 | { 84 | log_warn << e.what() << ", address: " << address_; 85 | return false; 86 | } 87 | 88 | return true; 89 | } 90 | 91 | void tcp_client::reconnect() 92 | { 93 | std::this_thread::sleep_for(std::chrono::milliseconds(1000)); 94 | boost::asio::async_connect(session_->get_socket(), endpoint_iter_, 95 | [this](boost::system::error_code ec, boost::asio::ip::tcp::resolver::iterator) 96 | { 97 | if (!ec) 98 | { 99 | codec_->reset(); 100 | session_->run(); 101 | deal_connection_created(); 102 | } 103 | else if (ec != boost::asio::error::already_connected) 104 | { 105 | reconnect(); 106 | } 107 | }); 108 | } 109 | 110 | void tcp_client::deal_connection_created() 111 | { 112 | if (notify_func_) 113 | { 114 | notify_func_(true, session_->get_session_id()); 115 | } 116 | } 117 | 118 | void tcp_client::deal_connection_closed(const std::string& session_id) 119 | { 120 | if (notify_func_) 121 | { 122 | notify_func_(false, session_id); 123 | } 124 | 125 | reconnect(); 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /easyrpc/net/tcp_client.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file tcp_client.h 3 | * @brief tcp客户端基类 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-11-05 7 | */ 8 | #pragma once 9 | 10 | #include 11 | 12 | namespace easyrpc 13 | { 14 | 15 | class codec; 16 | class tcp_session; 17 | class io_service_pool; 18 | 19 | class tcp_client 20 | { 21 | public: 22 | tcp_client(const std::string& address); 23 | virtual ~tcp_client(); 24 | 25 | void set_connection_notify(const std::function& func); 26 | virtual bool run(); 27 | virtual void stop(); 28 | void async_write(const std::shared_ptr& network_data); 29 | 30 | 31 | private: 32 | bool parse_connect_address(); 33 | bool connect(boost::asio::ip::tcp::socket& socket); 34 | void reconnect(); 35 | void deal_connection_created(); 36 | void deal_connection_closed(const std::string& session_id); 37 | 38 | protected: 39 | std::shared_ptr codec_; 40 | 41 | private: 42 | std::string address_; 43 | std::shared_ptr pool_; 44 | std::shared_ptr session_; 45 | boost::asio::ip::tcp::resolver::iterator endpoint_iter_; 46 | std::function notify_func_; 47 | }; 48 | 49 | } 50 | -------------------------------------------------------------------------------- /easyrpc/net/tcp_server.cpp: -------------------------------------------------------------------------------- 1 | #include "tcp_server.h" 2 | #include "tcp_session.h" 3 | #include "io_service_pool.h" 4 | #include "tcp_session_cache.h" 5 | #include "easyrpc/codec/server_codec.h" 6 | #include "easyrpc/utility/logger.h" 7 | #include "easyrpc/utility/utiltiy.h" 8 | 9 | namespace easyrpc 10 | { 11 | 12 | tcp_server::tcp_server(const std::string& host, int ios_threads) 13 | : host_(host), 14 | pool_(std::make_shared(ios_threads)), 15 | acceptor_(pool_->get_io_service()) 16 | { 17 | 18 | } 19 | 20 | tcp_server::~tcp_server() 21 | { 22 | stop(); 23 | } 24 | 25 | void tcp_server::set_connection_notify(const notify_handler& func) 26 | { 27 | notify_func_ = func; 28 | } 29 | 30 | void tcp_server::publish(const std::string& session_id, const std::shared_ptr& message) 31 | { 32 | if (message) 33 | { 34 | auto session = session_cache_->get_session(session_id); 35 | if (session) 36 | { 37 | auto network_data = session->get_codec()->encode(make_serial_num(), message_model::pub_sub, message); 38 | if (network_data) 39 | { 40 | session->async_write(network_data); 41 | } 42 | } 43 | } 44 | } 45 | 46 | bool tcp_server::run() 47 | { 48 | session_cache_ = std::make_shared(); 49 | return start_listen(); 50 | } 51 | 52 | void tcp_server::stop() 53 | { 54 | pool_->stop(); 55 | 56 | if (session_cache_) 57 | { 58 | session_cache_->clear(); 59 | } 60 | } 61 | 62 | bool tcp_server::start_listen() 63 | { 64 | pool_->run(); 65 | 66 | std::string ip; 67 | unsigned short port = 0; 68 | if (!utiltiy::get_ip_and_port(host_, ip, port)) 69 | { 70 | log_error << "Parse address failed, host: " << host_; 71 | return false; 72 | } 73 | 74 | if (listen(ip, port)) 75 | { 76 | accept(); 77 | return true; 78 | } 79 | 80 | return false; 81 | } 82 | 83 | bool tcp_server::listen(const std::string& ip, unsigned short port) 84 | { 85 | try 86 | { 87 | boost::asio::ip::tcp::endpoint ep(boost::asio::ip::address_v4::from_string(ip), port); 88 | acceptor_.open(ep.protocol()); 89 | acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); 90 | acceptor_.bind(ep); 91 | acceptor_.listen(); 92 | } 93 | catch(std::exception& e) 94 | { 95 | log_error << e.what(); 96 | return false; 97 | } 98 | 99 | return true; 100 | } 101 | 102 | void tcp_server::accept() 103 | { 104 | std::shared_ptr codec = std::make_shared(std::bind(&tcp_server::deal_request, 105 | this, std::placeholders::_1, 106 | std::placeholders::_2)); 107 | auto session = std::make_shared(codec, pool_->get_io_service(), 108 | std::bind(&tcp_server::deal_connection_closed, this, std::placeholders::_1)); 109 | acceptor_.async_accept(session->get_socket(), [this, session](boost::system::error_code ec) 110 | { 111 | if (!ec) 112 | { 113 | session->run(); 114 | deal_connection_created(session); 115 | } 116 | accept(); 117 | }); 118 | } 119 | 120 | void tcp_server::deal_connection_created(const std::shared_ptr& session) 121 | { 122 | session_cache_->add_session(session->get_session_id(), session); 123 | ++connection_counts_; 124 | if (notify_func_) 125 | { 126 | notify_func_(connection_status{ true, session->get_session_id(), connection_counts_ }); 127 | } 128 | } 129 | 130 | void tcp_server::deal_connection_closed(const std::string& session_id) 131 | { 132 | session_cache_->remove_session(session_id); 133 | --connection_counts_; 134 | if (notify_func_) 135 | { 136 | notify_func_(connection_status{ false, session_id, connection_counts_ }); 137 | } 138 | } 139 | 140 | int tcp_server::make_serial_num() 141 | { 142 | static std::atomic serial_num{ -1 }; 143 | if (++serial_num < 0) 144 | { 145 | serial_num = 0; 146 | } 147 | 148 | return serial_num; 149 | } 150 | 151 | } 152 | -------------------------------------------------------------------------------- /easyrpc/net/tcp_server.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file tcp_server.h 3 | * @brief tcp服务端 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-11-16 7 | */ 8 | #pragma once 9 | 10 | #include 11 | #include 12 | 13 | namespace easyrpc 14 | { 15 | 16 | class request; 17 | class response; 18 | class io_service_pool; 19 | class tcp_session; 20 | class tcp_session_cache; 21 | 22 | struct connection_status 23 | { 24 | bool created; 25 | std::string session_id; 26 | int connection_counts; 27 | }; 28 | 29 | using notify_handler = std::function; 30 | 31 | class tcp_server 32 | { 33 | public: 34 | tcp_server(const std::string& host, int ios_threads); 35 | virtual ~tcp_server(); 36 | 37 | void set_connection_notify(const notify_handler& func); 38 | void publish(const std::string& session_id, const std::shared_ptr& message); 39 | virtual bool run(); 40 | virtual void stop(); 41 | 42 | protected: 43 | virtual void deal_request(const std::shared_ptr& req, const std::shared_ptr& res) = 0; 44 | 45 | private: 46 | bool start_listen(); 47 | bool listen(const std::string& ip, unsigned short port); 48 | void accept(); 49 | void deal_connection_created(const std::shared_ptr& session); 50 | void deal_connection_closed(const std::string& session_id); 51 | int make_serial_num(); 52 | 53 | private: 54 | std::string host_; 55 | std::shared_ptr session_cache_; 56 | std::shared_ptr pool_; 57 | boost::asio::ip::tcp::acceptor acceptor_; 58 | notify_handler notify_func_; 59 | std::atomic connection_counts_{ 0 }; 60 | }; 61 | 62 | } 63 | -------------------------------------------------------------------------------- /easyrpc/net/tcp_session.cpp: -------------------------------------------------------------------------------- 1 | #include "tcp_session.h" 2 | #include "easyrpc/utility/logger.h" 3 | #include "easyrpc/codec/codec.h" 4 | 5 | namespace easyrpc 6 | { 7 | 8 | tcp_session::tcp_session(const std::shared_ptr& dec, boost::asio::io_service& ios, 9 | const std::function& closed_callback) 10 | : codec_(dec), 11 | ios_(ios), 12 | socket_(ios), 13 | closed_callback_(closed_callback) 14 | { 15 | 16 | } 17 | 18 | tcp_session::~tcp_session() 19 | { 20 | close(); 21 | } 22 | 23 | void tcp_session::run() 24 | { 25 | set_no_delay(); 26 | async_read(); 27 | active_ = true; 28 | } 29 | 30 | void tcp_session::close() 31 | { 32 | active_ = false; 33 | if (socket_.is_open()) 34 | { 35 | boost::system::error_code ignore_ec; 36 | socket_.shutdown(boost::asio::socket_base::shutdown_both, ignore_ec); 37 | socket_.close(ignore_ec); 38 | } 39 | } 40 | 41 | boost::asio::ip::tcp::socket& tcp_session::get_socket() 42 | { 43 | return socket_; 44 | } 45 | 46 | std::shared_ptr& tcp_session::get_codec() 47 | { 48 | return codec_; 49 | } 50 | 51 | std::string tcp_session::get_session_id() 52 | { 53 | if (session_id_.empty()) 54 | { 55 | if (socket_.is_open()) 56 | { 57 | boost::system::error_code ec, ec2; 58 | auto local_endpoint = socket_.local_endpoint(); 59 | auto remote_endpoint = socket_.remote_endpoint(); 60 | if (!ec && !ec2) 61 | { 62 | session_id_ = local_endpoint.address().to_string() + ":" 63 | + std::to_string(local_endpoint.port()) + "&" 64 | + remote_endpoint.address().to_string() + ":" 65 | + std::to_string(remote_endpoint.port()); 66 | } 67 | } 68 | } 69 | 70 | return session_id_; 71 | } 72 | 73 | void tcp_session::async_write(const std::shared_ptr& network_data) 74 | { 75 | if (!active_) 76 | { 77 | return; 78 | } 79 | 80 | auto self(shared_from_this()); 81 | ios_.post([this, self, network_data] 82 | { 83 | bool empty = send_queue_.empty(); 84 | send_queue_.emplace_back(network_data); 85 | if (empty) 86 | { 87 | async_write_loop(); 88 | } 89 | }); 90 | } 91 | 92 | void tcp_session::async_write_loop() 93 | { 94 | auto self(shared_from_this()); 95 | boost::asio::async_write(socket_, boost::asio::buffer(*send_queue_.front()), 96 | [this, self](boost::system::error_code ec, std::size_t) 97 | { 98 | if (!ec) 99 | { 100 | send_queue_.pop_front(); 101 | if (!send_queue_.empty()) 102 | { 103 | async_write_loop(); 104 | } 105 | } 106 | else 107 | { 108 | log_warn << ec.message(); 109 | send_queue_.clear(); 110 | } 111 | }); 112 | } 113 | 114 | void tcp_session::async_read() 115 | { 116 | resize_buffer(codec_->get_next_recv_bytes()); 117 | auto self(shared_from_this()); 118 | boost::asio::async_read(socket_, boost::asio::buffer(buffer_), 119 | [this, self](boost::system::error_code ec, std::size_t) 120 | { 121 | if (!ec) 122 | { 123 | codec_->decode(buffer_, self); 124 | async_read(); 125 | } 126 | else if (active_ && ec != boost::asio::error::operation_aborted) 127 | { 128 | deal_connection_closed(); 129 | } 130 | }); 131 | } 132 | 133 | void tcp_session::set_no_delay() 134 | { 135 | boost::asio::ip::tcp::no_delay option(true); 136 | boost::system::error_code ec; 137 | socket_.set_option(option, ec); 138 | } 139 | 140 | void tcp_session::resize_buffer(int size) 141 | { 142 | buffer_.resize(size); 143 | } 144 | 145 | void tcp_session::deal_connection_closed() 146 | { 147 | close(); 148 | closed_callback_(get_session_id()); 149 | } 150 | 151 | } 152 | -------------------------------------------------------------------------------- /easyrpc/net/tcp_session.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file tcp_session.h 3 | * @brief tcp会话 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-11-05 7 | */ 8 | #pragma once 9 | 10 | #include 11 | #include "easyrpc/utility/threadsafe_list.h" 12 | 13 | namespace easyrpc 14 | { 15 | 16 | class codec; 17 | 18 | class tcp_session : public std::enable_shared_from_this 19 | { 20 | public: 21 | tcp_session(const std::shared_ptr& dec, boost::asio::io_service& ios, 22 | const std::function& closed_callback); 23 | ~tcp_session(); 24 | 25 | void run(); 26 | void close(); 27 | boost::asio::ip::tcp::socket& get_socket(); 28 | std::shared_ptr& get_codec(); 29 | std::string get_session_id(); 30 | void async_write(const std::shared_ptr& network_data); 31 | 32 | private: 33 | void async_write_loop(); 34 | void async_read(); 35 | void set_no_delay(); 36 | void resize_buffer(int size); 37 | void deal_connection_closed(); 38 | 39 | private: 40 | std::shared_ptr codec_; 41 | boost::asio::io_service& ios_; 42 | boost::asio::ip::tcp::socket socket_; 43 | std::function closed_callback_; 44 | threadsafe_list> send_queue_; 45 | std::vector buffer_; 46 | std::atomic active_{ false }; 47 | std::string session_id_; 48 | }; 49 | 50 | } 51 | -------------------------------------------------------------------------------- /easyrpc/net/tcp_session_cache.cpp: -------------------------------------------------------------------------------- 1 | #include "tcp_session_cache.h" 2 | 3 | namespace easyrpc 4 | { 5 | 6 | std::shared_ptr tcp_session_cache::get_session(const std::string& session_id) 7 | { 8 | lock_shared lock(mutex_, true); 9 | auto iter = sessions_.find(session_id); 10 | if (iter != sessions_.end()) 11 | { 12 | return iter->second; 13 | } 14 | 15 | return nullptr; 16 | } 17 | 18 | void tcp_session_cache::add_session(const std::string& session_id, const std::shared_ptr& session) 19 | { 20 | lock_shared lock(mutex_); 21 | sessions_.emplace(session_id, session); 22 | } 23 | 24 | void tcp_session_cache::remove_session(const std::string& session_id) 25 | { 26 | lock_shared lock(mutex_); 27 | sessions_.erase(session_id); 28 | } 29 | 30 | void tcp_session_cache::clear() 31 | { 32 | lock_shared lock(mutex_); 33 | sessions_.clear(); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /easyrpc/net/tcp_session_cache.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file tcp_session_cache.h 3 | * @brief tcp会话缓存 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-12-01 7 | */ 8 | #pragma once 9 | 10 | #include 11 | #include 12 | #include "easyrpc/utility/shared_mutex.h" 13 | 14 | namespace easyrpc 15 | { 16 | 17 | class tcp_session; 18 | 19 | class tcp_session_cache 20 | { 21 | public: 22 | std::shared_ptr get_session(const std::string& session_id); 23 | void add_session(const std::string& session_id, const std::shared_ptr& session); 24 | void remove_session(const std::string& session_id); 25 | void clear(); 26 | 27 | private: 28 | std::unordered_map> sessions_; 29 | shared_mutex mutex_; 30 | }; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /easyrpc/server/request.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file request.h 3 | * @brief 包装rpc服务请求参数 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-11-19 7 | */ 8 | #pragma once 9 | 10 | #include 11 | 12 | namespace easyrpc 13 | { 14 | 15 | struct request 16 | { 17 | request(const std::shared_ptr& msg, const std::string& id) 18 | : message(msg), session_id(id) {} 19 | 20 | std::shared_ptr message; 21 | std::string session_id; 22 | }; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /easyrpc/server/response.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file response.h 3 | * @brief 包装rpc服务应答参数 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-11-19 7 | */ 8 | #pragma once 9 | 10 | #include "easyrpc/codec/codec.h" 11 | #include "easyrpc/net/tcp_session.h" 12 | 13 | namespace easyrpc 14 | { 15 | 16 | struct response 17 | { 18 | response(const std::shared_ptr& sess, int serial) 19 | : session(sess), serial_num(serial) {} 20 | 21 | void set_response(const std::shared_ptr& message) 22 | { 23 | if (message) 24 | { 25 | auto network_data = session->get_codec()->encode(serial_num, message_model::rpc, message); 26 | if (network_data) 27 | { 28 | session->async_write(network_data); 29 | } 30 | } 31 | } 32 | 33 | std::shared_ptr session; 34 | int serial_num; 35 | }; 36 | 37 | } 38 | -------------------------------------------------------------------------------- /easyrpc/server/router.cpp: -------------------------------------------------------------------------------- 1 | #include "router.h" 2 | #include "request.h" 3 | #include "response.h" 4 | #include "easyrpc/utility/logger.h" 5 | 6 | namespace easyrpc 7 | { 8 | 9 | router::~router() 10 | { 11 | stop(); 12 | } 13 | 14 | void router::run(int work_threads) 15 | { 16 | threadpool_.init_thread_size(work_threads); 17 | } 18 | 19 | std::size_t router::route_table_size() 20 | { 21 | return route_table_.size(); 22 | } 23 | 24 | void router::route(const std::string& message_name, const request_handler& func) 25 | { 26 | route_table_.emplace(message_name, func); 27 | } 28 | 29 | void router::stop() 30 | { 31 | threadpool_.stop(); 32 | route_table_.clear(); 33 | } 34 | 35 | void router::do_route(const std::shared_ptr& req, const std::shared_ptr& res) 36 | { 37 | threadpool_.add_task(std::bind(&router::route_thread, this, req, res)); 38 | } 39 | 40 | void router::route_thread(const std::shared_ptr& req, const std::shared_ptr& res) 41 | { 42 | auto iter = route_table_.find(req->message->GetDescriptor()->full_name()); 43 | if (iter != route_table_.end()) 44 | { 45 | try 46 | { 47 | iter->second(req, res); 48 | } 49 | catch (std::exception& e) 50 | { 51 | log_warn << e.what(); 52 | } 53 | } 54 | else 55 | { 56 | log_warn << "Route failed, message name: " << req->message->GetDescriptor()->full_name(); 57 | } 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /easyrpc/server/router.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file router.h 3 | * @brief rpc服务消息路由器 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-11-19 7 | */ 8 | #pragma once 9 | 10 | #include 11 | #include "easyrpc/utility/thread_pool.h" 12 | 13 | namespace easyrpc 14 | { 15 | 16 | class request; 17 | class response; 18 | 19 | using request_handler = std::function&, const std::shared_ptr&)>; 20 | 21 | class router 22 | { 23 | public: 24 | ~router(); 25 | 26 | void run(int work_threads); 27 | std::size_t route_table_size(); 28 | void route(const std::string& message_name, const request_handler& func); 29 | void stop(); 30 | void do_route(const std::shared_ptr& req, const std::shared_ptr& res); 31 | 32 | private: 33 | void route_thread(const std::shared_ptr& req, const std::shared_ptr& res); 34 | 35 | private: 36 | thread_pool threadpool_; 37 | std::unordered_map route_table_; 38 | }; 39 | 40 | } 41 | -------------------------------------------------------------------------------- /easyrpc/server/rpc_server.cpp: -------------------------------------------------------------------------------- 1 | #include "rpc_server.h" 2 | #include "easyrpc/utility/logger.h" 3 | 4 | namespace easyrpc 5 | { 6 | 7 | rpc_server::rpc_server(const std::string& host, int ios_threads, int work_threads) 8 | : tcp_server(host, ios_threads), 9 | work_threads_(work_threads) 10 | { 11 | 12 | } 13 | 14 | rpc_server::~rpc_server() 15 | { 16 | stop(); 17 | } 18 | 19 | bool rpc_server::run() 20 | { 21 | if (router_.route_table_size() == 0) 22 | { 23 | log_warn << "Route table is empty"; 24 | return false; 25 | } 26 | 27 | if (tcp_server::run()) 28 | { 29 | router_.run(work_threads_); 30 | return true; 31 | } 32 | 33 | return false; 34 | } 35 | 36 | void rpc_server::stop() 37 | { 38 | tcp_server::stop(); 39 | router_.stop(); 40 | } 41 | 42 | void rpc_server::route(const std::string& message_name, const request_handler& func) 43 | { 44 | router_.route(message_name, func); 45 | } 46 | 47 | void rpc_server::deal_request(const std::shared_ptr& req, const std::shared_ptr& res) 48 | { 49 | router_.do_route(req, res); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /easyrpc/server/rpc_server.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file rpc_server.h 3 | * @brief rpc服务端 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-11-19 7 | */ 8 | #pragma once 9 | 10 | #include "easyrpc/net/tcp_server.h" 11 | #include "router.h" 12 | 13 | namespace easyrpc 14 | { 15 | 16 | class rpc_server : public tcp_server 17 | { 18 | public: 19 | rpc_server(const std::string& host, int ios_threads = 4, int work_threads = 4); 20 | virtual ~rpc_server(); 21 | 22 | virtual bool run(); 23 | virtual void stop(); 24 | void route(const std::string& message_name, const request_handler& func); 25 | 26 | protected: 27 | virtual void deal_request(const std::shared_ptr& req, const std::shared_ptr& res); 28 | 29 | private: 30 | int work_threads_; 31 | router router_; 32 | }; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /easyrpc/utility/logger.cpp: -------------------------------------------------------------------------------- 1 | #include "logger.h" 2 | #include "utiltiy.h" 3 | 4 | logger::logger(const std::string& file_path, unsigned long line, log_level level) 5 | : level_(level) 6 | { 7 | buffer_ = std::make_shared(); 8 | int pos = file_path.find_last_of("/"); 9 | (*buffer_) << file_path.substr(pos + 1) << ":" << line << " "; 10 | } 11 | 12 | logger::~logger() 13 | { 14 | print_log(make_log()); 15 | } 16 | 17 | std::string logger::get_level_string() 18 | { 19 | switch (level_) 20 | { 21 | case log_level::error: return "[error]"; 22 | case log_level::warn: return "[warn]"; 23 | case log_level::info: return "[info]"; 24 | case log_level::debug: return "[debug]"; 25 | default: return "[debug]"; 26 | } 27 | } 28 | 29 | std::string logger::make_log() 30 | { 31 | std::string log; 32 | log += utiltiy::get_time_us(); 33 | log += " "; 34 | log += get_level_string(); 35 | log += " "; 36 | log += buffer_->str(); 37 | 38 | return log; 39 | } 40 | 41 | void logger::print_log(const std::string& log) 42 | { 43 | switch (level_) 44 | { 45 | case log_level::error: printf("\033[31m%s\n\033[0m", log.c_str()); break; 46 | case log_level::warn: printf("\033[33m%s\n\033[0m", log.c_str()); break; 47 | default: printf("%s\n", log.c_str()); break; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /easyrpc/utility/logger.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file logger.h 3 | * @brief 日志库 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-11-05 7 | */ 8 | #pragma once 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | enum class log_level 16 | { 17 | debug = 0, 18 | info, 19 | warn, 20 | error 21 | }; 22 | 23 | class logger 24 | { 25 | public: 26 | logger(const std::string& file_path, unsigned long line, log_level level); 27 | ~logger(); 28 | 29 | template 30 | logger& operator << (const T& t) 31 | { 32 | (*buffer_) << t; 33 | return *this; 34 | } 35 | 36 | private: 37 | std::string get_level_string(); 38 | std::string make_log(); 39 | void print_log(const std::string& log); 40 | 41 | private: 42 | std::shared_ptr buffer_; 43 | log_level level_; 44 | }; 45 | 46 | #define FILE_LOCATION __FILE__, __LINE__ 47 | 48 | #define log_error logger(FILE_LOCATION, log_level::error) 49 | #define log_warn logger(FILE_LOCATION, log_level::warn) 50 | #define log_info logger(FILE_LOCATION, log_level::info) 51 | #define log_debug logger(FILE_LOCATION, log_level::debug) 52 | -------------------------------------------------------------------------------- /easyrpc/utility/protobuf_serialize.cpp: -------------------------------------------------------------------------------- 1 | #include "protobuf_serialize.h" 2 | #include "logger.h" 3 | 4 | std::string protobuf_serialize::serialize(const std::shared_ptr& message) 5 | { 6 | if (!message->IsInitialized()) 7 | { 8 | log_warn << "Message initialized failed"; 9 | return ""; 10 | } 11 | 12 | return message->SerializeAsString(); 13 | } 14 | 15 | std::shared_ptr protobuf_serialize::unserialize(const std::string& message_name, 16 | const std::string& body) 17 | { 18 | if (message_name.empty()) 19 | { 20 | log_warn << "Message name is empty"; 21 | return nullptr; 22 | } 23 | 24 | auto message = create_message(message_name); 25 | if (message == nullptr) 26 | { 27 | log_warn<< "Message is nullptr"; 28 | return nullptr; 29 | } 30 | 31 | if (!message->ParseFromString(body)) 32 | { 33 | log_warn << "Parse from string failed, message name: " << message_name; 34 | return nullptr; 35 | } 36 | 37 | if (!message->IsInitialized()) 38 | { 39 | log_warn << "Message initialized failed, message name: " << message_name; 40 | return nullptr; 41 | } 42 | 43 | return message; 44 | } 45 | 46 | std::shared_ptr protobuf_serialize::create_message(const std::string& message_name) 47 | { 48 | const auto descriptor = google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(message_name); 49 | if (descriptor) 50 | { 51 | const auto prototype = google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor); 52 | if (prototype) 53 | { 54 | return std::shared_ptr(prototype->New()); 55 | } 56 | } 57 | 58 | return nullptr; 59 | } 60 | -------------------------------------------------------------------------------- /easyrpc/utility/protobuf_serialize.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file protobuf_serialize.h 3 | * @brief protobuf序列化/反序列化类 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-11-05 7 | */ 8 | #pragma once 9 | 10 | #include 11 | #include 12 | 13 | class protobuf_serialize 14 | { 15 | public: 16 | static std::string serialize(const std::shared_ptr& message); 17 | static std::shared_ptr unserialize(const std::string& message_name, const std::string& body); 18 | 19 | private: 20 | static std::shared_ptr create_message(const std::string& message_name); 21 | }; 22 | -------------------------------------------------------------------------------- /easyrpc/utility/shared_mutex.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file shared_mutex.h 3 | * @brief 封装读写锁 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2018-01-01 7 | */ 8 | #pragma once 9 | 10 | #include 11 | 12 | class shared_mutex 13 | { 14 | public: 15 | shared_mutex() 16 | { 17 | pthread_rwlock_init(&mutex_, nullptr); 18 | } 19 | 20 | ~shared_mutex() 21 | { 22 | pthread_rwlock_destroy(&mutex_); 23 | } 24 | 25 | void lock_read() 26 | { 27 | pthread_rwlock_rdlock(&mutex_); 28 | } 29 | 30 | void lock_write() 31 | { 32 | pthread_rwlock_wrlock(&mutex_); 33 | } 34 | 35 | void unlock() 36 | { 37 | pthread_rwlock_unlock(&mutex_); 38 | } 39 | 40 | private: 41 | pthread_rwlock_t mutex_; 42 | }; 43 | 44 | class lock_shared 45 | { 46 | public: 47 | lock_shared(shared_mutex& mt, bool shared = false) 48 | : mutex_(mt) 49 | { 50 | if (shared) 51 | { 52 | mutex_.lock_read(); 53 | } 54 | else 55 | { 56 | mutex_.lock_write(); 57 | } 58 | } 59 | 60 | ~lock_shared() 61 | { 62 | mutex_.unlock(); 63 | } 64 | 65 | private: 66 | shared_mutex& mutex_; 67 | }; 68 | -------------------------------------------------------------------------------- /easyrpc/utility/task_timer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file task_timer.h 3 | * @brief 任务定时器 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-11-05 7 | */ 8 | #pragma once 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | template 19 | class task_timer 20 | { 21 | public: 22 | task_timer() : work_(ios_), timer_(ios_), single_shot_(false) {} 23 | ~task_timer() 24 | { 25 | destroy(); 26 | } 27 | 28 | void start(std::size_t duration) 29 | { 30 | if (ios_.stopped() || duration == 0) 31 | { 32 | return; 33 | } 34 | 35 | duration_ = duration; 36 | if (thread_ == nullptr) 37 | { 38 | thread_ = std::make_unique([this]{ ios_.run(); }); 39 | } 40 | start(); 41 | } 42 | 43 | void start() 44 | { 45 | if (duration_ == 0) 46 | { 47 | return; 48 | } 49 | 50 | timer_.expires_from_now(Duration(duration_)); 51 | timer_.async_wait([this](const boost::system::error_code& ec) 52 | { 53 | if (ec) 54 | { 55 | return; 56 | } 57 | 58 | for (auto& func : func_list_) 59 | { 60 | func(); 61 | } 62 | 63 | if (!single_shot_) 64 | { 65 | start(); 66 | } 67 | }); 68 | } 69 | 70 | void stop() 71 | { 72 | timer_.cancel(); 73 | } 74 | 75 | void destroy() 76 | { 77 | stop(); 78 | ios_.stop(); 79 | if (thread_ != nullptr) 80 | { 81 | if (thread_->joinable()) 82 | { 83 | thread_->join(); 84 | } 85 | } 86 | } 87 | 88 | void bind(const std::function& func) 89 | { 90 | func_list_.emplace_back(func); 91 | } 92 | 93 | void set_single_shot(bool single_short) 94 | { 95 | single_shot_ = single_short; 96 | } 97 | 98 | private: 99 | boost::asio::io_service ios_; 100 | boost::asio::io_service::work work_; 101 | boost::asio::deadline_timer timer_; 102 | std::unique_ptr thread_ = nullptr; 103 | std::vector> func_list_; 104 | std::atomic single_shot_; 105 | std::size_t duration_ = 0; 106 | }; 107 | 108 | -------------------------------------------------------------------------------- /easyrpc/utility/thread_pool.cpp: -------------------------------------------------------------------------------- 1 | #include "thread_pool.h" 2 | 3 | thread_pool::~thread_pool() 4 | { 5 | stop(); 6 | } 7 | 8 | void thread_pool::init_thread_size(int size) 9 | { 10 | for (int i = 0; i < size; ++i) 11 | { 12 | auto t = std::make_shared(std::bind(&thread_pool::run_task, this)); 13 | threads_.emplace_back(t); 14 | } 15 | } 16 | 17 | void thread_pool::stop() 18 | { 19 | std::call_once(call_flag_, [this]{ stop_impl(); }); 20 | } 21 | 22 | std::size_t thread_pool::size() 23 | { 24 | std::unique_lock lock(mutex_); 25 | return task_queue_.size(); 26 | } 27 | 28 | void thread_pool::run_task() 29 | { 30 | while (true) 31 | { 32 | std::function task; 33 | 34 | { 35 | std::unique_lock lock(mutex_); 36 | cond_.wait(lock, [this]{ return threadpool_stoped_ || !task_queue_.empty(); }); 37 | if (threadpool_stoped_ && task_queue_.empty()) 38 | { 39 | return; 40 | } 41 | task = std::move(task_queue_.front()); 42 | task_queue_.pop(); 43 | } 44 | 45 | task(); 46 | } 47 | } 48 | 49 | void thread_pool::stop_impl() 50 | { 51 | threadpool_stoped_ = true; 52 | cond_.notify_all(); 53 | for(auto& t: threads_) 54 | { 55 | if (t->joinable()) 56 | { 57 | t->join(); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /easyrpc/utility/thread_pool.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file thread_pool.h 3 | * @brief 线程池 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-11-05 7 | */ 8 | #pragma once 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | class thread_pool 21 | { 22 | public: 23 | ~thread_pool(); 24 | void init_thread_size(int size); 25 | void stop(); 26 | std::size_t size(); 27 | 28 | template 29 | auto add_task(Function&& func, Args&&... args) -> std::future::type> 30 | { 31 | if (threadpool_stoped_) 32 | { 33 | throw std::runtime_error("Add task on stopped thread pool"); 34 | } 35 | 36 | using return_type = typename std::result_of::type; 37 | auto task = std::make_shared>( std::bind(std::forward(func), std::forward(args)...)); 38 | std::future res = task->get_future(); 39 | 40 | std::unique_lock lock(mutex_); 41 | task_queue_.emplace([task](){ (*task)(); }); 42 | lock.unlock(); 43 | 44 | cond_.notify_one(); 45 | return res; 46 | } 47 | 48 | private: 49 | void run_task(); 50 | void stop_impl(); 51 | 52 | private: 53 | std::vector> threads_; 54 | std::queue> task_queue_; 55 | 56 | std::mutex mutex_; 57 | std::condition_variable cond_; 58 | std::atomic threadpool_stoped_{ false }; 59 | std::once_flag call_flag_; 60 | }; 61 | -------------------------------------------------------------------------------- /easyrpc/utility/threadsafe_list.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file threadsafe_list.hpp 3 | * @brief 线程安全的队列 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-11-05 7 | */ 8 | #pragma once 9 | 10 | #include 11 | #include "shared_mutex.h" 12 | 13 | template 14 | class threadsafe_list 15 | { 16 | public: 17 | void emplace_back(const T& t) 18 | { 19 | lock_shared lock(mutex_); 20 | list_.emplace_back(t); 21 | } 22 | 23 | T front() 24 | { 25 | lock_shared lock(mutex_, true); 26 | return list_.front(); 27 | } 28 | 29 | void pop_front() 30 | { 31 | lock_shared lock(mutex_); 32 | list_.pop_front(); 33 | } 34 | 35 | void clear() 36 | { 37 | lock_shared lock(mutex_); 38 | list_.clear(); 39 | } 40 | 41 | bool empty() 42 | { 43 | lock_shared lock(mutex_, true); 44 | return list_.empty(); 45 | } 46 | 47 | std::size_t size() 48 | { 49 | lock_shared lock(mutex_, true); 50 | return list_.size(); 51 | } 52 | 53 | private: 54 | std::list list_; 55 | shared_mutex mutex_; 56 | }; 57 | -------------------------------------------------------------------------------- /easyrpc/utility/utiltiy.cpp: -------------------------------------------------------------------------------- 1 | #include "utiltiy.h" 2 | 3 | std::vector utiltiy::split(const std::string& str, const std::string& delimiter) 4 | { 5 | std::string save_str = str; 6 | char* save = nullptr; 7 | 8 | char* token = strtok_r(const_cast(save_str.c_str()), delimiter.c_str(), &save); 9 | std::vector results; 10 | while (token != nullptr) 11 | { 12 | results.emplace_back(token); 13 | token = strtok_r(nullptr, delimiter.c_str(), &save); 14 | } 15 | 16 | return results; 17 | } 18 | 19 | bool utiltiy::contains(const std::string& str, const std::string& token) 20 | { 21 | return str.find(token) == std::string::npos ? false : true; 22 | } 23 | 24 | bool utiltiy::get_ip_and_port(const std::string& address, std::string& ip, unsigned short& port) 25 | { 26 | if (!contains(address, ":")) 27 | { 28 | return false; 29 | } 30 | 31 | auto vec = split(address, ":"); 32 | if (vec.size() != 2) 33 | { 34 | return false; 35 | } 36 | 37 | ip = vec[0]; 38 | port = std::atoi(vec[1].c_str()); 39 | 40 | return true; 41 | } 42 | 43 | std::string utiltiy::get_time_us() 44 | { 45 | struct timeval now_tv; 46 | gettimeofday(&now_tv, nullptr); 47 | 48 | struct tm t; 49 | localtime_r(&now_tv.tv_sec, &t); 50 | 51 | char time_str[27] = {0}; 52 | snprintf(time_str, sizeof(time_str), "%04d-%02d-%02d %02d:%02d:%02d.%06d", 53 | t.tm_year + 1900, 54 | t.tm_mon + 1, 55 | t.tm_mday, 56 | t.tm_hour, 57 | t.tm_min, 58 | t.tm_sec, 59 | static_cast(now_tv.tv_usec)); 60 | 61 | return time_str; 62 | } 63 | -------------------------------------------------------------------------------- /easyrpc/utility/utiltiy.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file utiltiy.h 3 | * @brief 通用工具 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-11-05 7 | */ 8 | #pragma once 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | class utiltiy 16 | { 17 | public: 18 | static std::vector split(const std::string& str, const std::string& delimiter); 19 | static bool contains(const std::string& str, const std::string& token); 20 | static bool get_ip_and_port(const std::string& address, std::string& ip, unsigned short& port); 21 | static std::string get_time_us(); 22 | }; 23 | 24 | -------------------------------------------------------------------------------- /test/protoc/build_proto.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | protos=`find ./ -name '*.proto'` 4 | for i in $protos 5 | do 6 | echo 'building ' $i 7 | protoc --cpp_out=./code $i 8 | done 9 | -------------------------------------------------------------------------------- /test/protoc/code/common.pb.cc: -------------------------------------------------------------------------------- 1 | // Generated by the protocol buffer compiler. DO NOT EDIT! 2 | // source: common.proto 3 | 4 | #include "common.pb.h" 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | // This is a temporary google only hack 18 | #ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS 19 | #include "third_party/protobuf/version.h" 20 | #endif 21 | // @@protoc_insertion_point(includes) 22 | class echo_messageDefaultTypeInternal { 23 | public: 24 | ::google::protobuf::internal::ExplicitlyConstructed 25 | _instance; 26 | } _echo_message_default_instance_; 27 | class auto_weather_messageDefaultTypeInternal { 28 | public: 29 | ::google::protobuf::internal::ExplicitlyConstructed 30 | _instance; 31 | } _auto_weather_message_default_instance_; 32 | namespace protobuf_common_2eproto { 33 | void InitDefaultsecho_messageImpl() { 34 | GOOGLE_PROTOBUF_VERIFY_VERSION; 35 | 36 | #ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS 37 | ::google::protobuf::internal::InitProtobufDefaultsForceUnique(); 38 | #else 39 | ::google::protobuf::internal::InitProtobufDefaults(); 40 | #endif // GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS 41 | { 42 | void* ptr = &::_echo_message_default_instance_; 43 | new (ptr) ::echo_message(); 44 | ::google::protobuf::internal::OnShutdownDestroyMessage(ptr); 45 | } 46 | ::echo_message::InitAsDefaultInstance(); 47 | } 48 | 49 | void InitDefaultsecho_message() { 50 | static GOOGLE_PROTOBUF_DECLARE_ONCE(once); 51 | ::google::protobuf::GoogleOnceInit(&once, &InitDefaultsecho_messageImpl); 52 | } 53 | 54 | void InitDefaultsauto_weather_messageImpl() { 55 | GOOGLE_PROTOBUF_VERIFY_VERSION; 56 | 57 | #ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS 58 | ::google::protobuf::internal::InitProtobufDefaultsForceUnique(); 59 | #else 60 | ::google::protobuf::internal::InitProtobufDefaults(); 61 | #endif // GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS 62 | { 63 | void* ptr = &::_auto_weather_message_default_instance_; 64 | new (ptr) ::auto_weather_message(); 65 | ::google::protobuf::internal::OnShutdownDestroyMessage(ptr); 66 | } 67 | ::auto_weather_message::InitAsDefaultInstance(); 68 | } 69 | 70 | void InitDefaultsauto_weather_message() { 71 | static GOOGLE_PROTOBUF_DECLARE_ONCE(once); 72 | ::google::protobuf::GoogleOnceInit(&once, &InitDefaultsauto_weather_messageImpl); 73 | } 74 | 75 | ::google::protobuf::Metadata file_level_metadata[2]; 76 | 77 | const ::google::protobuf::uint32 TableStruct::offsets[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = { 78 | ~0u, // no _has_bits_ 79 | GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::echo_message, _internal_metadata_), 80 | ~0u, // no _extensions_ 81 | ~0u, // no _oneof_case_ 82 | ~0u, // no _weak_field_map_ 83 | GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::echo_message, str_), 84 | GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::echo_message, num_), 85 | ~0u, // no _has_bits_ 86 | GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::auto_weather_message, _internal_metadata_), 87 | ~0u, // no _extensions_ 88 | ~0u, // no _oneof_case_ 89 | ~0u, // no _weak_field_map_ 90 | GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::auto_weather_message, city_name_), 91 | GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::auto_weather_message, weather_), 92 | }; 93 | static const ::google::protobuf::internal::MigrationSchema schemas[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = { 94 | { 0, -1, sizeof(::echo_message)}, 95 | { 7, -1, sizeof(::auto_weather_message)}, 96 | }; 97 | 98 | static ::google::protobuf::Message const * const file_default_instances[] = { 99 | reinterpret_cast(&::_echo_message_default_instance_), 100 | reinterpret_cast(&::_auto_weather_message_default_instance_), 101 | }; 102 | 103 | void protobuf_AssignDescriptors() { 104 | AddDescriptors(); 105 | ::google::protobuf::MessageFactory* factory = NULL; 106 | AssignDescriptors( 107 | "common.proto", schemas, file_default_instances, TableStruct::offsets, factory, 108 | file_level_metadata, NULL, NULL); 109 | } 110 | 111 | void protobuf_AssignDescriptorsOnce() { 112 | static GOOGLE_PROTOBUF_DECLARE_ONCE(once); 113 | ::google::protobuf::GoogleOnceInit(&once, &protobuf_AssignDescriptors); 114 | } 115 | 116 | void protobuf_RegisterTypes(const ::std::string&) GOOGLE_PROTOBUF_ATTRIBUTE_COLD; 117 | void protobuf_RegisterTypes(const ::std::string&) { 118 | protobuf_AssignDescriptorsOnce(); 119 | ::google::protobuf::internal::RegisterAllTypes(file_level_metadata, 2); 120 | } 121 | 122 | void AddDescriptorsImpl() { 123 | InitDefaults(); 124 | static const char descriptor[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = { 125 | "\n\014common.proto\"(\n\014echo_message\022\013\n\003str\030\001 " 126 | "\001(\t\022\013\n\003num\030\002 \001(\005\":\n\024auto_weather_message" 127 | "\022\021\n\tcity_name\030\001 \001(\t\022\017\n\007weather\030\002 \001(\tb\006pr" 128 | "oto3" 129 | }; 130 | ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( 131 | descriptor, 124); 132 | ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( 133 | "common.proto", &protobuf_RegisterTypes); 134 | } 135 | 136 | void AddDescriptors() { 137 | static GOOGLE_PROTOBUF_DECLARE_ONCE(once); 138 | ::google::protobuf::GoogleOnceInit(&once, &AddDescriptorsImpl); 139 | } 140 | // Force AddDescriptors() to be called at dynamic initialization time. 141 | struct StaticDescriptorInitializer { 142 | StaticDescriptorInitializer() { 143 | AddDescriptors(); 144 | } 145 | } static_descriptor_initializer; 146 | } // namespace protobuf_common_2eproto 147 | 148 | // =================================================================== 149 | 150 | void echo_message::InitAsDefaultInstance() { 151 | } 152 | #if !defined(_MSC_VER) || _MSC_VER >= 1900 153 | const int echo_message::kStrFieldNumber; 154 | const int echo_message::kNumFieldNumber; 155 | #endif // !defined(_MSC_VER) || _MSC_VER >= 1900 156 | 157 | echo_message::echo_message() 158 | : ::google::protobuf::Message(), _internal_metadata_(NULL) { 159 | if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) { 160 | ::protobuf_common_2eproto::InitDefaultsecho_message(); 161 | } 162 | SharedCtor(); 163 | // @@protoc_insertion_point(constructor:echo_message) 164 | } 165 | echo_message::echo_message(const echo_message& from) 166 | : ::google::protobuf::Message(), 167 | _internal_metadata_(NULL), 168 | _cached_size_(0) { 169 | _internal_metadata_.MergeFrom(from._internal_metadata_); 170 | str_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 171 | if (from.str().size() > 0) { 172 | str_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.str_); 173 | } 174 | num_ = from.num_; 175 | // @@protoc_insertion_point(copy_constructor:echo_message) 176 | } 177 | 178 | void echo_message::SharedCtor() { 179 | str_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 180 | num_ = 0; 181 | _cached_size_ = 0; 182 | } 183 | 184 | echo_message::~echo_message() { 185 | // @@protoc_insertion_point(destructor:echo_message) 186 | SharedDtor(); 187 | } 188 | 189 | void echo_message::SharedDtor() { 190 | str_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 191 | } 192 | 193 | void echo_message::SetCachedSize(int size) const { 194 | GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); 195 | _cached_size_ = size; 196 | GOOGLE_SAFE_CONCURRENT_WRITES_END(); 197 | } 198 | const ::google::protobuf::Descriptor* echo_message::descriptor() { 199 | ::protobuf_common_2eproto::protobuf_AssignDescriptorsOnce(); 200 | return ::protobuf_common_2eproto::file_level_metadata[kIndexInFileMessages].descriptor; 201 | } 202 | 203 | const echo_message& echo_message::default_instance() { 204 | ::protobuf_common_2eproto::InitDefaultsecho_message(); 205 | return *internal_default_instance(); 206 | } 207 | 208 | echo_message* echo_message::New(::google::protobuf::Arena* arena) const { 209 | echo_message* n = new echo_message; 210 | if (arena != NULL) { 211 | arena->Own(n); 212 | } 213 | return n; 214 | } 215 | 216 | void echo_message::Clear() { 217 | // @@protoc_insertion_point(message_clear_start:echo_message) 218 | ::google::protobuf::uint32 cached_has_bits = 0; 219 | // Prevent compiler warnings about cached_has_bits being unused 220 | (void) cached_has_bits; 221 | 222 | str_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 223 | num_ = 0; 224 | _internal_metadata_.Clear(); 225 | } 226 | 227 | bool echo_message::MergePartialFromCodedStream( 228 | ::google::protobuf::io::CodedInputStream* input) { 229 | #define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure 230 | ::google::protobuf::uint32 tag; 231 | // @@protoc_insertion_point(parse_start:echo_message) 232 | for (;;) { 233 | ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u); 234 | tag = p.first; 235 | if (!p.second) goto handle_unusual; 236 | switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { 237 | // string str = 1; 238 | case 1: { 239 | if (static_cast< ::google::protobuf::uint8>(tag) == 240 | static_cast< ::google::protobuf::uint8>(10u /* 10 & 0xFF */)) { 241 | DO_(::google::protobuf::internal::WireFormatLite::ReadString( 242 | input, this->mutable_str())); 243 | DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( 244 | this->str().data(), static_cast(this->str().length()), 245 | ::google::protobuf::internal::WireFormatLite::PARSE, 246 | "echo_message.str")); 247 | } else { 248 | goto handle_unusual; 249 | } 250 | break; 251 | } 252 | 253 | // int32 num = 2; 254 | case 2: { 255 | if (static_cast< ::google::protobuf::uint8>(tag) == 256 | static_cast< ::google::protobuf::uint8>(16u /* 16 & 0xFF */)) { 257 | 258 | DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< 259 | ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( 260 | input, &num_))); 261 | } else { 262 | goto handle_unusual; 263 | } 264 | break; 265 | } 266 | 267 | default: { 268 | handle_unusual: 269 | if (tag == 0) { 270 | goto success; 271 | } 272 | DO_(::google::protobuf::internal::WireFormat::SkipField( 273 | input, tag, _internal_metadata_.mutable_unknown_fields())); 274 | break; 275 | } 276 | } 277 | } 278 | success: 279 | // @@protoc_insertion_point(parse_success:echo_message) 280 | return true; 281 | failure: 282 | // @@protoc_insertion_point(parse_failure:echo_message) 283 | return false; 284 | #undef DO_ 285 | } 286 | 287 | void echo_message::SerializeWithCachedSizes( 288 | ::google::protobuf::io::CodedOutputStream* output) const { 289 | // @@protoc_insertion_point(serialize_start:echo_message) 290 | ::google::protobuf::uint32 cached_has_bits = 0; 291 | (void) cached_has_bits; 292 | 293 | // string str = 1; 294 | if (this->str().size() > 0) { 295 | ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( 296 | this->str().data(), static_cast(this->str().length()), 297 | ::google::protobuf::internal::WireFormatLite::SERIALIZE, 298 | "echo_message.str"); 299 | ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 300 | 1, this->str(), output); 301 | } 302 | 303 | // int32 num = 2; 304 | if (this->num() != 0) { 305 | ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->num(), output); 306 | } 307 | 308 | if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) { 309 | ::google::protobuf::internal::WireFormat::SerializeUnknownFields( 310 | (::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), output); 311 | } 312 | // @@protoc_insertion_point(serialize_end:echo_message) 313 | } 314 | 315 | ::google::protobuf::uint8* echo_message::InternalSerializeWithCachedSizesToArray( 316 | bool deterministic, ::google::protobuf::uint8* target) const { 317 | (void)deterministic; // Unused 318 | // @@protoc_insertion_point(serialize_to_array_start:echo_message) 319 | ::google::protobuf::uint32 cached_has_bits = 0; 320 | (void) cached_has_bits; 321 | 322 | // string str = 1; 323 | if (this->str().size() > 0) { 324 | ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( 325 | this->str().data(), static_cast(this->str().length()), 326 | ::google::protobuf::internal::WireFormatLite::SERIALIZE, 327 | "echo_message.str"); 328 | target = 329 | ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 330 | 1, this->str(), target); 331 | } 332 | 333 | // int32 num = 2; 334 | if (this->num() != 0) { 335 | target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->num(), target); 336 | } 337 | 338 | if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) { 339 | target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( 340 | (::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), target); 341 | } 342 | // @@protoc_insertion_point(serialize_to_array_end:echo_message) 343 | return target; 344 | } 345 | 346 | size_t echo_message::ByteSizeLong() const { 347 | // @@protoc_insertion_point(message_byte_size_start:echo_message) 348 | size_t total_size = 0; 349 | 350 | if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) { 351 | total_size += 352 | ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( 353 | (::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance())); 354 | } 355 | // string str = 1; 356 | if (this->str().size() > 0) { 357 | total_size += 1 + 358 | ::google::protobuf::internal::WireFormatLite::StringSize( 359 | this->str()); 360 | } 361 | 362 | // int32 num = 2; 363 | if (this->num() != 0) { 364 | total_size += 1 + 365 | ::google::protobuf::internal::WireFormatLite::Int32Size( 366 | this->num()); 367 | } 368 | 369 | int cached_size = ::google::protobuf::internal::ToCachedSize(total_size); 370 | GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); 371 | _cached_size_ = cached_size; 372 | GOOGLE_SAFE_CONCURRENT_WRITES_END(); 373 | return total_size; 374 | } 375 | 376 | void echo_message::MergeFrom(const ::google::protobuf::Message& from) { 377 | // @@protoc_insertion_point(generalized_merge_from_start:echo_message) 378 | GOOGLE_DCHECK_NE(&from, this); 379 | const echo_message* source = 380 | ::google::protobuf::internal::DynamicCastToGenerated( 381 | &from); 382 | if (source == NULL) { 383 | // @@protoc_insertion_point(generalized_merge_from_cast_fail:echo_message) 384 | ::google::protobuf::internal::ReflectionOps::Merge(from, this); 385 | } else { 386 | // @@protoc_insertion_point(generalized_merge_from_cast_success:echo_message) 387 | MergeFrom(*source); 388 | } 389 | } 390 | 391 | void echo_message::MergeFrom(const echo_message& from) { 392 | // @@protoc_insertion_point(class_specific_merge_from_start:echo_message) 393 | GOOGLE_DCHECK_NE(&from, this); 394 | _internal_metadata_.MergeFrom(from._internal_metadata_); 395 | ::google::protobuf::uint32 cached_has_bits = 0; 396 | (void) cached_has_bits; 397 | 398 | if (from.str().size() > 0) { 399 | 400 | str_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.str_); 401 | } 402 | if (from.num() != 0) { 403 | set_num(from.num()); 404 | } 405 | } 406 | 407 | void echo_message::CopyFrom(const ::google::protobuf::Message& from) { 408 | // @@protoc_insertion_point(generalized_copy_from_start:echo_message) 409 | if (&from == this) return; 410 | Clear(); 411 | MergeFrom(from); 412 | } 413 | 414 | void echo_message::CopyFrom(const echo_message& from) { 415 | // @@protoc_insertion_point(class_specific_copy_from_start:echo_message) 416 | if (&from == this) return; 417 | Clear(); 418 | MergeFrom(from); 419 | } 420 | 421 | bool echo_message::IsInitialized() const { 422 | return true; 423 | } 424 | 425 | void echo_message::Swap(echo_message* other) { 426 | if (other == this) return; 427 | InternalSwap(other); 428 | } 429 | void echo_message::InternalSwap(echo_message* other) { 430 | using std::swap; 431 | str_.Swap(&other->str_); 432 | swap(num_, other->num_); 433 | _internal_metadata_.Swap(&other->_internal_metadata_); 434 | swap(_cached_size_, other->_cached_size_); 435 | } 436 | 437 | ::google::protobuf::Metadata echo_message::GetMetadata() const { 438 | protobuf_common_2eproto::protobuf_AssignDescriptorsOnce(); 439 | return ::protobuf_common_2eproto::file_level_metadata[kIndexInFileMessages]; 440 | } 441 | 442 | 443 | // =================================================================== 444 | 445 | void auto_weather_message::InitAsDefaultInstance() { 446 | } 447 | #if !defined(_MSC_VER) || _MSC_VER >= 1900 448 | const int auto_weather_message::kCityNameFieldNumber; 449 | const int auto_weather_message::kWeatherFieldNumber; 450 | #endif // !defined(_MSC_VER) || _MSC_VER >= 1900 451 | 452 | auto_weather_message::auto_weather_message() 453 | : ::google::protobuf::Message(), _internal_metadata_(NULL) { 454 | if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) { 455 | ::protobuf_common_2eproto::InitDefaultsauto_weather_message(); 456 | } 457 | SharedCtor(); 458 | // @@protoc_insertion_point(constructor:auto_weather_message) 459 | } 460 | auto_weather_message::auto_weather_message(const auto_weather_message& from) 461 | : ::google::protobuf::Message(), 462 | _internal_metadata_(NULL), 463 | _cached_size_(0) { 464 | _internal_metadata_.MergeFrom(from._internal_metadata_); 465 | city_name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 466 | if (from.city_name().size() > 0) { 467 | city_name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.city_name_); 468 | } 469 | weather_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 470 | if (from.weather().size() > 0) { 471 | weather_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.weather_); 472 | } 473 | // @@protoc_insertion_point(copy_constructor:auto_weather_message) 474 | } 475 | 476 | void auto_weather_message::SharedCtor() { 477 | city_name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 478 | weather_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 479 | _cached_size_ = 0; 480 | } 481 | 482 | auto_weather_message::~auto_weather_message() { 483 | // @@protoc_insertion_point(destructor:auto_weather_message) 484 | SharedDtor(); 485 | } 486 | 487 | void auto_weather_message::SharedDtor() { 488 | city_name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 489 | weather_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 490 | } 491 | 492 | void auto_weather_message::SetCachedSize(int size) const { 493 | GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); 494 | _cached_size_ = size; 495 | GOOGLE_SAFE_CONCURRENT_WRITES_END(); 496 | } 497 | const ::google::protobuf::Descriptor* auto_weather_message::descriptor() { 498 | ::protobuf_common_2eproto::protobuf_AssignDescriptorsOnce(); 499 | return ::protobuf_common_2eproto::file_level_metadata[kIndexInFileMessages].descriptor; 500 | } 501 | 502 | const auto_weather_message& auto_weather_message::default_instance() { 503 | ::protobuf_common_2eproto::InitDefaultsauto_weather_message(); 504 | return *internal_default_instance(); 505 | } 506 | 507 | auto_weather_message* auto_weather_message::New(::google::protobuf::Arena* arena) const { 508 | auto_weather_message* n = new auto_weather_message; 509 | if (arena != NULL) { 510 | arena->Own(n); 511 | } 512 | return n; 513 | } 514 | 515 | void auto_weather_message::Clear() { 516 | // @@protoc_insertion_point(message_clear_start:auto_weather_message) 517 | ::google::protobuf::uint32 cached_has_bits = 0; 518 | // Prevent compiler warnings about cached_has_bits being unused 519 | (void) cached_has_bits; 520 | 521 | city_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 522 | weather_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 523 | _internal_metadata_.Clear(); 524 | } 525 | 526 | bool auto_weather_message::MergePartialFromCodedStream( 527 | ::google::protobuf::io::CodedInputStream* input) { 528 | #define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure 529 | ::google::protobuf::uint32 tag; 530 | // @@protoc_insertion_point(parse_start:auto_weather_message) 531 | for (;;) { 532 | ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u); 533 | tag = p.first; 534 | if (!p.second) goto handle_unusual; 535 | switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { 536 | // string city_name = 1; 537 | case 1: { 538 | if (static_cast< ::google::protobuf::uint8>(tag) == 539 | static_cast< ::google::protobuf::uint8>(10u /* 10 & 0xFF */)) { 540 | DO_(::google::protobuf::internal::WireFormatLite::ReadString( 541 | input, this->mutable_city_name())); 542 | DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( 543 | this->city_name().data(), static_cast(this->city_name().length()), 544 | ::google::protobuf::internal::WireFormatLite::PARSE, 545 | "auto_weather_message.city_name")); 546 | } else { 547 | goto handle_unusual; 548 | } 549 | break; 550 | } 551 | 552 | // string weather = 2; 553 | case 2: { 554 | if (static_cast< ::google::protobuf::uint8>(tag) == 555 | static_cast< ::google::protobuf::uint8>(18u /* 18 & 0xFF */)) { 556 | DO_(::google::protobuf::internal::WireFormatLite::ReadString( 557 | input, this->mutable_weather())); 558 | DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( 559 | this->weather().data(), static_cast(this->weather().length()), 560 | ::google::protobuf::internal::WireFormatLite::PARSE, 561 | "auto_weather_message.weather")); 562 | } else { 563 | goto handle_unusual; 564 | } 565 | break; 566 | } 567 | 568 | default: { 569 | handle_unusual: 570 | if (tag == 0) { 571 | goto success; 572 | } 573 | DO_(::google::protobuf::internal::WireFormat::SkipField( 574 | input, tag, _internal_metadata_.mutable_unknown_fields())); 575 | break; 576 | } 577 | } 578 | } 579 | success: 580 | // @@protoc_insertion_point(parse_success:auto_weather_message) 581 | return true; 582 | failure: 583 | // @@protoc_insertion_point(parse_failure:auto_weather_message) 584 | return false; 585 | #undef DO_ 586 | } 587 | 588 | void auto_weather_message::SerializeWithCachedSizes( 589 | ::google::protobuf::io::CodedOutputStream* output) const { 590 | // @@protoc_insertion_point(serialize_start:auto_weather_message) 591 | ::google::protobuf::uint32 cached_has_bits = 0; 592 | (void) cached_has_bits; 593 | 594 | // string city_name = 1; 595 | if (this->city_name().size() > 0) { 596 | ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( 597 | this->city_name().data(), static_cast(this->city_name().length()), 598 | ::google::protobuf::internal::WireFormatLite::SERIALIZE, 599 | "auto_weather_message.city_name"); 600 | ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 601 | 1, this->city_name(), output); 602 | } 603 | 604 | // string weather = 2; 605 | if (this->weather().size() > 0) { 606 | ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( 607 | this->weather().data(), static_cast(this->weather().length()), 608 | ::google::protobuf::internal::WireFormatLite::SERIALIZE, 609 | "auto_weather_message.weather"); 610 | ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( 611 | 2, this->weather(), output); 612 | } 613 | 614 | if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) { 615 | ::google::protobuf::internal::WireFormat::SerializeUnknownFields( 616 | (::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), output); 617 | } 618 | // @@protoc_insertion_point(serialize_end:auto_weather_message) 619 | } 620 | 621 | ::google::protobuf::uint8* auto_weather_message::InternalSerializeWithCachedSizesToArray( 622 | bool deterministic, ::google::protobuf::uint8* target) const { 623 | (void)deterministic; // Unused 624 | // @@protoc_insertion_point(serialize_to_array_start:auto_weather_message) 625 | ::google::protobuf::uint32 cached_has_bits = 0; 626 | (void) cached_has_bits; 627 | 628 | // string city_name = 1; 629 | if (this->city_name().size() > 0) { 630 | ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( 631 | this->city_name().data(), static_cast(this->city_name().length()), 632 | ::google::protobuf::internal::WireFormatLite::SERIALIZE, 633 | "auto_weather_message.city_name"); 634 | target = 635 | ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 636 | 1, this->city_name(), target); 637 | } 638 | 639 | // string weather = 2; 640 | if (this->weather().size() > 0) { 641 | ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( 642 | this->weather().data(), static_cast(this->weather().length()), 643 | ::google::protobuf::internal::WireFormatLite::SERIALIZE, 644 | "auto_weather_message.weather"); 645 | target = 646 | ::google::protobuf::internal::WireFormatLite::WriteStringToArray( 647 | 2, this->weather(), target); 648 | } 649 | 650 | if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) { 651 | target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( 652 | (::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance()), target); 653 | } 654 | // @@protoc_insertion_point(serialize_to_array_end:auto_weather_message) 655 | return target; 656 | } 657 | 658 | size_t auto_weather_message::ByteSizeLong() const { 659 | // @@protoc_insertion_point(message_byte_size_start:auto_weather_message) 660 | size_t total_size = 0; 661 | 662 | if ((_internal_metadata_.have_unknown_fields() && ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) { 663 | total_size += 664 | ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( 665 | (::google::protobuf::internal::GetProto3PreserveUnknownsDefault() ? _internal_metadata_.unknown_fields() : _internal_metadata_.default_instance())); 666 | } 667 | // string city_name = 1; 668 | if (this->city_name().size() > 0) { 669 | total_size += 1 + 670 | ::google::protobuf::internal::WireFormatLite::StringSize( 671 | this->city_name()); 672 | } 673 | 674 | // string weather = 2; 675 | if (this->weather().size() > 0) { 676 | total_size += 1 + 677 | ::google::protobuf::internal::WireFormatLite::StringSize( 678 | this->weather()); 679 | } 680 | 681 | int cached_size = ::google::protobuf::internal::ToCachedSize(total_size); 682 | GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); 683 | _cached_size_ = cached_size; 684 | GOOGLE_SAFE_CONCURRENT_WRITES_END(); 685 | return total_size; 686 | } 687 | 688 | void auto_weather_message::MergeFrom(const ::google::protobuf::Message& from) { 689 | // @@protoc_insertion_point(generalized_merge_from_start:auto_weather_message) 690 | GOOGLE_DCHECK_NE(&from, this); 691 | const auto_weather_message* source = 692 | ::google::protobuf::internal::DynamicCastToGenerated( 693 | &from); 694 | if (source == NULL) { 695 | // @@protoc_insertion_point(generalized_merge_from_cast_fail:auto_weather_message) 696 | ::google::protobuf::internal::ReflectionOps::Merge(from, this); 697 | } else { 698 | // @@protoc_insertion_point(generalized_merge_from_cast_success:auto_weather_message) 699 | MergeFrom(*source); 700 | } 701 | } 702 | 703 | void auto_weather_message::MergeFrom(const auto_weather_message& from) { 704 | // @@protoc_insertion_point(class_specific_merge_from_start:auto_weather_message) 705 | GOOGLE_DCHECK_NE(&from, this); 706 | _internal_metadata_.MergeFrom(from._internal_metadata_); 707 | ::google::protobuf::uint32 cached_has_bits = 0; 708 | (void) cached_has_bits; 709 | 710 | if (from.city_name().size() > 0) { 711 | 712 | city_name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.city_name_); 713 | } 714 | if (from.weather().size() > 0) { 715 | 716 | weather_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.weather_); 717 | } 718 | } 719 | 720 | void auto_weather_message::CopyFrom(const ::google::protobuf::Message& from) { 721 | // @@protoc_insertion_point(generalized_copy_from_start:auto_weather_message) 722 | if (&from == this) return; 723 | Clear(); 724 | MergeFrom(from); 725 | } 726 | 727 | void auto_weather_message::CopyFrom(const auto_weather_message& from) { 728 | // @@protoc_insertion_point(class_specific_copy_from_start:auto_weather_message) 729 | if (&from == this) return; 730 | Clear(); 731 | MergeFrom(from); 732 | } 733 | 734 | bool auto_weather_message::IsInitialized() const { 735 | return true; 736 | } 737 | 738 | void auto_weather_message::Swap(auto_weather_message* other) { 739 | if (other == this) return; 740 | InternalSwap(other); 741 | } 742 | void auto_weather_message::InternalSwap(auto_weather_message* other) { 743 | using std::swap; 744 | city_name_.Swap(&other->city_name_); 745 | weather_.Swap(&other->weather_); 746 | _internal_metadata_.Swap(&other->_internal_metadata_); 747 | swap(_cached_size_, other->_cached_size_); 748 | } 749 | 750 | ::google::protobuf::Metadata auto_weather_message::GetMetadata() const { 751 | protobuf_common_2eproto::protobuf_AssignDescriptorsOnce(); 752 | return ::protobuf_common_2eproto::file_level_metadata[kIndexInFileMessages]; 753 | } 754 | 755 | 756 | // @@protoc_insertion_point(namespace_scope) 757 | 758 | // @@protoc_insertion_point(global_scope) 759 | -------------------------------------------------------------------------------- /test/protoc/code/common.pb.h: -------------------------------------------------------------------------------- 1 | // Generated by the protocol buffer compiler. DO NOT EDIT! 2 | // source: common.proto 3 | 4 | #ifndef PROTOBUF_common_2eproto__INCLUDED 5 | #define PROTOBUF_common_2eproto__INCLUDED 6 | 7 | #include 8 | 9 | #include 10 | 11 | #if GOOGLE_PROTOBUF_VERSION < 3004000 12 | #error This file was generated by a newer version of protoc which is 13 | #error incompatible with your Protocol Buffer headers. Please update 14 | #error your headers. 15 | #endif 16 | #if 3004000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 17 | #error This file was generated by an older version of protoc which is 18 | #error incompatible with your Protocol Buffer headers. Please 19 | #error regenerate this file with a newer version of protoc. 20 | #endif 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include // IWYU pragma: export 30 | #include // IWYU pragma: export 31 | #include 32 | // @@protoc_insertion_point(includes) 33 | 34 | namespace protobuf_common_2eproto { 35 | // Internal implementation detail -- do not use these members. 36 | struct TableStruct { 37 | static const ::google::protobuf::internal::ParseTableField entries[]; 38 | static const ::google::protobuf::internal::AuxillaryParseTableField aux[]; 39 | static const ::google::protobuf::internal::ParseTable schema[2]; 40 | static const ::google::protobuf::internal::FieldMetadata field_metadata[]; 41 | static const ::google::protobuf::internal::SerializationTable serialization_table[]; 42 | static const ::google::protobuf::uint32 offsets[]; 43 | }; 44 | void AddDescriptors(); 45 | void InitDefaultsecho_messageImpl(); 46 | void InitDefaultsecho_message(); 47 | void InitDefaultsauto_weather_messageImpl(); 48 | void InitDefaultsauto_weather_message(); 49 | inline void InitDefaults() { 50 | InitDefaultsecho_message(); 51 | InitDefaultsauto_weather_message(); 52 | } 53 | } // namespace protobuf_common_2eproto 54 | class auto_weather_message; 55 | class auto_weather_messageDefaultTypeInternal; 56 | extern auto_weather_messageDefaultTypeInternal _auto_weather_message_default_instance_; 57 | class echo_message; 58 | class echo_messageDefaultTypeInternal; 59 | extern echo_messageDefaultTypeInternal _echo_message_default_instance_; 60 | 61 | // =================================================================== 62 | 63 | class echo_message : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:echo_message) */ { 64 | public: 65 | echo_message(); 66 | virtual ~echo_message(); 67 | 68 | echo_message(const echo_message& from); 69 | 70 | inline echo_message& operator=(const echo_message& from) { 71 | CopyFrom(from); 72 | return *this; 73 | } 74 | #if LANG_CXX11 75 | echo_message(echo_message&& from) noexcept 76 | : echo_message() { 77 | *this = ::std::move(from); 78 | } 79 | 80 | inline echo_message& operator=(echo_message&& from) noexcept { 81 | if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) { 82 | if (this != &from) InternalSwap(&from); 83 | } else { 84 | CopyFrom(from); 85 | } 86 | return *this; 87 | } 88 | #endif 89 | static const ::google::protobuf::Descriptor* descriptor(); 90 | static const echo_message& default_instance(); 91 | 92 | static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY 93 | static inline const echo_message* internal_default_instance() { 94 | return reinterpret_cast( 95 | &_echo_message_default_instance_); 96 | } 97 | static PROTOBUF_CONSTEXPR int const kIndexInFileMessages = 98 | 0; 99 | 100 | void Swap(echo_message* other); 101 | friend void swap(echo_message& a, echo_message& b) { 102 | a.Swap(&b); 103 | } 104 | 105 | // implements Message ---------------------------------------------- 106 | 107 | inline echo_message* New() const PROTOBUF_FINAL { return New(NULL); } 108 | 109 | echo_message* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL; 110 | void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL; 111 | void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL; 112 | void CopyFrom(const echo_message& from); 113 | void MergeFrom(const echo_message& from); 114 | void Clear() PROTOBUF_FINAL; 115 | bool IsInitialized() const PROTOBUF_FINAL; 116 | 117 | size_t ByteSizeLong() const PROTOBUF_FINAL; 118 | bool MergePartialFromCodedStream( 119 | ::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL; 120 | void SerializeWithCachedSizes( 121 | ::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL; 122 | ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( 123 | bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL; 124 | int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; } 125 | private: 126 | void SharedCtor(); 127 | void SharedDtor(); 128 | void SetCachedSize(int size) const PROTOBUF_FINAL; 129 | void InternalSwap(echo_message* other); 130 | private: 131 | inline ::google::protobuf::Arena* GetArenaNoVirtual() const { 132 | return NULL; 133 | } 134 | inline void* MaybeArenaPtr() const { 135 | return NULL; 136 | } 137 | public: 138 | 139 | ::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL; 140 | 141 | // nested types ---------------------------------------------------- 142 | 143 | // accessors ------------------------------------------------------- 144 | 145 | // string str = 1; 146 | void clear_str(); 147 | static const int kStrFieldNumber = 1; 148 | const ::std::string& str() const; 149 | void set_str(const ::std::string& value); 150 | #if LANG_CXX11 151 | void set_str(::std::string&& value); 152 | #endif 153 | void set_str(const char* value); 154 | void set_str(const char* value, size_t size); 155 | ::std::string* mutable_str(); 156 | ::std::string* release_str(); 157 | void set_allocated_str(::std::string* str); 158 | 159 | // int32 num = 2; 160 | void clear_num(); 161 | static const int kNumFieldNumber = 2; 162 | ::google::protobuf::int32 num() const; 163 | void set_num(::google::protobuf::int32 value); 164 | 165 | // @@protoc_insertion_point(class_scope:echo_message) 166 | private: 167 | 168 | ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; 169 | ::google::protobuf::internal::ArenaStringPtr str_; 170 | ::google::protobuf::int32 num_; 171 | mutable int _cached_size_; 172 | friend struct ::protobuf_common_2eproto::TableStruct; 173 | friend void ::protobuf_common_2eproto::InitDefaultsecho_messageImpl(); 174 | }; 175 | // ------------------------------------------------------------------- 176 | 177 | class auto_weather_message : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:auto_weather_message) */ { 178 | public: 179 | auto_weather_message(); 180 | virtual ~auto_weather_message(); 181 | 182 | auto_weather_message(const auto_weather_message& from); 183 | 184 | inline auto_weather_message& operator=(const auto_weather_message& from) { 185 | CopyFrom(from); 186 | return *this; 187 | } 188 | #if LANG_CXX11 189 | auto_weather_message(auto_weather_message&& from) noexcept 190 | : auto_weather_message() { 191 | *this = ::std::move(from); 192 | } 193 | 194 | inline auto_weather_message& operator=(auto_weather_message&& from) noexcept { 195 | if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) { 196 | if (this != &from) InternalSwap(&from); 197 | } else { 198 | CopyFrom(from); 199 | } 200 | return *this; 201 | } 202 | #endif 203 | static const ::google::protobuf::Descriptor* descriptor(); 204 | static const auto_weather_message& default_instance(); 205 | 206 | static void InitAsDefaultInstance(); // FOR INTERNAL USE ONLY 207 | static inline const auto_weather_message* internal_default_instance() { 208 | return reinterpret_cast( 209 | &_auto_weather_message_default_instance_); 210 | } 211 | static PROTOBUF_CONSTEXPR int const kIndexInFileMessages = 212 | 1; 213 | 214 | void Swap(auto_weather_message* other); 215 | friend void swap(auto_weather_message& a, auto_weather_message& b) { 216 | a.Swap(&b); 217 | } 218 | 219 | // implements Message ---------------------------------------------- 220 | 221 | inline auto_weather_message* New() const PROTOBUF_FINAL { return New(NULL); } 222 | 223 | auto_weather_message* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL; 224 | void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL; 225 | void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL; 226 | void CopyFrom(const auto_weather_message& from); 227 | void MergeFrom(const auto_weather_message& from); 228 | void Clear() PROTOBUF_FINAL; 229 | bool IsInitialized() const PROTOBUF_FINAL; 230 | 231 | size_t ByteSizeLong() const PROTOBUF_FINAL; 232 | bool MergePartialFromCodedStream( 233 | ::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL; 234 | void SerializeWithCachedSizes( 235 | ::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL; 236 | ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( 237 | bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL; 238 | int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; } 239 | private: 240 | void SharedCtor(); 241 | void SharedDtor(); 242 | void SetCachedSize(int size) const PROTOBUF_FINAL; 243 | void InternalSwap(auto_weather_message* other); 244 | private: 245 | inline ::google::protobuf::Arena* GetArenaNoVirtual() const { 246 | return NULL; 247 | } 248 | inline void* MaybeArenaPtr() const { 249 | return NULL; 250 | } 251 | public: 252 | 253 | ::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL; 254 | 255 | // nested types ---------------------------------------------------- 256 | 257 | // accessors ------------------------------------------------------- 258 | 259 | // string city_name = 1; 260 | void clear_city_name(); 261 | static const int kCityNameFieldNumber = 1; 262 | const ::std::string& city_name() const; 263 | void set_city_name(const ::std::string& value); 264 | #if LANG_CXX11 265 | void set_city_name(::std::string&& value); 266 | #endif 267 | void set_city_name(const char* value); 268 | void set_city_name(const char* value, size_t size); 269 | ::std::string* mutable_city_name(); 270 | ::std::string* release_city_name(); 271 | void set_allocated_city_name(::std::string* city_name); 272 | 273 | // string weather = 2; 274 | void clear_weather(); 275 | static const int kWeatherFieldNumber = 2; 276 | const ::std::string& weather() const; 277 | void set_weather(const ::std::string& value); 278 | #if LANG_CXX11 279 | void set_weather(::std::string&& value); 280 | #endif 281 | void set_weather(const char* value); 282 | void set_weather(const char* value, size_t size); 283 | ::std::string* mutable_weather(); 284 | ::std::string* release_weather(); 285 | void set_allocated_weather(::std::string* weather); 286 | 287 | // @@protoc_insertion_point(class_scope:auto_weather_message) 288 | private: 289 | 290 | ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; 291 | ::google::protobuf::internal::ArenaStringPtr city_name_; 292 | ::google::protobuf::internal::ArenaStringPtr weather_; 293 | mutable int _cached_size_; 294 | friend struct ::protobuf_common_2eproto::TableStruct; 295 | friend void ::protobuf_common_2eproto::InitDefaultsauto_weather_messageImpl(); 296 | }; 297 | // =================================================================== 298 | 299 | 300 | // =================================================================== 301 | 302 | #ifdef __GNUC__ 303 | #pragma GCC diagnostic push 304 | #pragma GCC diagnostic ignored "-Wstrict-aliasing" 305 | #endif // __GNUC__ 306 | // echo_message 307 | 308 | // string str = 1; 309 | inline void echo_message::clear_str() { 310 | str_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 311 | } 312 | inline const ::std::string& echo_message::str() const { 313 | // @@protoc_insertion_point(field_get:echo_message.str) 314 | return str_.GetNoArena(); 315 | } 316 | inline void echo_message::set_str(const ::std::string& value) { 317 | 318 | str_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); 319 | // @@protoc_insertion_point(field_set:echo_message.str) 320 | } 321 | #if LANG_CXX11 322 | inline void echo_message::set_str(::std::string&& value) { 323 | 324 | str_.SetNoArena( 325 | &::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value)); 326 | // @@protoc_insertion_point(field_set_rvalue:echo_message.str) 327 | } 328 | #endif 329 | inline void echo_message::set_str(const char* value) { 330 | GOOGLE_DCHECK(value != NULL); 331 | 332 | str_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); 333 | // @@protoc_insertion_point(field_set_char:echo_message.str) 334 | } 335 | inline void echo_message::set_str(const char* value, size_t size) { 336 | 337 | str_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), 338 | ::std::string(reinterpret_cast(value), size)); 339 | // @@protoc_insertion_point(field_set_pointer:echo_message.str) 340 | } 341 | inline ::std::string* echo_message::mutable_str() { 342 | 343 | // @@protoc_insertion_point(field_mutable:echo_message.str) 344 | return str_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 345 | } 346 | inline ::std::string* echo_message::release_str() { 347 | // @@protoc_insertion_point(field_release:echo_message.str) 348 | 349 | return str_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 350 | } 351 | inline void echo_message::set_allocated_str(::std::string* str) { 352 | if (str != NULL) { 353 | 354 | } else { 355 | 356 | } 357 | str_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), str); 358 | // @@protoc_insertion_point(field_set_allocated:echo_message.str) 359 | } 360 | 361 | // int32 num = 2; 362 | inline void echo_message::clear_num() { 363 | num_ = 0; 364 | } 365 | inline ::google::protobuf::int32 echo_message::num() const { 366 | // @@protoc_insertion_point(field_get:echo_message.num) 367 | return num_; 368 | } 369 | inline void echo_message::set_num(::google::protobuf::int32 value) { 370 | 371 | num_ = value; 372 | // @@protoc_insertion_point(field_set:echo_message.num) 373 | } 374 | 375 | // ------------------------------------------------------------------- 376 | 377 | // auto_weather_message 378 | 379 | // string city_name = 1; 380 | inline void auto_weather_message::clear_city_name() { 381 | city_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 382 | } 383 | inline const ::std::string& auto_weather_message::city_name() const { 384 | // @@protoc_insertion_point(field_get:auto_weather_message.city_name) 385 | return city_name_.GetNoArena(); 386 | } 387 | inline void auto_weather_message::set_city_name(const ::std::string& value) { 388 | 389 | city_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); 390 | // @@protoc_insertion_point(field_set:auto_weather_message.city_name) 391 | } 392 | #if LANG_CXX11 393 | inline void auto_weather_message::set_city_name(::std::string&& value) { 394 | 395 | city_name_.SetNoArena( 396 | &::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value)); 397 | // @@protoc_insertion_point(field_set_rvalue:auto_weather_message.city_name) 398 | } 399 | #endif 400 | inline void auto_weather_message::set_city_name(const char* value) { 401 | GOOGLE_DCHECK(value != NULL); 402 | 403 | city_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); 404 | // @@protoc_insertion_point(field_set_char:auto_weather_message.city_name) 405 | } 406 | inline void auto_weather_message::set_city_name(const char* value, size_t size) { 407 | 408 | city_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), 409 | ::std::string(reinterpret_cast(value), size)); 410 | // @@protoc_insertion_point(field_set_pointer:auto_weather_message.city_name) 411 | } 412 | inline ::std::string* auto_weather_message::mutable_city_name() { 413 | 414 | // @@protoc_insertion_point(field_mutable:auto_weather_message.city_name) 415 | return city_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 416 | } 417 | inline ::std::string* auto_weather_message::release_city_name() { 418 | // @@protoc_insertion_point(field_release:auto_weather_message.city_name) 419 | 420 | return city_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 421 | } 422 | inline void auto_weather_message::set_allocated_city_name(::std::string* city_name) { 423 | if (city_name != NULL) { 424 | 425 | } else { 426 | 427 | } 428 | city_name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), city_name); 429 | // @@protoc_insertion_point(field_set_allocated:auto_weather_message.city_name) 430 | } 431 | 432 | // string weather = 2; 433 | inline void auto_weather_message::clear_weather() { 434 | weather_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 435 | } 436 | inline const ::std::string& auto_weather_message::weather() const { 437 | // @@protoc_insertion_point(field_get:auto_weather_message.weather) 438 | return weather_.GetNoArena(); 439 | } 440 | inline void auto_weather_message::set_weather(const ::std::string& value) { 441 | 442 | weather_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); 443 | // @@protoc_insertion_point(field_set:auto_weather_message.weather) 444 | } 445 | #if LANG_CXX11 446 | inline void auto_weather_message::set_weather(::std::string&& value) { 447 | 448 | weather_.SetNoArena( 449 | &::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::move(value)); 450 | // @@protoc_insertion_point(field_set_rvalue:auto_weather_message.weather) 451 | } 452 | #endif 453 | inline void auto_weather_message::set_weather(const char* value) { 454 | GOOGLE_DCHECK(value != NULL); 455 | 456 | weather_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); 457 | // @@protoc_insertion_point(field_set_char:auto_weather_message.weather) 458 | } 459 | inline void auto_weather_message::set_weather(const char* value, size_t size) { 460 | 461 | weather_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), 462 | ::std::string(reinterpret_cast(value), size)); 463 | // @@protoc_insertion_point(field_set_pointer:auto_weather_message.weather) 464 | } 465 | inline ::std::string* auto_weather_message::mutable_weather() { 466 | 467 | // @@protoc_insertion_point(field_mutable:auto_weather_message.weather) 468 | return weather_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 469 | } 470 | inline ::std::string* auto_weather_message::release_weather() { 471 | // @@protoc_insertion_point(field_release:auto_weather_message.weather) 472 | 473 | return weather_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); 474 | } 475 | inline void auto_weather_message::set_allocated_weather(::std::string* weather) { 476 | if (weather != NULL) { 477 | 478 | } else { 479 | 480 | } 481 | weather_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), weather); 482 | // @@protoc_insertion_point(field_set_allocated:auto_weather_message.weather) 483 | } 484 | 485 | #ifdef __GNUC__ 486 | #pragma GCC diagnostic pop 487 | #endif // __GNUC__ 488 | // ------------------------------------------------------------------- 489 | 490 | 491 | // @@protoc_insertion_point(namespace_scope) 492 | 493 | 494 | // @@protoc_insertion_point(global_scope) 495 | 496 | #endif // PROTOBUF_common_2eproto__INCLUDED 497 | -------------------------------------------------------------------------------- /test/protoc/common.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | message echo_message 4 | { 5 | string str = 1; 6 | int32 num = 2; 7 | } 8 | 9 | message auto_weather_message 10 | { 11 | string city_name = 1; 12 | string weather = 2; 13 | } 14 | -------------------------------------------------------------------------------- /test/rpc_client/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | project(rpc_client) 3 | 4 | # 程序名 5 | set(OUT_NAME rpc_client.out) 6 | 7 | # debug或release模式 8 | if(CMAKE_BUILD_TYPE MATCHES "debug") 9 | message("Build debug...") 10 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -g -O0 -std=c++14") 11 | else() 12 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -g -O3 -std=c++14") 13 | endif() 14 | 15 | # 遍历主目录源文件,删除cmake自动生成的main源文件 16 | file(GLOB_RECURSE SOURCE_FILES "*.cpp" "../protoc/code/*.cc" "../../easyrpc/*.cpp") 17 | file(GLOB_RECURSE DEBUG_REMOVE_FILE "debug/*") 18 | file(GLOB_RECURSE RELEASE_REMOVE_FILE "release/*") 19 | list(REMOVE_ITEM SOURCE_FILES ${DEBUG_REMOVE_FILE} ${RELEASE_REMOVE_FILE}) 20 | 21 | # 依赖包含 22 | include_directories(../../) 23 | include_directories(../proto/code) 24 | include_directories(/usr/local/3rdparty/include) 25 | 26 | # 链接依赖 27 | link_directories(/usr/local/3rdparty/lib) 28 | 29 | # 可执行程序 30 | add_executable(${OUT_NAME} ${SOURCE_FILES}) 31 | 32 | # 连接库 33 | set(LINK_LIST libboost_system.a libprotobuf.a pthread) 34 | target_link_libraries(${OUT_NAME} ${LINK_LIST}) 35 | -------------------------------------------------------------------------------- /test/rpc_client/main.cpp: -------------------------------------------------------------------------------- 1 | #include "rpc_client_test.h" 2 | 3 | int main() 4 | { 5 | rpc_client_test test; 6 | test.run(); 7 | 8 | std::cin.get(); 9 | test.stop(); 10 | 11 | return 0; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /test/rpc_client/rpc_client_test.cpp: -------------------------------------------------------------------------------- 1 | #include "rpc_client_test.h" 2 | 3 | using namespace std::placeholders; 4 | 5 | rpc_client_test::rpc_client_test() 6 | { 7 | client_ = std::make_shared("127.0.0.1:8888", 3); 8 | client_->set_connection_notify(std::bind(&rpc_client_test::deal_connection_notify, this, _1, _2)); 9 | client_->bind(std::bind(&rpc_client_test::deal_sub_message, this, _1)); 10 | } 11 | 12 | rpc_client_test::~rpc_client_test() 13 | { 14 | stop(); 15 | } 16 | 17 | void rpc_client_test::run() 18 | { 19 | bool ok = client_->run(); 20 | if (!ok) 21 | { 22 | log_error << "Connect server failed"; 23 | return; 24 | } 25 | 26 | call(); 27 | } 28 | 29 | void rpc_client_test::stop() 30 | { 31 | client_->stop(); 32 | } 33 | 34 | void rpc_client_test::deal_connection_notify(bool created, const std::string& session_id) 35 | { 36 | if (created) 37 | { 38 | log_info << "Connection created: " << session_id; 39 | } 40 | else 41 | { 42 | log_warn << "Connection closed: " << session_id; 43 | } 44 | } 45 | 46 | void rpc_client_test::deal_sub_message(const std::shared_ptr& ret) 47 | { 48 | log_info << ret->message->DebugString(); 49 | } 50 | 51 | void rpc_client_test::call() 52 | { 53 | client_->call(make_echo_message(), [](const std::shared_ptr& ret) 54 | { 55 | log_info << ret->message->DebugString(); 56 | }); 57 | } 58 | 59 | std::shared_ptr rpc_client_test::make_echo_message() 60 | { 61 | auto message = std::make_shared(); 62 | message->set_str("Hello world"); 63 | message->set_num(1024); 64 | 65 | return message; 66 | } 67 | -------------------------------------------------------------------------------- /test/rpc_client/rpc_client_test.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file rpc_client_test.h 3 | * @brief rpc客户端测试程序 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-12-02 7 | */ 8 | #pragma once 9 | 10 | #include "../protoc/code/common.pb.h" 11 | #include "easyrpc/easyrpc.h" 12 | 13 | using namespace easyrpc; 14 | 15 | class rpc_client_test 16 | { 17 | public: 18 | rpc_client_test(); 19 | ~rpc_client_test(); 20 | 21 | void run(); 22 | void stop(); 23 | 24 | private: 25 | void deal_connection_notify(bool created, const std::string& session_id); 26 | void deal_sub_message(const std::shared_ptr& ret); 27 | void call(); 28 | std::shared_ptr make_echo_message(); 29 | 30 | private: 31 | std::shared_ptr client_; 32 | }; 33 | -------------------------------------------------------------------------------- /test/rpc_server/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | project(rpc_server) 3 | 4 | # 程序名 5 | set(OUT_NAME rpc_server.out) 6 | 7 | # debug或release模式 8 | if(CMAKE_BUILD_TYPE MATCHES "debug") 9 | message("Build debug...") 10 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -g -O0 -std=c++14") 11 | else() 12 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -g -O3 -std=c++14") 13 | endif() 14 | 15 | # 遍历主目录源文件,删除cmake自动生成的main源文件 16 | file(GLOB_RECURSE SOURCE_FILES "*.cpp" "../protoc/code/*.cc" "../../easyrpc/*.cpp") 17 | file(GLOB_RECURSE DEBUG_REMOVE_FILE "debug/*") 18 | file(GLOB_RECURSE RELEASE_REMOVE_FILE "release/*") 19 | list(REMOVE_ITEM SOURCE_FILES ${DEBUG_REMOVE_FILE} ${RELEASE_REMOVE_FILE}) 20 | 21 | # 依赖包含 22 | include_directories(../../) 23 | include_directories(../proto/code) 24 | include_directories(/usr/local/3rdparty/include) 25 | 26 | # 链接依赖 27 | link_directories(/usr/local/3rdparty/lib) 28 | 29 | # 可执行程序 30 | add_executable(${OUT_NAME} ${SOURCE_FILES}) 31 | 32 | # 连接库 33 | set(LINK_LIST libboost_system.a libprotobuf.a pthread) 34 | target_link_libraries(${OUT_NAME} ${LINK_LIST}) 35 | -------------------------------------------------------------------------------- /test/rpc_server/main.cpp: -------------------------------------------------------------------------------- 1 | #include "rpc_server_test.h" 2 | #include 3 | 4 | int main() 5 | { 6 | rpc_server_test test; 7 | test.run(); 8 | 9 | std::cin.get(); 10 | test.stop(); 11 | 12 | return 0; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /test/rpc_server/rpc_server_test.cpp: -------------------------------------------------------------------------------- 1 | #include "rpc_server_test.h" 2 | 3 | using namespace std::placeholders; 4 | 5 | rpc_server_test::rpc_server_test() 6 | { 7 | server_ = std::make_shared("0.0.0.0:8888", 4, 4); 8 | server_->set_connection_notify(std::bind(&rpc_server_test::deal_connection_notify, this, _1)); 9 | server_->route(echo_message::descriptor()->full_name(), std::bind(&rpc_server_test::echo, this, _1, _2)); 10 | } 11 | 12 | rpc_server_test::~rpc_server_test() 13 | { 14 | stop(); 15 | } 16 | 17 | void rpc_server_test::run() 18 | { 19 | bool ok = server_->run(); 20 | if (!ok) 21 | { 22 | log_error<< "rpc server start failed"; 23 | return; 24 | } 25 | 26 | pub_thread_ = std::make_shared(std::bind(&rpc_server_test::publish_thread, this)); 27 | 28 | log_info << "rpc server start..."; 29 | } 30 | 31 | void rpc_server_test::stop() 32 | { 33 | server_stoped_ = true; 34 | 35 | if (pub_thread_ && pub_thread_->joinable()) 36 | { 37 | pub_thread_->join(); 38 | } 39 | 40 | server_->stop(); 41 | } 42 | 43 | void rpc_server_test::deal_connection_notify(const connection_status& status) 44 | { 45 | if (status.created) 46 | { 47 | client_session_id_ = status.session_id; 48 | log_info << "Connection created: " << status.session_id; 49 | } 50 | else 51 | { 52 | log_warn << "Connection closed: " << status.session_id; 53 | } 54 | 55 | log_info << "Connection counts: " << status.connection_counts; 56 | } 57 | 58 | void rpc_server_test::echo(const std::shared_ptr& req, const std::shared_ptr& res) 59 | { 60 | log_info << req->message->DebugString(); 61 | res->set_response(req->message); 62 | } 63 | 64 | void rpc_server_test::publish_thread() 65 | { 66 | while (!server_stoped_) 67 | { 68 | std::this_thread::sleep_for(std::chrono::milliseconds(1000)); 69 | if (!client_session_id_.empty()) 70 | { 71 | server_->publish(client_session_id_, make_auto_weather()); 72 | } 73 | } 74 | } 75 | 76 | std::shared_ptr rpc_server_test::make_auto_weather() 77 | { 78 | auto message = std::make_shared(); 79 | message->set_city_name("ChengDu"); 80 | message->set_weather("Sunny"); 81 | 82 | return message; 83 | } 84 | -------------------------------------------------------------------------------- /test/rpc_server/rpc_server_test.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file rpc_server_test.h 3 | * @brief rpc服务端测试程序 4 | * @author chxuan, 787280310@qq.com 5 | * @version 1.0.0 6 | * @date 2017-12-02 7 | */ 8 | #pragma once 9 | 10 | #include 11 | #include "../protoc/code/common.pb.h" 12 | #include "easyrpc/easyrpc.h" 13 | 14 | using namespace easyrpc; 15 | 16 | class rpc_server_test 17 | { 18 | public: 19 | rpc_server_test(); 20 | ~rpc_server_test(); 21 | 22 | void run(); 23 | void stop(); 24 | 25 | private: 26 | void deal_connection_notify(const connection_status& status); 27 | void echo(const std::shared_ptr& req, const std::shared_ptr& res); 28 | void publish_thread(); 29 | std::shared_ptr make_auto_weather(); 30 | 31 | private: 32 | std::shared_ptr server_; 33 | std::shared_ptr pub_thread_; 34 | std::atomic server_stoped_{ false }; 35 | std::string client_session_id_; 36 | }; 37 | --------------------------------------------------------------------------------