├── .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