├── CMakeLists.txt ├── README.md ├── evrpc.config ├── evrpc.creator ├── evrpc.files ├── evrpc.includes ├── evrpc.proto ├── example ├── CMakeLists.txt ├── evclient.cc ├── evrpc.proto ├── evserver.cc ├── tcpclient_test.cc └── tcpserver_test.cc ├── include ├── atomic.h ├── ev_endian.h └── util.h └── rpc ├── CMakeLists.txt ├── codeclite.cc ├── codeclite.h ├── google-inl.h ├── rpc.proto ├── rpcchannel.cc ├── rpcchannel.h ├── rpccodec.cc ├── rpccodec.h ├── rpcserver.cc ├── rpcserver.h ├── tcpclient.cc ├── tcpclient.h ├── tcpserver.cc └── tcpserver.h /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #cmake file for ev server 2 | #author changfa.zheng 3 | 4 | CMAKE_MINIMUM_REQUIRED(VERSION 2.6) 5 | 6 | 7 | #project name 8 | PROJECT(ev_server) 9 | 10 | #execute_process(COMMAND protoc --cpp_out . ${CMAKE_CURRENT_SOURCE_DIR}/rpc.proto -I${CMAKE_CURRENT_SOURCE_DIR}) 11 | 12 | #add_custom_command(OUTPUT evrpc.pb.cc evrpc.pb.h 13 | # COMMAND protoc ARGS --cpp_out . ${CMAKE_CURRENT_SOURCE_DIR}/evrpc.proto -I${CMAKE_CURRENT_SOURCE_DIR} 14 | # DEPENDS evrpc.proto 15 | # VERBATIM ) 16 | #add_custom_target(evserver_proto DEPENDS evrpc.pb.cc evrpc.pb.h) 17 | 18 | 19 | set(CMAKE_CXX_COMPILER "g++") 20 | SET(CMAKE_CXX_FLAGS "-std=c++11") 21 | SET(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -Wall") 22 | set(CMAKE_CXX_FLAGS_RELEASE "-O2 -finline-limit=1000 -DNDEBUG") 23 | SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) 24 | SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) 25 | 26 | #SET(CMAKE_BUILD_TYPE Release) 27 | SET(CMAKE_BUILD_TYPE DEBUG) 28 | 29 | #SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ./bin) 30 | 31 | 32 | 33 | #INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include) 34 | #INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/rpc) 35 | #INCLUDE_DIRECTORIES(${PROJECT_BINARY_DIR}) 36 | #LINK_DIRECTORIES(${LIBRARY_OUTPUT_DIRECTORY}) 37 | 38 | #message(STATUS ${PROJECT_BINARY_DIR}) 39 | #message(STATUS ${PROJECT_SOURCE_DIR}) 40 | 41 | add_subdirectory(rpc) 42 | add_subdirectory(example) 43 | 44 | #获得一个目录下所有源文件(不包括头文件)到变量SRCS 45 | #AUX_SOURCE_DIRECTORY(dirname SRCS) 46 | #AUX_SOURCE_DIRECTORY(./ SOURCE_FILES) 47 | 48 | 49 | #生成静态链接库libname.a 50 | #ADD_LIBRARY(name $SOURCE_FILES) 51 | 52 | 53 | #ADD_EXECUTABLE(ev_server evserver.cc evrpc.pb.cc) 54 | #ADD_EXECUTABLE(ev_client evclient.cc evrpc.pb.cc) 55 | #add_dependencies(ev_server evserver_proto) 56 | #add_dependencies(ev_client evserver_proto) 57 | 58 | #依赖的库文件 59 | #TARGET_LINK_LIBRARIES(ev_server evrpc z protobuf glog pthread event) 60 | #TARGET_LINK_LIBRARIES(ev_client evrpc z protobuf glog pthread event) 61 | 62 | SET(HEADERS 63 | include/atomic.h 64 | include/ev_endian.h 65 | include/util.h 66 | ) 67 | 68 | install(FILES ${HEADERS} DESTINATION ${PROJECT_BINARY_DIR}/include/) 69 | 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # evrpc 2 | -------------------------------------------------------------------------------- /evrpc.config: -------------------------------------------------------------------------------- 1 | // Add predefined macros for your project here. For example: 2 | // #define THE_ANSWER 42 3 | -------------------------------------------------------------------------------- /evrpc.creator: -------------------------------------------------------------------------------- 1 | [General] 2 | -------------------------------------------------------------------------------- /evrpc.files: -------------------------------------------------------------------------------- 1 | CMakeLists.txt 2 | README.md 3 | example/CMakeLists.txt 4 | example/evclient.cc 5 | example/evrpc.proto 6 | example/evserver.cc 7 | example/tcpclient_test.cc 8 | example/tcpserver_test.cc 9 | include/atomic.h 10 | include/ev_endian.h 11 | include/util.h 12 | rpc/CMakeLists.txt 13 | rpc/codeclite.cc 14 | rpc/codeclite.h 15 | rpc/google-inl.h 16 | rpc/rpc.proto 17 | rpc/rpcchannel.cc 18 | rpc/rpcchannel.h 19 | rpc/rpccodec.cc 20 | rpc/rpccodec.h 21 | rpc/rpcserver.cc 22 | rpc/rpcserver.h 23 | rpc/tcpclient.cc 24 | rpc/tcpclient.h 25 | rpc/tcpserver.cc 26 | rpc/tcpserver.h 27 | -------------------------------------------------------------------------------- /evrpc.includes: -------------------------------------------------------------------------------- 1 | include 2 | rpc 3 | -------------------------------------------------------------------------------- /evrpc.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package evrpc; 4 | 5 | option cc_generic_services = true; 6 | 7 | message Rvalue { 8 | bool success = 1; 9 | string errmsg = 2; 10 | } 11 | 12 | //message SiteKey { 13 | // bytes key = 1; 14 | //} 15 | //message SiteVal { 16 | // bytes value = 1; 17 | //} 18 | message Site { 19 | bytes key = 1; 20 | bytes value = 2; 21 | } 22 | 23 | message PutRequest{ 24 | repeated Site sites = 1; 25 | } 26 | message PutResult{ 27 | repeated Rvalue rvals = 1; 28 | // repeated Site sites = 1; 29 | } 30 | message GetRequest{ 31 | repeated bytes keys = 1; 32 | } 33 | message GetResult{ 34 | Rvalue rvals = 1; 35 | repeated Site sites = 2; 36 | } 37 | 38 | 39 | service EkvCmd { 40 | rpc Put (PutRequest) returns (PutResult); 41 | rpc Get (GetRequest) returns (GetResult); 42 | } 43 | 44 | -------------------------------------------------------------------------------- /example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #cmake file for ev server 2 | #author changfa.zheng 3 | 4 | add_custom_command(OUTPUT evrpc.pb.cc evrpc.pb.h 5 | COMMAND protoc ARGS --cpp_out . ${CMAKE_CURRENT_SOURCE_DIR}/evrpc.proto -I${CMAKE_CURRENT_SOURCE_DIR} 6 | DEPENDS evrpc.proto 7 | VERBATIM ) 8 | add_custom_target(evserver_proto DEPENDS evrpc.pb.cc evrpc.pb.h) 9 | 10 | INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include) 11 | INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/rpc) 12 | INCLUDE_DIRECTORIES(${PROJECT_BINARY_DIR}/example) 13 | INCLUDE_DIRECTORIES(${PROJECT_BINARY_DIR}/rpc) 14 | LINK_DIRECTORIES(${LIBRARY_OUTPUT_DIRECTORY}) 15 | 16 | 17 | ADD_EXECUTABLE(tcpclient_test tcpclient_test.cc) 18 | ADD_EXECUTABLE(tcpserver_test tcpserver_test.cc) 19 | 20 | ADD_EXECUTABLE(ev_server evserver.cc evrpc.pb.cc) 21 | ADD_EXECUTABLE(ev_client evclient.cc evrpc.pb.cc) 22 | 23 | add_dependencies(ev_server evserver_proto) 24 | add_dependencies(ev_client evserver_proto) 25 | 26 | TARGET_LINK_LIBRARIES(tcpclient_test evrpc glog pthread event) 27 | TARGET_LINK_LIBRARIES(tcpserver_test evrpc glog pthread event) 28 | TARGET_LINK_LIBRARIES(ev_server evrpc z protobuf glog pthread event) 29 | TARGET_LINK_LIBRARIES(ev_client evrpc z protobuf glog pthread event) 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /example/evclient.cc: -------------------------------------------------------------------------------- 1 | #include "evrpc.pb.h" 2 | #include "rpcchannel.h" 3 | #include "tcpclient.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace evrpc; 10 | using namespace std; 11 | 12 | class RpcClient : noncopyable 13 | { 14 | public: 15 | RpcClient(std::string ip, int port = 8009) 16 | : client_(ip, port), 17 | channel_(new RpcChannel), 18 | stub_(get_pointer(channel_)) 19 | { 20 | client_.setConnectionCallback( 21 | std::bind(&RpcClient::onConnection, this,std::placeholders::_1)); 22 | client_.setReadCallback( 23 | std::bind(&RpcChannel::onMessage, get_pointer(channel_), std::placeholders::_1)); 24 | // client_.enableRetry(); 25 | } 26 | 27 | void connect() 28 | { 29 | client_.startRun(); 30 | } 31 | 32 | private: 33 | void onConnection(Conn* conn) 34 | { 35 | //channel_.reset(new RpcChannel(conn)); 36 | channel_->setConnection(conn); 37 | evrpc::PutRequest request; 38 | evrpc::Site *sit = request.add_sites(); 39 | sit->set_key("key test 1"); 40 | sit->set_value("value test 1"); 41 | evrpc::PutResult* result = new evrpc::PutResult; 42 | stub_.Put(NULL, &request, result, google::protobuf::NewCallback(this, &RpcClient::solved, result)); 43 | } 44 | 45 | void solved(evrpc::PutResult* resp) 46 | { 47 | cout << "solved:\n" << resp->DebugString().c_str(); 48 | client_.quit(NULL); 49 | } 50 | 51 | TcpClient client_; 52 | RpcChannelPtr channel_; 53 | evrpc::EkvCmd_Stub stub_; 54 | }; 55 | 56 | int main(int argc, char* argv[]) 57 | { 58 | 59 | RpcClient rpcClient("127.0.0.1", 8009); 60 | rpcClient.connect(); 61 | 62 | google::protobuf::ShutdownProtobufLibrary(); 63 | } 64 | 65 | -------------------------------------------------------------------------------- /example/evrpc.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package evrpc; 4 | 5 | option cc_generic_services = true; 6 | 7 | message Rvalue { 8 | bool success = 1; 9 | string errmsg = 2; 10 | } 11 | 12 | //message SiteKey { 13 | // bytes key = 1; 14 | //} 15 | //message SiteVal { 16 | // bytes value = 1; 17 | //} 18 | message Site { 19 | bytes key = 1; 20 | bytes value = 2; 21 | } 22 | 23 | message PutRequest{ 24 | repeated Site sites = 1; 25 | } 26 | message PutResult{ 27 | repeated Rvalue rvals = 1; 28 | // repeated Site sites = 1; 29 | } 30 | message GetRequest{ 31 | repeated bytes keys = 1; 32 | } 33 | message GetResult{ 34 | Rvalue rvals = 1; 35 | repeated Site sites = 2; 36 | } 37 | 38 | 39 | service EkvCmd { 40 | rpc Put (PutRequest) returns (PutResult); 41 | rpc Get (GetRequest) returns (GetResult); 42 | } 43 | 44 | -------------------------------------------------------------------------------- /example/evserver.cc: -------------------------------------------------------------------------------- 1 | #include "evrpc.pb.h" 2 | #include "rpcserver.h" 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace evrpc; 8 | using namespace std; 9 | 10 | 11 | class EkvCmdImpl : public EkvCmd 12 | { 13 | public: 14 | 15 | virtual void Put(::google::protobuf::RpcController* controller, 16 | const evrpc::PutRequest* request, 17 | evrpc::PutResult* response, 18 | ::google::protobuf::Closure* done) 19 | { 20 | cout<DebugString() <add_rvals(); 22 | 23 | resVal->set_success(true); 24 | resVal->set_errmsg("no error!"); 25 | done->Run(); 26 | } 27 | virtual void Get(::google::protobuf::RpcController* controller, 28 | const evrpc::GetRequest* request, 29 | evrpc::GetResult* response, 30 | ::google::protobuf::Closure* done) 31 | { 32 | cout<DebugString() <add_sites(); 34 | sit->set_key(request->keys(1)); 35 | sit->set_value("value1"); 36 | done->Run(); 37 | } 38 | }; 39 | 40 | 41 | int main() 42 | { 43 | EkvCmdImpl impl; 44 | RpcServer server(4, "127.0.0.1", 8009); 45 | server.registerService(&impl); 46 | server.start(); 47 | google::protobuf::ShutdownProtobufLibrary(); 48 | } 49 | 50 | -------------------------------------------------------------------------------- /example/tcpclient_test.cc: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: tcpserver_test.cpp 3 | > Author: changfa.zheng 4 | > Mail: changfa.zheng@ele.me 5 | > Created Time: 2017年09月01日 星期五 11时50分38秒 6 | ************************************************************************/ 7 | 8 | #include 9 | #include "tcpclient.h" 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | using namespace evrpc; 15 | 16 | void lenprint(char *buf, size_t len) 17 | { 18 | string str(len+1, 'a'); 19 | const char *data = str.c_str(); 20 | memcpy(const_cast(data), buf, len); 21 | cout << str << endl; 22 | } 23 | 24 | 25 | class TcpServerImpl : noncopyable 26 | { 27 | public: 28 | TcpServerImpl() {} 29 | ~TcpServerImpl() {} 30 | 31 | static void onMessage(Conn *conn) 32 | { 33 | char buffer[1024] = {}; 34 | //cout << "recv data from client-->"<getReadBufferLen(); 38 | 39 | for(int i =0; i< len/1024+1; i++){ 40 | conn->readBuffer(buffer, (i*1023)>len ? (i%1023):1023); 41 | cout<< "\t\t\tserver " << i << ":" << buffer << endl; 42 | } 43 | 44 | std::this_thread::sleep_for(std::chrono::seconds(2)); 45 | } 46 | 47 | 48 | 49 | static void send(Conn *conn) 50 | { 51 | string str("****************************!"); 52 | conn->addToWriteBuffer(const_cast(str.c_str()), str.size()); 53 | 54 | std::this_thread::sleep_for(std::chrono::seconds(2)); 55 | } 56 | 57 | 58 | static void onAccept(Conn *conn) { 59 | cout << "client connect:"<getFd() << "\tthread id:" << conn->getThread()->thread_id << endl; 61 | string str("*************************!"); 62 | conn->addToWriteBuffer(const_cast(str.c_str()), str.size()); 63 | } 64 | 65 | 66 | 67 | static void onError(Conn *conn, short event) 68 | { 69 | cout << "client closed : " << endl; 70 | cout << "fd:" << conn->getFd() << "\tthread id:" << conn->getThread()->thread_id << endl; 71 | } 72 | 73 | private: 74 | // static char buffer[1024]; 75 | }; 76 | 77 | 78 | int main(int argc, char **argv) 79 | { 80 | TcpClient client("127.0.0.1", 8009); 81 | 82 | client.setConnectionCallback(&TcpServerImpl::onAccept); 83 | client.setReadCallback(&TcpServerImpl::onMessage); 84 | client.setWriteCallback(&TcpServerImpl::send); 85 | client.setEventCallback(&TcpServerImpl::onError); 86 | 87 | client.startRun(); 88 | 89 | 90 | return 0; 91 | } 92 | -------------------------------------------------------------------------------- /example/tcpserver_test.cc: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: tcpserver_test.cpp 3 | > Author: changfa.zheng 4 | > Mail: changfa.zheng@ele.me 5 | > Created Time: 2017年09月01日 星期五 11时50分38秒 6 | ************************************************************************/ 7 | 8 | #include 9 | #include "tcpserver.h" 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | using namespace evrpc; 15 | 16 | void lenprint(char *buf, size_t len) 17 | { 18 | string str(len+1, 'a'); 19 | str.clear(); 20 | const char *data = str.c_str(); 21 | memcpy(const_cast(data), buf, len); 22 | cout << "\t\t\tclient :" << str << endl; 23 | } 24 | 25 | 26 | class TcpServerImpl : noncopyable 27 | { 28 | public: 29 | TcpServerImpl() {} 30 | ~TcpServerImpl() {} 31 | 32 | static void onMessage(Conn *conn) 33 | { 34 | char buffer[1024] = {}; 35 | int len=0, res = 0; 36 | len = conn->getReadBufferLen(); 37 | 38 | /*********************************************** 39 | * test evbuffer_peek; 40 | * **********************************************/ 41 | evbuffer *evbuf= conn->getReadBuffer(); 42 | int n = evbuffer_peek(evbuf, len, NULL, NULL, 0); 43 | evbuffer_iovec *vec = new evbuffer_iovec[n]; 44 | res = evbuffer_peek(evbuf, len, NULL, vec, n); 45 | assert( res == n); 46 | 47 | for (int i = 0; i < n; i++){ 48 | lenprint((char *)(vec[i].iov_base), vec[i].iov_len); 49 | } 50 | delete [] vec; 51 | 52 | 53 | /*********************************************** 54 | * test evbuffer_peek; 55 | * **********************************************/ 56 | for(int i =0; i< len/1024+1; i++){ 57 | res = conn->readBuffer(buffer, (i*1023)>len ? (i%1023):1023); 58 | cout<< "\t\t\tbuf " << i << ":" << buffer << endl; 59 | } 60 | // string str("server send message success!"); 61 | // conn->addToWriteBuffer(const_cast(str.c_str()), str.size()); 62 | std::this_thread::sleep_for(std::chrono::seconds(2)); 63 | 64 | } 65 | 66 | 67 | 68 | static void send(Conn *conn) 69 | { 70 | string str("************************!"); 71 | conn->addToWriteBuffer(const_cast(str.c_str()), str.size()); 72 | 73 | std::this_thread::sleep_for(std::chrono::seconds(3)); 74 | } 75 | 76 | 77 | static void onAccept(Conn *conn) 78 | { 79 | cout << "client connect:"<getFd() << "\tthread id:" << conn->getThread()->thread_id << endl; 81 | } 82 | 83 | 84 | static void onError(Conn *conn, short event) 85 | { 86 | cout << "client closed : " << endl; 87 | cout << "fd:" << conn->getFd() << "\tthread id:" << conn->getThread()->thread_id << endl; 88 | } 89 | 90 | private: 91 | // static char buffer[1024]; 92 | }; 93 | 94 | 95 | int main(int argc, char **argv) 96 | { 97 | TcpServer server(4, "127.0.0.1", 8009); 98 | 99 | server.setConnectionCallback(&TcpServerImpl::onAccept); 100 | server.setReadCallback(&TcpServerImpl::onMessage); 101 | server.setWriteCallback(&TcpServerImpl::send); 102 | server.setEventCallback(&TcpServerImpl::onError); 103 | 104 | server.startRun(); 105 | 106 | 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /include/atomic.h: -------------------------------------------------------------------------------- 1 | #ifndef RPC_ATOMIC_H 2 | #define RPC_ATOMIC_H 3 | 4 | #include "util.h" 5 | 6 | #include 7 | 8 | namespace evrpc 9 | { 10 | 11 | template 12 | class AtomicIntegerT : noncopyable 13 | { 14 | public: 15 | AtomicIntegerT() 16 | : value_(0) 17 | { 18 | } 19 | 20 | // uncomment if you need copying and assignment 21 | // 22 | // AtomicIntegerT(const AtomicIntegerT& that) 23 | // : value_(that.get()) 24 | // {} 25 | // 26 | // AtomicIntegerT& operator=(const AtomicIntegerT& that) 27 | // { 28 | // getAndSet(that.get()); 29 | // return *this; 30 | // } 31 | 32 | T get() 33 | { 34 | // in gcc >= 4.7: __atomic_load_n(&value_, __ATOMIC_SEQ_CST) 35 | return __sync_val_compare_and_swap(&value_, 0, 0); 36 | } 37 | 38 | T getAndAdd(T x) 39 | { 40 | // in gcc >= 4.7: __atomic_fetch_add(&value_, x, __ATOMIC_SEQ_CST) 41 | return __sync_fetch_and_add(&value_, x); 42 | } 43 | 44 | T addAndGet(T x) 45 | { 46 | return getAndAdd(x) + x; 47 | } 48 | 49 | T incrementAndGet() 50 | { 51 | return addAndGet(1); 52 | } 53 | 54 | T decrementAndGet() 55 | { 56 | return addAndGet(-1); 57 | } 58 | 59 | void add(T x) 60 | { 61 | getAndAdd(x); 62 | } 63 | 64 | void increment() 65 | { 66 | incrementAndGet(); 67 | } 68 | 69 | void decrement() 70 | { 71 | decrementAndGet(); 72 | } 73 | 74 | T getAndSet(T newValue) 75 | { 76 | // in gcc >= 4.7: __atomic_exchange_n(&value, newValue, __ATOMIC_SEQ_CST) 77 | return __sync_lock_test_and_set(&value_, newValue); 78 | } 79 | 80 | private: 81 | volatile T value_; 82 | }; 83 | 84 | typedef AtomicIntegerT AtomicInt32; 85 | typedef AtomicIntegerT AtomicInt64; 86 | } 87 | 88 | #endif // RPC_ATOMIC_H 89 | -------------------------------------------------------------------------------- /include/ev_endian.h: -------------------------------------------------------------------------------- 1 | #ifndef RPC_ENDIAN_H__ 2 | #define RPC_ENDIAN_H__ 3 | 4 | #include 5 | #include 6 | 7 | namespace evrpc 8 | { 9 | namespace sockets 10 | { 11 | 12 | // the inline assembler code makes type blur, 13 | // so we disable warnings for a while. 14 | #if defined(__clang__) || __GNUC_PREREQ (4,6) 15 | #pragma GCC diagnostic push 16 | #endif 17 | #pragma GCC diagnostic ignored "-Wconversion" 18 | #pragma GCC diagnostic ignored "-Wold-style-cast" 19 | inline uint64_t hostToNetwork64(uint64_t host64) 20 | { 21 | return htobe64(host64); 22 | } 23 | 24 | inline uint32_t hostToNetwork32(uint32_t host32) 25 | { 26 | return htobe32(host32); 27 | } 28 | 29 | inline uint16_t hostToNetwork16(uint16_t host16) 30 | { 31 | return htobe16(host16); 32 | } 33 | 34 | inline uint64_t networkToHost64(uint64_t net64) 35 | { 36 | return be64toh(net64); 37 | } 38 | 39 | inline uint32_t networkToHost32(uint32_t net32) 40 | { 41 | return be32toh(net32); 42 | } 43 | 44 | inline uint16_t networkToHost16(uint16_t net16) 45 | { 46 | return be16toh(net16); 47 | } 48 | #if defined(__clang__) || __GNUC_PREREQ (4,6) 49 | #pragma GCC diagnostic pop 50 | #else 51 | #pragma GCC diagnostic warning "-Wconversion" 52 | #pragma GCC diagnostic warning "-Wold-style-cast" 53 | #endif 54 | 55 | } 56 | } 57 | 58 | #endif // RPC_ENDIAN_H__ 59 | -------------------------------------------------------------------------------- /include/util.h: -------------------------------------------------------------------------------- 1 | #ifndef _UTIL_H 2 | #define _UTIL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class noncopyable 11 | { 12 | protected: 13 | noncopyable() {} 14 | ~noncopyable() {} 15 | private: // emphasize the following members are private 16 | noncopyable( const noncopyable& ); 17 | const noncopyable& operator=( const noncopyable& ); 18 | }; 19 | 20 | 21 | template 22 | inline T* get_pointer(const std::shared_ptr& ptr) 23 | { 24 | return ptr.get(); 25 | } 26 | 27 | template 28 | inline T* get_pointer(const std::unique_ptr& ptr) 29 | { 30 | return ptr.get(); 31 | } 32 | 33 | 34 | template 35 | inline ::std::shared_ptr down_pointer_cast(const ::std::shared_ptr& f) { 36 | return ::std::static_pointer_cast(f); 37 | } 38 | 39 | 40 | 41 | struct Any 42 | { 43 | Any(void) : m_tpIndex(std::type_index(typeid(void))){} 44 | Any(const Any& that) : m_ptr(that.Clone()), m_tpIndex(that.m_tpIndex) {} 45 | Any(Any && that) : m_ptr(std::move(that.m_ptr)), m_tpIndex(that.m_tpIndex) {} 46 | 47 | //创建智能指针时,对于一般的类型,通过std::decay来移除引用和cv符,从而获取原始类型 48 | template::type, Any>::value, U>::type> Any(U && value) : 49 | m_ptr(new Derived < typename std::decay::type>(std::forward(value))), 50 | m_tpIndex(std::type_index(typeid(typename std::decay::type))){} 51 | 52 | bool IsNull() const { return !bool(m_ptr); } 53 | 54 | template bool Is() const 55 | { 56 | return m_tpIndex == std::type_index(typeid(U)); 57 | } 58 | 59 | //将Any转换为实际的类型 60 | template 61 | U& AnyCast() 62 | { 63 | if (!Is()) 64 | { 65 | // cout << "can not cast " << typeid(U).name() << " to " << m_tpIndex.name() << endl; 66 | throw std::runtime_error("any context error!"); 67 | } 68 | 69 | auto derived = dynamic_cast*> (m_ptr.get()); 70 | return derived->m_value; 71 | } 72 | 73 | Any& operator=(const Any& a) 74 | { 75 | if (m_ptr == a.m_ptr) 76 | return *this; 77 | 78 | m_ptr = a.Clone(); 79 | m_tpIndex = a.m_tpIndex; 80 | return *this; 81 | } 82 | 83 | private: 84 | struct Base; 85 | typedef std::unique_ptr BasePtr; 86 | 87 | struct Base 88 | { 89 | virtual ~Base() {} 90 | virtual BasePtr Clone() const = 0; 91 | }; 92 | 93 | template 94 | struct Derived : Base 95 | { 96 | template 97 | Derived(U && value) : m_value(std::forward(value)) { } 98 | 99 | BasePtr Clone() const 100 | { 101 | return BasePtr(new Derived(m_value)); 102 | } 103 | 104 | T m_value; 105 | }; 106 | 107 | BasePtr Clone() const 108 | { 109 | if (m_ptr != nullptr) 110 | return m_ptr->Clone(); 111 | return nullptr; 112 | } 113 | 114 | BasePtr m_ptr; 115 | std::type_index m_tpIndex; 116 | }; 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /rpc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #cmake file for ev server 2 | #author changfa.zheng 3 | 4 | add_custom_command(OUTPUT rpc.pb.cc rpc.pb.h 5 | COMMAND protoc ARGS --cpp_out . ${CMAKE_CURRENT_SOURCE_DIR}/rpc.proto -I${CMAKE_CURRENT_SOURCE_DIR} 6 | DEPENDS rpc.proto 7 | VERBATIM ) 8 | 9 | add_custom_target(rpc_comp DEPENDS rpc.pb.cc rpc.pb.h) 10 | 11 | 12 | 13 | INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include) 14 | INCLUDE_DIRECTORIES(${PROJECT_BINARY_DIR}/rpc) 15 | 16 | #LINK_DIRECTORIES( 17 | # ./ 18 | # ) 19 | 20 | 21 | #获得一个目录下所有源文件(不包括头文件)到变量SRCS 22 | #AUX_SOURCE_DIRECTORY(dirname SRCS) 23 | #AUX_SOURCE_DIRECTORY(./ SOURCE_FILES) 24 | 25 | set(SOURCE_FILES 26 | codeclite.cc 27 | rpcchannel.cc 28 | rpccodec.cc 29 | rpcserver.cc 30 | tcpserver.cc 31 | tcpclient.cc 32 | rpc.pb.cc) 33 | 34 | ADD_LIBRARY(evrpc ${SOURCE_FILES}) 35 | #生成静态链接库libname.a 36 | #ADD_LIBRARY(name $SOURCE_FILES) 37 | 38 | add_dependencies(evrpc rpc_comp) 39 | #依赖的库文件 40 | TARGET_LINK_LIBRARIES(evrpc glog pthread event) 41 | 42 | install(TARGETS evrpc DESTINATION ${PROJECT_BINARY_DIR}/lib/) 43 | 44 | SET(HEADERS 45 | codeclite.h 46 | google-inl.h 47 | rpcchannel.h 48 | rpccodec.h 49 | rpcserver.h 50 | tcpserver.h 51 | tcpclient.h 52 | ${PROJECT_BINARY_DIR}/rpc/rpc.pb.h 53 | ) 54 | 55 | install(FILES ${HEADERS} DESTINATION ${PROJECT_BINARY_DIR}/include/rpc/) 56 | -------------------------------------------------------------------------------- /rpc/codeclite.cc: -------------------------------------------------------------------------------- 1 | #include "codeclite.h" 2 | #include "tcpserver.h" 3 | #include "ev_endian.h" 4 | #include "google-inl.h" 5 | 6 | #include 7 | #include 8 | 9 | 10 | using namespace evrpc; 11 | using namespace evrpc::sockets; 12 | 13 | namespace 14 | { 15 | int ProtobufVersionCheck() 16 | { 17 | GOOGLE_PROTOBUF_VERIFY_VERSION; 18 | return 0; 19 | } 20 | int __attribute__ ((unused)) dummy = ProtobufVersionCheck(); 21 | } 22 | 23 | 24 | namespace evrpc 25 | { 26 | 27 | 28 | void ProtobufCodecLite::send(Conn* conn, 29 | const ::google::protobuf::Message& message) 30 | { 31 | // int res = 0; 32 | struct evbuffer *ebuf = evbuffer_new(); 33 | if (fillEmptyBuffer(ebuf, message) < 0) 34 | { 35 | LOG(ERROR) << "send error:"<addBufToWriteBuffer(ebuf) != 0) 38 | { 39 | LOG(ERROR) << "send error:"<readableBytes() == tag_.size() + byte_size + kChecksumLen); 58 | len = sockets::hostToNetwork32(static_cast(tag_.size() + byte_size + kChecksumLen)); 59 | if( (res = evbuffer_prepend(buf, &len, sizeof len)) < 0) 60 | return res; 61 | return 0; 62 | } 63 | 64 | 65 | int ProtobufCodecLite::serializeToBuffer(const google::protobuf::Message& message, struct evbuffer* buf) 66 | { 67 | GOOGLE_DCHECK(message.IsInitialized()) << InitializationErrorMessage("serialize", message); 68 | 69 | struct evbuffer_iovec vec; 70 | uint32_t byte_size = message.ByteSize(); 71 | /*int */evbuffer_reserve_space(buf, byte_size+kChecksumLen, &vec, 1); 72 | uint8_t *start = static_cast(vec.iov_base); 73 | uint8_t *end = message.SerializeWithCachedSizesToArray(start); 74 | vec.iov_len = end - start; 75 | if ( vec.iov_len != byte_size) 76 | { 77 | ByteSizeConsistencyError(byte_size, message.ByteSize(), static_cast(end - start)); 78 | } 79 | /*int */evbuffer_commit_space(buf, &vec, 1); 80 | 81 | return vec.iov_len; 82 | } 83 | 84 | 85 | void ProtobufCodecLite::onMessage(Conn* conn) 86 | { 87 | LOG(INFO) << "received message len:"<getReadBufferLen(); 88 | while (conn->getReadBufferLen() >= static_cast(kMinMessageLen+kHeaderLen)) 89 | { 90 | int32_t len = 0; 91 | conn->readBuffer(reinterpret_cast(&len), sizeof(len)); 92 | len = asInt32(reinterpret_cast(&len)); 93 | if (len > kMaxMessageLen || (uint32_t)len < kMinMessageLen) 94 | { 95 | errorCallback_(conn, kInvalidLength);/*change*/ 96 | break; 97 | } 98 | else if (conn->getReadBufferLen()>= (static_cast(len))) 99 | { 100 | if (rawCb_ && !rawCb_(conn, len)) 101 | { 102 | evbuffer_drain(conn->getReadBuffer(), len); 103 | continue; 104 | } 105 | MessagePtr message(prototype_->New()); 106 | // FIXME: can we move deserialization & callback to other thread? 107 | ErrorCode errorCode = parse(conn, len, message.get()); 108 | if (errorCode == kNoError) 109 | { 110 | // FIXME: try { } catch (...) { } 111 | messageCallback_(conn, message); 112 | evbuffer_drain(conn->getReadBuffer(), len); 113 | } 114 | else 115 | { 116 | errorCallback_(conn, errorCode); 117 | break; 118 | } 119 | } 120 | else 121 | { 122 | break; 123 | } 124 | } 125 | } 126 | 127 | bool ProtobufCodecLite::parseFromBuffer(const unsigned char * buf, int len, google::protobuf::Message* message) 128 | { 129 | return message->ParseFromArray(buf, len); 130 | } 131 | 132 | namespace 133 | { 134 | const std::string kNoErrorStr = "NoError"; 135 | const std::string kInvalidLengthStr = "InvalidLength"; 136 | const std::string kCheckSumErrorStr = "CheckSumError"; 137 | const std::string kInvalidNameLenStr = "InvalidNameLen"; 138 | const std::string kUnknownMessageTypeStr = "UnknownMessageType"; 139 | const std::string kParseErrorStr = "ParseError"; 140 | const std::string kUnknownErrorStr = "UnknownError"; 141 | } 142 | 143 | const std::string& ProtobufCodecLite::errorCodeToString(ErrorCode errorCode) 144 | { 145 | switch (errorCode) 146 | { 147 | case kNoError: 148 | return kNoErrorStr; 149 | case kInvalidLength: 150 | return kInvalidLengthStr; 151 | case kCheckSumError: 152 | return kCheckSumErrorStr; 153 | case kInvalidNameLen: 154 | return kInvalidNameLenStr; 155 | case kUnknownMessageType: 156 | return kUnknownMessageTypeStr; 157 | case kParseError: 158 | return kParseErrorStr; 159 | default: 160 | return kUnknownErrorStr; 161 | } 162 | } 163 | 164 | void ProtobufCodecLite::defaultErrorCallback(Conn* conn, 165 | ErrorCode errorCode) 166 | { 167 | //LOG(DEBUF)<< "ProtobufCodecLite::defaultErrorCallback - " << errorCodeToString(errorCode); 168 | if (conn) 169 | { 170 | bufferevent_free(conn->getBufferevent()); 171 | conn->getThread()->connect_queue.deleteConn(conn); 172 | } 173 | } 174 | 175 | int32_t ProtobufCodecLite::asInt32(const char* buf) 176 | { 177 | int32_t be32 = 0; 178 | ::memcpy(&be32, buf, sizeof(be32)); 179 | return sockets::networkToHost32(be32); 180 | } 181 | 182 | int32_t ProtobufCodecLite::checksum(struct evbuffer* buf, int len) 183 | { 184 | int dlen = 0; 185 | uLong adler = adler32(1L, Z_NULL, 0); 186 | int n = evbuffer_peek(buf, len, NULL, NULL, 0); 187 | evbuffer_iovec *vec = new evbuffer_iovec[n]; 188 | int res = evbuffer_peek(buf, len, NULL, vec, n); 189 | assert( res == n); 190 | for (int i = 0; i < n; i++){ 191 | dlen += vec[i].iov_len; 192 | adler = adler32(adler, static_cast(vec[i].iov_base), vec[i].iov_len); 193 | } 194 | delete [] vec; 195 | // LOG(INFO) << "Len : "<< dlen << "checksum : "<(adler); 198 | } 199 | 200 | bool ProtobufCodecLite::validateChecksum(const Bytef* buf, int len) 201 | { 202 | int32_t expectedCheckSum = asInt32(reinterpret_cast(buf) + len - kChecksumLen); 203 | uLong adler = adler32(1L, Z_NULL, 0); 204 | adler = adler32(adler, (buf), len-kChecksumLen); 205 | // LOG(INFO) << "Len : "<< len-kChecksumLen << "checksum : "<(adler)) == (expectedCheckSum); 208 | } 209 | 210 | ProtobufCodecLite::ErrorCode ProtobufCodecLite::parse(Conn* conn, 211 | int len, 212 | ::google::protobuf::Message* message) 213 | { 214 | ErrorCode error = kNoError; 215 | evbuffer *readBuffer = conn->getReadBuffer(); 216 | // std::vector tag(tag_.size()); 217 | unsigned char *data = evbuffer_pullup(readBuffer, len); 218 | if (data == NULL){ 219 | // 220 | } 221 | /* 222 | struct evbuffer_iovec vec ; 223 | res = evbuffer_peek(readBuffer, len, NULL, &vec, 1); 224 | assert( res == 1); 225 | */ 226 | if (validateChecksum(static_cast(data), len)) 227 | { 228 | if (memcmp(data, tag_.data(), tag_.size()) == 0) 229 | { 230 | // parse from buffer 231 | int32_t dataLen = len - kChecksumLen - static_cast(tag_.size()); 232 | if (parseFromBuffer(data+tag_.size(), dataLen, message)) 233 | { 234 | error = kNoError; 235 | } 236 | else 237 | { 238 | error = kParseError; 239 | } 240 | } 241 | else 242 | { 243 | error = kUnknownMessageType; 244 | } 245 | } 246 | else 247 | { 248 | error = kCheckSumError; 249 | } 250 | 251 | return error; 252 | } 253 | 254 | } 255 | -------------------------------------------------------------------------------- /rpc/codeclite.h: -------------------------------------------------------------------------------- 1 | #ifndef RPC_CODEC_LITE_H 2 | #define RPC_CODEC_LITE_H 3 | 4 | 5 | #include 6 | #include 7 | #include "tcpserver.h" 8 | #include 9 | 10 | namespace google 11 | { 12 | namespace protobuf 13 | { 14 | class Message; 15 | } 16 | } 17 | 18 | namespace evrpc 19 | { 20 | 21 | typedef std::shared_ptr MessagePtr; 22 | 23 | // wire format 24 | // 25 | // Field Length Content 26 | // 27 | // size 4-byte M+N+4 28 | // tag M-byte could be "RPC0", etc. 29 | // payload N-byte 30 | // checksum 4-byte adler32 of tag+payload 31 | // 32 | // This is an internal class, you should use ProtobufCodecT instead. 33 | class ProtobufCodecLite : noncopyable 34 | { 35 | public: 36 | const static int kHeaderLen = sizeof(int32_t); 37 | const static int kChecksumLen = sizeof(int32_t); 38 | const static int kMaxMessageLen = 64*1024*1024; // same as codec_stream.h kDefaultTotalBytesLimit 39 | 40 | enum ErrorCode 41 | { 42 | kNoError = 0, 43 | kInvalidLength, 44 | kCheckSumError, 45 | kInvalidNameLen, 46 | kUnknownMessageType, 47 | kParseError, 48 | }; 49 | 50 | // return false to stop parsing protobuf message 51 | typedef std::function RawMessageCallback; 52 | 53 | typedef std::function ProtobufMessageCallback; 54 | 55 | typedef std::function ErrorCallback; 56 | 57 | ProtobufCodecLite(const ::google::protobuf::Message* prototype, 58 | const char * tagArg, 59 | const ProtobufMessageCallback& messageCb, 60 | const RawMessageCallback& rawCb = RawMessageCallback(), 61 | const ErrorCallback& errorCb = defaultErrorCallback) 62 | : prototype_(prototype), 63 | tag_(tagArg, strlen(tagArg)), 64 | messageCallback_(messageCb), 65 | rawCb_(rawCb), 66 | errorCallback_(errorCb), 67 | kMinMessageLen(tag_.length() + kChecksumLen) 68 | { 69 | LOG(INFO) << "ProtobufCodecLite Constructor" ; 70 | } 71 | 72 | virtual ~ProtobufCodecLite() { } 73 | 74 | const std::string& tag() const { return tag_; } 75 | 76 | 77 | void send(Conn* conn, 78 | const ::google::protobuf::Message& message); 79 | void onMessage(Conn* conn); 80 | bool parseFromBuffer(const unsigned char * buf, int len, 81 | google::protobuf::Message* message);; 82 | 83 | 84 | int serializeToBuffer(const google::protobuf::Message& message, 85 | struct evbuffer* buf); 86 | static const std::string& errorCodeToString(ErrorCode errorCode); 87 | 88 | // public for unit tests 89 | ErrorCode parse(Conn* conn, int len, ::google::protobuf::Message* message); 90 | int fillEmptyBuffer(struct evbuffer* buf, const google::protobuf::Message& message); 91 | 92 | 93 | 94 | 95 | static int32_t checksum(struct evbuffer* buf, int len); 96 | static bool validateChecksum(const Bytef* buf, int len); 97 | static int32_t asInt32(const char* buf); 98 | static void defaultErrorCallback(Conn*, ErrorCode); 99 | 100 | private: 101 | const ::google::protobuf::Message* prototype_; 102 | const std::string tag_; 103 | ProtobufMessageCallback messageCallback_; 104 | RawMessageCallback rawCb_; 105 | ErrorCallback errorCallback_; 106 | const uint32_t kMinMessageLen; 107 | }; 108 | 109 | template // TAG must be a variable with external linkage, not a string literal 110 | class ProtobufCodecLiteT 111 | { 112 | static_assert(std::is_base_of::value, "CODEC should be derived from ProtobufCodecLite"); 113 | public: 114 | typedef std::shared_ptr ConcreteMessagePtr; 115 | typedef std::function ProtobufMessageCallback; 116 | typedef ProtobufCodecLite::RawMessageCallback RawMessageCallback; 117 | typedef ProtobufCodecLite::ErrorCallback ErrorCallback; 118 | 119 | explicit ProtobufCodecLiteT(const ProtobufMessageCallback& messageCb, 120 | const RawMessageCallback& rawCb = RawMessageCallback(), 121 | const ErrorCallback& errorCb = ProtobufCodecLite::defaultErrorCallback) 122 | : messageCallback_(messageCb), 123 | codec_(&MSG::default_instance(), TAG, 124 | std::bind(&ProtobufCodecLiteT::onRpcMessage, this, std::placeholders::_1,std::placeholders::_2), 125 | rawCb, errorCb) 126 | { 127 | } 128 | 129 | const std::string& tag() const { return codec_.tag(); } 130 | 131 | void send(Conn* conn, 132 | const MSG& message) 133 | { 134 | codec_.send(conn, message); 135 | } 136 | 137 | void onMessage(Conn* conn) 138 | { 139 | codec_.onMessage(conn); 140 | } 141 | 142 | // internal 143 | void onRpcMessage(Conn* conn, 144 | const MessagePtr& message) 145 | { 146 | messageCallback_(conn, ::down_pointer_cast(message)); 147 | } 148 | 149 | void fillEmptyBuffer(struct evbuffer* buf, const google::protobuf::Message& message) 150 | { 151 | codec_.fillEmptyBuffer(buf, message); 152 | } 153 | 154 | private: 155 | ProtobufMessageCallback messageCallback_; 156 | CODEC codec_; 157 | }; 158 | 159 | } 160 | 161 | #endif // RPC_CODEC_LITE_H__ 162 | -------------------------------------------------------------------------------- /rpc/google-inl.h: -------------------------------------------------------------------------------- 1 | // ByteSizeConsistencyError and InitializationErrorMessage are 2 | // copied from google/protobuf/message_lite.cc 3 | 4 | // Protocol Buffers - Google's data interchange format 5 | // Copyright 2008 Google Inc. All rights reserved. 6 | // http://code.google.com/p/protobuf/ 7 | // 8 | // Redistribution and use in source and binary forms, with or without 9 | // modification, are permitted provided that the following conditions are 10 | // met: 11 | // 12 | // * Redistributions of source code must retain the above copyright 13 | // notice, this list of conditions and the following disclaimer. 14 | // * Redistributions in binary form must reproduce the above 15 | // copyright notice, this list of conditions and the following disclaimer 16 | // in the documentation and/or other materials provided with the 17 | // distribution. 18 | // * Neither the name of Google Inc. nor the names of its 19 | // contributors may be used to endorse or promote products derived from 20 | // this software without specific prior written permission. 21 | // 22 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | 34 | // Authors: wink@google.com (Wink Saville), 35 | // kenton@google.com (Kenton Varda) 36 | // Based on original Protocol Buffers design by 37 | // Sanjay Ghemawat, Jeff Dean, and others. 38 | 39 | #include 40 | 41 | // When serializing, we first compute the byte size, then serialize the message. 42 | // If serialization produces a different number of bytes than expected, we 43 | // call this function, which crashes. The problem could be due to a bug in the 44 | // protobuf implementation but is more likely caused by concurrent modification 45 | // of the message. This function attempts to distinguish between the two and 46 | // provide a useful error message. 47 | inline 48 | void ByteSizeConsistencyError(int byte_size_before_serialization, 49 | int byte_size_after_serialization, 50 | int bytes_produced_by_serialization) 51 | { 52 | GOOGLE_CHECK_EQ(byte_size_before_serialization, byte_size_after_serialization) 53 | << "Protocol message was modified concurrently during serialization."; 54 | GOOGLE_CHECK_EQ(bytes_produced_by_serialization, byte_size_before_serialization) 55 | << "Byte size calculation and serialization were inconsistent. This " 56 | "may indicate a bug in protocol buffers or it may be caused by " 57 | "concurrent modification of the message."; 58 | GOOGLE_LOG(FATAL) << "This shouldn't be called if all the sizes are equal."; 59 | } 60 | 61 | inline 62 | std::string InitializationErrorMessage(const char* action, 63 | const google::protobuf::MessageLite& message) 64 | { 65 | // Note: We want to avoid depending on strutil in the lite library, otherwise 66 | // we'd use: 67 | // 68 | // return strings::Substitute( 69 | // "Can't $0 message of type \"$1\" because it is missing required " 70 | // "fields: $2", 71 | // action, message.GetTypeName(), 72 | // message.InitializationErrorString()); 73 | 74 | std::string result; 75 | result += "Can't "; 76 | result += action; 77 | result += " message of type \""; 78 | result += message.GetTypeName(); 79 | result += "\" because it is missing required fields: "; 80 | result += message.InitializationErrorString(); 81 | return result; 82 | } 83 | 84 | 85 | -------------------------------------------------------------------------------- /rpc/rpc.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | 3 | package evrpc; 4 | 5 | option go_package = "ekvrpc"; 6 | option java_package = "ekvrpc"; 7 | option java_outer_classname = "RpcProto"; 8 | 9 | enum MessageType 10 | { 11 | UNKNOW = 0; 12 | REQUEST = 1; 13 | RESPONSE = 2; 14 | ERROR = 3; // not used 15 | } 16 | 17 | enum ErrorCode 18 | { 19 | NO_ERROR = 0; 20 | WRONG_PROTO = 1; 21 | NO_SERVICE = 2; 22 | NO_METHOD = 3; 23 | INVALID_REQUEST = 4; 24 | INVALID_RESPONSE = 5; 25 | TIMEOUT = 6; 26 | } 27 | 28 | message RpcMessage 29 | { 30 | optional MessageType type= 1; 31 | optional fixed64 id = 2; 32 | 33 | optional string service = 3; 34 | optional string method = 4; 35 | optional bytes request = 5; 36 | 37 | optional bytes response = 6; 38 | 39 | optional ErrorCode error = 7; 40 | } 41 | -------------------------------------------------------------------------------- /rpc/rpcchannel.cc: -------------------------------------------------------------------------------- 1 | #include "rpcchannel.h" 2 | #include "rpc.pb.h" 3 | #include 4 | 5 | using namespace evrpc; 6 | 7 | RpcChannel::RpcChannel() 8 | : codec_(std::bind(&RpcChannel::onRpcMessage, this, std::placeholders::_1,std::placeholders::_2)), 9 | services_(NULL) 10 | { 11 | LOG(INFO) << "RpcChannel::Constructor -- " << this; 12 | } 13 | 14 | RpcChannel::RpcChannel(Conn* conn) 15 | : codec_(std::bind(&RpcChannel::onRpcMessage, this,std::placeholders::_1,std::placeholders::_2)), 16 | conn_(conn), 17 | services_(NULL) 18 | { 19 | LOG(INFO) << "RpcChannel::Constructor -- " << this; 20 | } 21 | 22 | RpcChannel::~RpcChannel() 23 | { 24 | LOG(INFO) << "RpcChannel::Destructor - " << this; 25 | for (std::map::iterator it = outstandings_.begin(); it != outstandings_.end(); ++it) 26 | { 27 | OutstandingCall out = it->second; 28 | delete out.response; 29 | delete out.done; 30 | } 31 | } 32 | 33 | // Call the given method of the remote service. The signature of this 34 | // procedure looks the same as Service::CallMethod(), but the requirements 35 | // are less strict in one important way: the request and response objects 36 | // need not be of any specific class as long as their descriptors are 37 | // method->input_type() and method->output_type(). 38 | void RpcChannel::CallMethod(const ::google::protobuf::MethodDescriptor* method, 39 | google::protobuf::RpcController* controller, 40 | const ::google::protobuf::Message* request, 41 | ::google::protobuf::Message* response, 42 | ::google::protobuf::Closure* done) 43 | { 44 | RpcMessage message; 45 | message.set_type(REQUEST); 46 | int64_t id = id_.incrementAndGet(); 47 | message.set_id(id); 48 | message.set_service(method->service()->full_name()); 49 | message.set_method(method->name()); 50 | message.set_request(request->SerializeAsString()); // FIXME: error check 51 | 52 | OutstandingCall out = { response, done }; 53 | { 54 | std::lock_guard lk(mutex_); 55 | outstandings_[id] = out; 56 | } 57 | codec_.send(conn_, message); 58 | } 59 | 60 | void RpcChannel::onMessage(Conn* conn) 61 | { 62 | codec_.onMessage(conn); 63 | } 64 | 65 | void RpcChannel::onRpcMessage(Conn* conn, const RpcMessagePtr& messagePtr) 66 | { 67 | assert(conn == conn_); 68 | //printf("%s\n", message.DebugString().c_str()); 69 | RpcMessage& message = *messagePtr; 70 | if (message.type() == RESPONSE) 71 | { 72 | int64_t id = message.id(); 73 | assert(message.has_response() || message.has_error()); 74 | 75 | OutstandingCall out = { NULL, NULL }; 76 | 77 | { 78 | std::lock_guard lk(mutex_); 79 | std::map::iterator it = outstandings_.find(id); 80 | if (it != outstandings_.end()) 81 | { 82 | out = it->second; 83 | outstandings_.erase(it); 84 | } 85 | } 86 | 87 | if (out.response) 88 | { 89 | std::unique_ptr d(out.response); 90 | if (message.has_response()) 91 | { 92 | out.response->ParseFromString(message.response()); 93 | } 94 | if (out.done) 95 | { 96 | out.done->Run(); 97 | } 98 | } 99 | } 100 | else if (message.type() == REQUEST) 101 | { 102 | // FIXME: extract to a function 103 | ErrorCode error = WRONG_PROTO; 104 | if (services_) 105 | { 106 | std::map::const_iterator it = services_->find(message.service()); 107 | if (it != services_->end()) 108 | { 109 | google::protobuf::Service* service = it->second; 110 | assert(service != NULL); 111 | const google::protobuf::ServiceDescriptor* desc = service->GetDescriptor(); 112 | const google::protobuf::MethodDescriptor* method 113 | = desc->FindMethodByName(message.method()); 114 | if (method) 115 | { 116 | std::unique_ptr request(service->GetRequestPrototype(method).New()); 117 | if (request->ParseFromString(message.request())) 118 | { 119 | google::protobuf::Message* response = service->GetResponsePrototype(method).New(); 120 | // response is deleted in doneCallback 121 | int64_t id = message.id(); 122 | service->CallMethod(method, NULL, get_pointer(request), response, 123 | NewCallback(this, &RpcChannel::doneCallback, response, id)); 124 | error = NO_ERROR; 125 | } 126 | else 127 | { 128 | error = INVALID_REQUEST; 129 | } 130 | } 131 | else 132 | { 133 | error = NO_METHOD; 134 | } 135 | } 136 | else 137 | { 138 | error = NO_SERVICE; 139 | } 140 | } 141 | else 142 | { 143 | error = NO_SERVICE; 144 | } 145 | if (error != NO_ERROR) 146 | { 147 | RpcMessage response; 148 | response.set_type(RESPONSE); 149 | response.set_id(message.id()); 150 | response.set_error(error); 151 | codec_.send(conn_, response); 152 | } 153 | } 154 | else if (message.type() == ERROR) 155 | { 156 | } 157 | } 158 | 159 | void RpcChannel::doneCallback(::google::protobuf::Message* response, int64_t id) 160 | { 161 | std::unique_ptr d(response); 162 | RpcMessage message; 163 | message.set_type(RESPONSE); 164 | message.set_id(id); 165 | message.set_response(response->SerializeAsString()); // FIXME: error check 166 | codec_.send(conn_, message); 167 | } 168 | 169 | -------------------------------------------------------------------------------- /rpc/rpcchannel.h: -------------------------------------------------------------------------------- 1 | #ifndef RPC_RPCCHANNEL_H 2 | #define RPC_RPCCHANNEL_H 3 | 4 | #include "rpccodec.h" 5 | #include "atomic.h" 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace google { 13 | namespace protobuf { 14 | 15 | // Defined in other files. 16 | class Descriptor; // descriptor.h 17 | class ServiceDescriptor; // descriptor.h 18 | class MethodDescriptor; // descriptor.h 19 | class Message; // message.h 20 | 21 | class Closure; 22 | 23 | class RpcController; 24 | class Service; 25 | 26 | } // namespace protobuf 27 | } // namespace google 28 | 29 | 30 | namespace evrpc 31 | { 32 | 33 | // Abstract interface for an RPC channel. An RpcChannel represents a 34 | // communication line to a Service which can be used to call that Service's 35 | // methods. The Service may be running on another machine. Normally, you 36 | // should not call an RpcChannel directly, but instead construct a stub Service 37 | // wrapping it. Example: 38 | // FIXME: update here 39 | // RpcChannel* channel = new MyRpcChannel("remotehost.example.com:1234"); 40 | // MyService* service = new MyService::Stub(channel); 41 | // service->MyMethod(request, &response, callback); 42 | class RpcChannel : public ::google::protobuf::RpcChannel 43 | { 44 | public: 45 | RpcChannel(); 46 | 47 | explicit RpcChannel(Conn* conn); 48 | 49 | ~RpcChannel(); 50 | 51 | void setConnection(Conn* conn) 52 | { 53 | conn_ = conn; 54 | } 55 | 56 | void setServices(const std::map* services) 57 | { 58 | services_ = services; 59 | } 60 | 61 | // Call the given method of the remote service. The signature of this 62 | // procedure looks the same as Service::CallMethod(), but the requirements 63 | // are less strict in one important way: the request and response objects 64 | // need not be of any specific class as long as their descriptors are 65 | // method->input_type() and method->output_type(). 66 | void CallMethod(const ::google::protobuf::MethodDescriptor* method, 67 | ::google::protobuf::RpcController* controller, 68 | const ::google::protobuf::Message* request, 69 | ::google::protobuf::Message* response, 70 | ::google::protobuf::Closure* done); 71 | 72 | void onMessage(Conn* conn); 73 | 74 | private: 75 | void onRpcMessage(Conn* conn, const RpcMessagePtr& messagePtr); 76 | 77 | void doneCallback(::google::protobuf::Message* response, int64_t id); 78 | 79 | struct OutstandingCall 80 | { 81 | ::google::protobuf::Message* response; 82 | ::google::protobuf::Closure* done; 83 | }; 84 | 85 | RpcCodec codec_; 86 | Conn* conn_; 87 | AtomicInt64 id_; 88 | 89 | std::mutex mutex_; 90 | std::map outstandings_; 91 | 92 | const std::map* services_; 93 | }; 94 | typedef std::shared_ptr RpcChannelPtr; 95 | 96 | } 97 | 98 | #endif // RPC_RPCCHANNEL_H 99 | -------------------------------------------------------------------------------- /rpc/rpccodec.cc: -------------------------------------------------------------------------------- 1 | #include "rpccodec.h" 2 | #include "tcpserver.h" 3 | #include "rpc.pb.h" 4 | #include "google-inl.h" 5 | 6 | namespace 7 | { 8 | int ProtobufVersionCheck() 9 | { 10 | GOOGLE_PROTOBUF_VERIFY_VERSION; 11 | return 0; 12 | } 13 | int dummy __attribute__ ((unused)) = ProtobufVersionCheck(); 14 | } 15 | 16 | namespace evrpc 17 | { 18 | const char rpctag [] = "RPC0"; 19 | } 20 | -------------------------------------------------------------------------------- /rpc/rpccodec.h: -------------------------------------------------------------------------------- 1 | #ifndef RPC_RPCCODEC_H 2 | #define RPC_RPCCODEC_H 3 | 4 | 5 | #include "codeclite.h" 6 | 7 | namespace evrpc 8 | { 9 | 10 | class Buffer; 11 | class TcpConnection; 12 | typedef std::shared_ptr TcpConnectionPtr; 13 | 14 | class RpcMessage; 15 | typedef std::shared_ptr RpcMessagePtr; 16 | extern const char rpctag[];// = "RPC0"; 17 | 18 | // wire format 19 | // 20 | // Field Length Content 21 | // 22 | // size 4-byte N+8 23 | // "RPC0" 4-byte 24 | // payload N-byte 25 | // checksum 4-byte adler32 of "RPC0"+payload 26 | // 27 | 28 | typedef ProtobufCodecLiteT RpcCodec; 29 | 30 | } 31 | 32 | #endif // MUDUO_NET_PROTORPC_RPCCODEC_H 33 | -------------------------------------------------------------------------------- /rpc/rpcserver.cc: -------------------------------------------------------------------------------- 1 | #include "rpcserver.h" 2 | #include "tcpserver.h" 3 | 4 | #include "rpcchannel.h" 5 | 6 | #include 7 | #include 8 | 9 | using namespace evrpc; 10 | 11 | RpcServer::RpcServer(int threads, 12 | const std::string& ip, int port) 13 | : server_(threads, ip, port) 14 | { 15 | server_.setConnectionCallback(std::bind(&RpcServer::onConnection, this, std::placeholders::_1)); 16 | // server_.setMessageCallback( 17 | // std::bind(&RpcServer::onMessage, this, _1, _2, _3)); 18 | } 19 | 20 | void RpcServer::registerService(google::protobuf::Service* service) 21 | { 22 | const google::protobuf::ServiceDescriptor* desc = service->GetDescriptor(); 23 | services_[desc->full_name()] = service; 24 | } 25 | 26 | void RpcServer::start() 27 | { 28 | server_.startRun(); 29 | } 30 | 31 | void RpcServer::onConnection(Conn* conn) 32 | { 33 | LOG(INFO)<<"Socketfd:"<getFd()<<"\tthreadid:"<getThread()->thread_id<setServices(&services_); 37 | server_.setReadCallback(std::bind(&RpcChannel::onMessage, get_pointer(channel), std::placeholders::_1)); 38 | conn->setContext(channel); 39 | } 40 | 41 | // void RpcServer::onMessage(const Conn* conn) 42 | // { 43 | // RpcChannelPtr& channel = boost::any_cast(conn->getContext()); 44 | // channel->onMessage(conn, buf, time); 45 | // } 46 | 47 | -------------------------------------------------------------------------------- /rpc/rpcserver.h: -------------------------------------------------------------------------------- 1 | #ifndef RPC_RPCSERVER_H 2 | #define RPC_RPCSERVER_H 3 | 4 | #include "tcpserver.h" 5 | #include 6 | 7 | namespace google { 8 | namespace protobuf { 9 | 10 | class Service; 11 | 12 | } // namespace protobuf 13 | } // namespace google 14 | 15 | namespace evrpc 16 | { 17 | 18 | class RpcServer 19 | { 20 | public: 21 | RpcServer(int threads, const std::string& ip, int port); 22 | 23 | void registerService(::google::protobuf::Service*); 24 | void start(); 25 | 26 | private: 27 | void onConnection(Conn* conn); 28 | 29 | // void onMessage(const Conn* conn ); 30 | 31 | TcpServer server_; 32 | std::map services_; 33 | }; 34 | 35 | } 36 | 37 | 38 | #endif // RPC_RPCSERVER_H 39 | -------------------------------------------------------------------------------- /rpc/tcpclient.cc: -------------------------------------------------------------------------------- 1 | #include "tcpclient.h" 2 | #include "tcpserver.h" 3 | #include 4 | 5 | using namespace::evrpc; 6 | 7 | TcpClient::TcpClient(const std::string& ip,int port) 8 | :read_cb_(NULL), write_cb_(NULL), connect_cb_(NULL), event_cb_(NULL), 9 | port_(port), ip_(ip), main_base_() 10 | { 11 | main_base_.thread_id = pthread_self(); 12 | conn_.thread_ = &main_base_; 13 | main_base_.tcp_client = this; 14 | main_base_.base = event_base_new(); 15 | if (!main_base_.base) 16 | throw EkvNetErr(std::string("Client event_base_new error:").append( 17 | evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()))); 18 | 19 | LOG(INFO) << "TcpClient init success"; 20 | } 21 | 22 | TcpClient::~TcpClient() 23 | { 24 | quit(NULL); 25 | event_base_free(main_base_.base); 26 | LOG(INFO)<< "TcpClient dtor"; 27 | } 28 | 29 | void TcpClient::bufferReadCb(struct bufferevent* bev,void* data) 30 | { 31 | Conn* conn = (Conn*)data; 32 | conn->readBuf_ = bufferevent_get_input(bev); 33 | conn->writeBuf_ = bufferevent_get_output(bev); 34 | 35 | LOG(INFO)<<"have data to read"; 36 | 37 | if(conn->getThread()->tcp_client->read_cb_) 38 | conn->getThread()->tcp_client->read_cb_(conn); 39 | } 40 | void TcpClient::bufferWriteCb(struct bufferevent* bev,void* data) 41 | { 42 | Conn* conn = (Conn*)data; 43 | conn->readBuf_ = bufferevent_get_input(bev); 44 | conn->writeBuf_ = bufferevent_get_output(bev); 45 | LOG(INFO)<<"have data to send"; 46 | if(conn->getThread()->tcp_client->write_cb_) 47 | conn->getThread()->tcp_client->write_cb_(conn); 48 | } 49 | void TcpClient::bufferEventCb(struct bufferevent* bev,short events,void* data) 50 | { 51 | Conn *conn = (Conn*)data; 52 | 53 | if (events & BEV_EVENT_EOF){ 54 | LOG(INFO) <<"Connected closed."<fd_ = bufferevent_getfd(bev); 66 | conn->readBuf_ = bufferevent_get_input(bev); 67 | conn->writeBuf_ = bufferevent_get_output(bev); 68 | 69 | if(conn->getThread()->tcp_client->connect_cb_) 70 | conn->getThread()->tcp_client->connect_cb_(conn); 71 | return; 72 | // }else if (EVUTIL_SOCKET_ERROR() == 115){ 73 | // LOG(INFO) <<"info::::::is not connected."<getThread()->tcp_client->event_cb_) 81 | conn->getThread()->tcp_client->event_cb_(conn, events); 82 | 83 | bufferevent_free(bev); 84 | } 85 | void TcpClient::startRun() 86 | { 87 | sockaddr_in sin; 88 | memset(&sin,0,sizeof(sin)); 89 | 90 | sin.sin_family = AF_INET; 91 | sin.sin_port = htons(port_); 92 | if(ip_ != std::string()) 93 | { 94 | if(inet_pton(AF_INET,ip_.c_str(),&sin.sin_addr) <= 0) 95 | throw EkvNetErr("sokcet ip error!"); 96 | } 97 | errno = 0; 98 | conn_.bev_ = bufferevent_socket_new(this->main_base_.base, -1, BEV_OPT_CLOSE_ON_FREE); 99 | if (!conn_.bev_){ 100 | throw EkvNetErr(std::string("New bufferevent socket error:").append( 101 | evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()))); 102 | } 103 | 104 | bufferevent_setcb(conn_.bev_,bufferReadCb,bufferWriteCb,bufferEventCb, &conn_); 105 | bufferevent_enable(conn_.bev_, EV_WRITE|EV_READ); 106 | 107 | if ((bufferevent_socket_connect(conn_.bev_, (struct sockaddr *)(&sin), sizeof(sin))) < 0) 108 | { 109 | bufferevent_free(conn_.bev_); 110 | LOG(ERROR) << "connect to " << ip_ << "error :\n\t" 111 | <readBuf_ = bufferevent_get_input(conn_.bev_); 116 | // conn_->writeBuf_ = bufferevent_get_output(conn_.bev_); 117 | event_base_dispatch(main_base_.base); 118 | 119 | // printf("Finished\n"); 120 | } 121 | 122 | void TcpClient::quit(timeval *tv) 123 | { 124 | bufferevent_free(conn_.bev_); 125 | event_base_loopexit(main_base_.base,tv); 126 | } 127 | 128 | -------------------------------------------------------------------------------- /rpc/tcpclient.h: -------------------------------------------------------------------------------- 1 | #ifndef RPC_TCPCLIENT_H 2 | #define RPC_TCPCLIENT_H 3 | 4 | #include "tcpserver.h" 5 | 6 | namespace evrpc 7 | { 8 | 9 | 10 | class TcpClient: public noncopyable 11 | { 12 | public: 13 | 14 | TcpClient(const std::string& ip,int port = 0); 15 | ~TcpClient(); 16 | 17 | void startRun(); 18 | 19 | void quit(timeval *tv); 20 | 21 | // read enough data then call ReadCallback 22 | void setReadCallback(const DataCallback& cb) 23 | { 24 | read_cb_ =cb; 25 | } 26 | // write enough data the call WriteCallback 27 | void setWriteCallback(const DataCallback& cb) 28 | { 29 | write_cb_ = cb; 30 | } 31 | // add a new conn then call ConnectCallback 32 | void setConnectionCallback(const DataCallback& cb) 33 | { 34 | connect_cb_ = cb; 35 | } 36 | // error then call EventCallback 37 | void setEventCallback(const EventCallback& cb) 38 | { 39 | event_cb_ = cb; 40 | } 41 | 42 | private: 43 | static void* threadProcess(void *arg); 44 | static void notifyHandler(int fd,short which,void* arg); 45 | 46 | 47 | static void acceptCb(evconnlistener* listener,evutil_socket_t fd,sockaddr* sa,int socklen,void *user_data); 48 | 49 | static void bufferReadCb(struct bufferevent* bev,void* data); 50 | static void bufferWriteCb(struct bufferevent* bev,void* data); 51 | static void bufferEventCb(struct bufferevent* bev,short events,void* data); 52 | 53 | DataCallback read_cb_; 54 | DataCallback write_cb_; 55 | DataCallback connect_cb_; 56 | EventCallback event_cb_; 57 | 58 | int port_; 59 | std::string ip_; 60 | Conn conn_; 61 | LibeventThread main_base_; 62 | }; 63 | 64 | 65 | } 66 | #endif // TCPCLIENT_H 67 | -------------------------------------------------------------------------------- /rpc/tcpserver.cc: -------------------------------------------------------------------------------- 1 | #include "tcpserver.h" 2 | 3 | using namespace::evrpc; 4 | 5 | TcpServer::TcpServer(int count, const std::string& ip,int port) 6 | :read_cb_(NULL), write_cb_(NULL), connect_cb_(NULL), event_cb_(NULL), 7 | thread_count_(count), port_(port), ip_(ip), main_base_(new LibeventThread), 8 | threads_(new LibeventThread[thread_count_]) 9 | { 10 | main_base_->thread_id = pthread_self(); 11 | main_base_->base = event_base_new(); 12 | if (!main_base_->base) 13 | throw EkvNetErr(std::string("main thread event_base_new error:").append( 14 | evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()))); 15 | 16 | for(int i=0;i< thread_count_;i++) 17 | { 18 | setupThread(&threads_[i]); 19 | } 20 | LOG(INFO) << "TcpServer init success"; 21 | } 22 | 23 | TcpServer::~TcpServer() 24 | { 25 | quit(NULL); 26 | event_base_free(main_base_->base); 27 | for(int i =0;i< thread_count_;i++) 28 | { 29 | event_base_free(threads_[i].base); 30 | } 31 | delete main_base_; 32 | delete[] threads_; 33 | } 34 | void TcpServer::setupThread(LibeventThread* thread) 35 | { 36 | thread->tcp_server = this; 37 | thread->base = event_base_new(); 38 | if(!thread->base) 39 | throw EkvNetErr(std::string("child thread event_base_new error:").append( 40 | evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()))); 41 | int fds[2]; 42 | if(pipe(fds)) 43 | throw EkvNetErr(std::string("child thread pipe create error:").append(strerror(errno))); 44 | thread->notify_send_fd = fds[1]; 45 | thread->notify_recv_fd = fds[0]; 46 | 47 | event_set(&thread->notify_event,thread->notify_recv_fd,EV_READ|EV_PERSIST,notifyHandler,thread); 48 | event_base_set(thread->base,&thread->notify_event); 49 | if(event_add(&thread->notify_event,0) == -1) 50 | throw EkvNetErr(std::string("child thread add event error:").append( 51 | evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()))); 52 | } 53 | 54 | void TcpServer::notifyHandler(int fd, short which,void* arg) 55 | { 56 | LibeventThread * thread = (LibeventThread*)arg; 57 | 58 | int pipefd = thread->notify_recv_fd; 59 | evutil_socket_t confd; 60 | if(-1 == read(pipefd,&confd,sizeof(evutil_socket_t))) 61 | { 62 | LOG(ERROR)<<"pipe read error:"<base); 68 | LOG(INFO) << "notify pipe recv EXIT_CODE base loopbreak"; 69 | return; 70 | } 71 | 72 | struct bufferevent *bev; 73 | bev = bufferevent_socket_new(thread->base,confd,BEV_OPT_CLOSE_ON_FREE); 74 | if(!bev) 75 | { 76 | LOG(ERROR)<<"bufferevent create with evutil_socket_t error:" << 77 | evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()); 78 | // event_base_loopbreak(thread->base); 79 | return; 80 | } 81 | 82 | // insert new connect to the thread's connection queue 83 | Conn *conn = thread->connect_queue.insertConn(confd,thread); 84 | 85 | conn->bev_ = bev; 86 | conn->thread_ = thread; 87 | // conn->readBuf_ = bufferevent_get_input(bev); 88 | // conn->writeBuf_ = bufferevent_get_output(bev); 89 | 90 | bufferevent_setcb(bev,bufferReadCb,bufferWriteCb,bufferEventCb,conn); 91 | bufferevent_enable(bev,EV_READ|EV_WRITE); 92 | 93 | if(thread->tcp_server->connect_cb_) 94 | thread->tcp_server->connect_cb_(conn); 95 | } 96 | 97 | void* TcpServer::threadProcess(void *arg) 98 | { 99 | LibeventThread *thread = (LibeventThread*)arg; 100 | LOG(INFO)<<"thread "<thread_id <<" started!"; 101 | event_base_dispatch(thread->base); 102 | return NULL; 103 | } 104 | void TcpServer::bufferReadCb(struct bufferevent* bev,void* data) 105 | { 106 | Conn* conn = (Conn*)data; 107 | 108 | conn->readBuf_ = bufferevent_get_input(bev); 109 | conn->writeBuf_ = bufferevent_get_output(bev); 110 | 111 | LOG(INFO)<<"have data to read"; 112 | 113 | if(conn->getThread()->tcp_server->read_cb_) 114 | conn->getThread()->tcp_server->read_cb_(conn); 115 | } 116 | void TcpServer::bufferWriteCb(struct bufferevent* bev,void* data) 117 | { 118 | Conn* conn = (Conn*)data; 119 | conn->readBuf_ = bufferevent_get_input(bev); 120 | conn->writeBuf_ = bufferevent_get_output(bev); 121 | LOG(INFO)<<"have data to send"; 122 | if(conn->getThread()->tcp_server->write_cb_) 123 | conn->getThread()->tcp_server->write_cb_(conn); 124 | } 125 | 126 | void TcpServer::bufferEventCb(struct bufferevent* bev,short events,void* data) 127 | { 128 | if (events & BEV_EVENT_EOF){ 129 | LOG(INFO) <<"Connected closed."<getThread()->tcp_server->event_cb_) 146 | conn->getThread()->tcp_server->event_cb_(conn,events); 147 | conn->getThread()->connect_queue.deleteConn(conn); 148 | bufferevent_free(bev); 149 | } 150 | void TcpServer::startRun() 151 | { 152 | evconnlistener *listener; 153 | 154 | sockaddr_in sin; 155 | memset(&sin,0,sizeof(sin)); 156 | 157 | sin.sin_family = AF_INET; 158 | sin.sin_port = htons(port_); 159 | if(ip_ != std::string()) 160 | { 161 | if(inet_pton(AF_INET,ip_.c_str(),&sin.sin_addr) <= 0) 162 | throw EkvNetErr(std::string("sokcet ip error:").append(strerror(errno))); 163 | } 164 | 165 | listener = evconnlistener_new_bind(main_base_->base,acceptCb,(void*)this,LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE,-1,(sockaddr*)&sin,sizeof(sockaddr_in)); 166 | if(NULL == listener) 167 | throw EkvNetErr(std::string("create listener error:").append(strerror(errno))); 168 | 169 | for(int i=0;ibase); 176 | 177 | evconnlistener_free(listener); 178 | } 179 | 180 | void TcpServer::quit(timeval *tv) 181 | { 182 | int contant = EXIT_CODE; 183 | for(int i=0;ibase,tv); 189 | } 190 | void TcpServer::acceptCb(evconnlistener* listener,evutil_socket_t fd,sockaddr* sa,int socklen,void *user_data) 191 | { 192 | TcpServer *server = (TcpServer*) user_data; 193 | unsigned long num = 0 ; 194 | for(int i=0; i< server->thread_count_; i++){ 195 | num = server->threads_[num].connect_queue.getCount() > server->threads_[i].connect_queue.getCount() ? i : num; 196 | } 197 | write(server->threads_[num].notify_send_fd,&fd,sizeof(evutil_socket_t)); 198 | } 199 | 200 | -------------------------------------------------------------------------------- /rpc/tcpserver.h: -------------------------------------------------------------------------------- 1 | #ifndef RPC_SERVER_H 2 | #define RPC_SERVER_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "util.h" 27 | 28 | 29 | namespace evrpc 30 | { 31 | 32 | class TcpClient; 33 | 34 | 35 | 36 | class EkvNetErr : public std::runtime_error 37 | { 38 | public: 39 | EkvNetErr(const std::string &what_arg):std::runtime_error(what_arg){} 40 | }; 41 | 42 | class TcpServer; 43 | class ConnQueue; 44 | class Conn; 45 | struct LibeventThread; 46 | 47 | 48 | typedef std::function DataCallback; 49 | typedef std::function EventCallback; 50 | 51 | class Conn : public noncopyable 52 | { 53 | friend class ConnQueue; 54 | friend class TcpServer; 55 | friend class TcpClient; 56 | public: 57 | Conn(int fd=0) :fd_(fd),thread_(NULL),bev_(NULL),readBuf_(NULL), 58 | writeBuf_(NULL),pre_(NULL),next_(NULL) { } 59 | 60 | LibeventThread* getThread() {return thread_;} 61 | int getFd() {return fd_;} 62 | bufferevent* getBufferevent() {return bev_;} 63 | uint32_t getReadBufferLen() { return evbuffer_get_length(readBuf_); } 64 | evbuffer* getReadBuffer() { return readBuf_; } 65 | int readBuffer(char* buffer,int len) { return evbuffer_remove(readBuf_,buffer,len); } 66 | int copyBuffer(char *buffer, int len) { return evbuffer_copyout(readBuf_, buffer, len); } 67 | uint32_t getWriteBufferLen() { return evbuffer_get_length(writeBuf_); } 68 | int addToWriteBuffer(char *buffer, int len) { LOG(INFO)<<"add write buffer"; return evbuffer_add(writeBuf_, buffer, len); } 69 | int addBufToWriteBuffer(evbuffer *buf) { return evbuffer_add_buffer(writeBuf_, buf); } 70 | void moveBufferReadToWrite() { evbuffer_add_buffer(writeBuf_, readBuf_); } 71 | void setContext(const Any& context) { context_ = context; } 72 | const Any& getContext() const { return context_; } 73 | Any* getMutableContext() { return &context_; } 74 | 75 | private: 76 | int fd_; 77 | Any context_; 78 | LibeventThread* thread_; 79 | bufferevent *bev_; 80 | evbuffer *readBuf_; 81 | evbuffer *writeBuf_; 82 | 83 | Conn *pre_; 84 | Conn *next_; 85 | }; 86 | 87 | class ConnQueue 88 | { 89 | public: 90 | ConnQueue() : total(0), head_(new Conn(0)), tail_(new Conn(0)) 91 | { 92 | head_->pre_ = tail_->next_ = NULL; 93 | head_->next_ = tail_; tail_->pre_ = head_; 94 | } 95 | ~ConnQueue() 96 | { 97 | Conn *tcur,*tnext; tcur = head_; 98 | while(tcur != NULL) { 99 | tnext = tcur->next_; 100 | delete tcur; 101 | tcur = tnext; 102 | } 103 | } 104 | unsigned long getCount() { return total; } 105 | Conn* insertConn(int fd,LibeventThread* t) 106 | { 107 | Conn *c = new Conn(fd); 108 | c->thread_ = t; 109 | Conn *next = head_->next_; 110 | 111 | c->pre_ = head_; 112 | c->next_ = head_->next_; 113 | head_->next_ = c; 114 | next->pre_ = c; 115 | total++; 116 | return c; 117 | } 118 | void deleteConn(Conn* conn) 119 | { 120 | conn->pre_->next_ = conn->next_; 121 | conn->next_->pre_ = conn->pre_; 122 | delete conn; 123 | total--; 124 | } 125 | private: 126 | unsigned long total; 127 | Conn* head_; 128 | Conn* tail_; 129 | }; 130 | 131 | struct LibeventThread 132 | { 133 | pthread_t thread_id; 134 | struct event_base *base; 135 | struct event notify_event; 136 | int notify_send_fd; 137 | int notify_recv_fd; 138 | ///TODO: 139 | /// not use this. 140 | /// every loop have one queue,but not use 141 | 142 | ConnQueue connect_queue; 143 | //queue connect_queue; 144 | union { 145 | TcpServer *tcp_server; 146 | TcpClient *tcp_client; 147 | }; 148 | //vector tcp_connect; 149 | }; 150 | 151 | 152 | class TcpServer: public noncopyable 153 | { 154 | public: 155 | 156 | static const int EXIT_CODE = -1; 157 | 158 | TcpServer(int count, const std::string& ip,int port = 0); 159 | ~TcpServer(); 160 | 161 | void startRun(); 162 | 163 | void quit(timeval *tv); 164 | 165 | // read enough data then call ReadCallback 166 | void setReadCallback(const DataCallback& cb) 167 | { 168 | read_cb_ =cb; 169 | } 170 | // write enough data the call WriteCallback 171 | void setWriteCallback(const DataCallback& cb) 172 | { 173 | write_cb_ = cb; 174 | } 175 | // add a new conn then call ConnectCallback 176 | void setConnectionCallback(const DataCallback& cb) 177 | { 178 | connect_cb_ = cb; 179 | } 180 | // error then call EventCallback 181 | void setEventCallback(const EventCallback& cb) 182 | { 183 | event_cb_ = cb; 184 | } 185 | 186 | private: 187 | void setupThread(LibeventThread* thread); 188 | static void* threadProcess(void *arg); 189 | static void notifyHandler(int fd,short which,void* arg); 190 | 191 | 192 | static void acceptCb(evconnlistener* listener,evutil_socket_t fd,sockaddr* sa,int socklen,void *user_data); 193 | 194 | static void bufferReadCb(struct bufferevent* bev,void* data); 195 | static void bufferWriteCb(struct bufferevent* bev,void* data); 196 | static void bufferEventCb(struct bufferevent* bev,short events,void* data); 197 | 198 | DataCallback read_cb_; 199 | DataCallback write_cb_; 200 | DataCallback connect_cb_; 201 | EventCallback event_cb_; 202 | 203 | int thread_count_; 204 | int port_; 205 | std::string ip_; 206 | LibeventThread* main_base_; 207 | LibeventThread* threads_; 208 | 209 | 210 | }; 211 | 212 | } 213 | 214 | #endif // EKV_SERVER_H 215 | --------------------------------------------------------------------------------