├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── doc ├── rpc.doc ├── rpc_inspecting.doc └── rpc_message.txt ├── gen_env_conf.sh ├── samples ├── Makefile ├── async_client │ ├── ReadMe.txt │ ├── async_client.cpp │ ├── async_client.vcproj │ ├── stdafx.cpp │ └── stdafx.h ├── async_server │ ├── ReadMe.txt │ ├── async_server.cpp │ ├── async_server.vcproj │ ├── stdafx.cpp │ └── stdafx.h ├── echo.h ├── echo_client │ ├── ReadMe.txt │ ├── echo_client.cpp │ ├── echo_client.vcproj │ ├── echo_client.vcproj.leipeng-PC.leipeng.user │ ├── stdafx.cpp │ └── stdafx.h ├── echo_server │ ├── echo_server.cpp │ ├── echo_server.vcproj │ ├── echo_server.vcproj.leipeng-PC.leipeng.user │ ├── stdafx.cpp │ └── stdafx.h ├── employee.h ├── employee_client │ ├── ReadMe.txt │ ├── employee_client.cpp │ ├── employee_client.vcproj │ ├── employee_client.vcproj.leipeng-PC.leipeng.user │ ├── stdafx.cpp │ └── stdafx.h ├── employee_server │ ├── ReadMe.txt │ ├── employee_server.cpp │ ├── employee_server.vcproj │ ├── employee_server.vcproj.leipeng-PC.leipeng.user │ ├── stdafx.cpp │ └── stdafx.h ├── file_client │ ├── ReadMe.txt │ ├── file_client.cpp │ ├── file_client.vcproj │ ├── stdafx.cpp │ └── stdafx.h ├── file_server │ ├── file_server.cpp │ ├── file_server.vcproj │ ├── stdafx.cpp │ ├── stdafx.h │ └── test.txt ├── ifile.h ├── test.h └── test_rpc.sln └── src └── nark ├── inet ├── MessageInputStream.cpp ├── MessageInputStream.hpp ├── ReactAcceptor.hpp ├── SocketStream.cpp ├── SocketStream.hpp ├── epoll_reactor.hpp └── reactor.hpp ├── io ├── access_byid.cpp └── access_byid.hpp └── rpc ├── arg_traits.hpp ├── client.cpp ├── client.hpp ├── client_io.hpp ├── doxygen_doc.hpp ├── pp_arglist_type.hpp ├── pp_client_stub.hpp ├── pp_server_stub.hpp ├── rpc_basic.cpp ├── rpc_basic.hpp ├── rpc_interface.hpp ├── server.cpp ├── server.hpp ├── server_io.cpp └── server_io.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | DBG_FLAGS ?= -g3 -D_DEBUG 2 | RLS_FLAGS ?= -O3 -DNDEBUG 3 | 4 | ifeq "$(origin LD)" "default" 5 | LD := ${CXX} 6 | endif 7 | 8 | COMPILER := $(shell ${CXX} --version | head -1 | awk '{split($$3, Ver, "."); printf("%s-%d.%d", $$1, Ver[1], Ver[2]);}') 9 | #$(error COMPILER=${COMPILER}) 10 | UNAME_MachineSystem := $(shell uname -m -s | sed 's:[ /]:-:g') 11 | BUILD_ROOT := build/${COMPILER}-${UNAME_MachineSystem} 12 | ddir:=${BUILD_ROOT}/dbg 13 | rdir:=${BUILD_ROOT}/rls 14 | 15 | gen_sh := $(dir $(lastword ${MAKEFILE_LIST}))gen_env_conf.sh 16 | 17 | err := $(shell env BDB_HOME=${BDB_HOME} BOOST_INC=${BOOST_INC} bash ${gen_sh} "${CXX}" ${COMPILER} ${BUILD_ROOT}/env.mk; echo $$?) 18 | ifneq "${err}" "0" 19 | $(error err = ${err} MAKEFILE_LIST = ${MAKEFILE_LIST}, PWD = ${PWD}, gen_sh = ${gen_sh} "${CXX}" ${COMPILER} ${BUILD_ROOT}/env.mk) 20 | endif 21 | 22 | NARK_INC := -Isrc 23 | NARK_INC += -I../nark-bone/src 24 | NARK_INC += -I../nark-hashmap/src 25 | NARK_INC += -I../nark-serialization/src 26 | 27 | include ${BUILD_ROOT}/env.mk 28 | 29 | UNAME_System := $(shell uname | sed 's/^\([0-9a-zA-Z]*\).*/\1/') 30 | ifeq (CYGWIN, ${UNAME_System}) 31 | FPIC = 32 | # lazy expansion 33 | CYGWIN_LDFLAGS = -Wl,--out-implib=$@ \ 34 | -Wl,--export-all-symbols \ 35 | -Wl,--enable-auto-import 36 | DLL_SUFFIX = .dll.a 37 | CYG_DLL_FILE = $(shell echo $@ | sed 's:\(.*\)/lib\([^/]*\)\.a$$:\1/cyg\2:') 38 | else 39 | FPIC = -fPIC 40 | DLL_SUFFIX = .so 41 | CYG_DLL_FILE = $@ 42 | endif 43 | override CFLAGS += ${FPIC} 44 | override CXXFLAGS += ${FPIC} 45 | override LDFLAGS += ${FPIC} 46 | 47 | ifeq "$(shell expr substr ${COMPILER} 1 3)" "g++" 48 | override LDFLAGS += -rdynamic 49 | override CXXFLAGS += -time 50 | ifeq "$(shell echo ${COMPILER} | awk -F- '{if ($$2 >= 4.8) print 1;}')" "1" 51 | CXX_STD := -std=gnu++1y 52 | endif 53 | endif 54 | 55 | ifeq "${CXX_STD}" "" 56 | CXX_STD := -std=gnu++11 57 | endif 58 | 59 | # icc or icpc 60 | ifeq "$(shell expr substr ${COMPILER} 1 2)" "ic" 61 | override CXXFLAGS += -xHost -fasm-blocks 62 | CPU = -xHost 63 | else 64 | CPU = -march=native 65 | COMMON_C_FLAGS += -Wno-deprecated-declarations 66 | COMMON_C_FLAGS += -fstrict-aliasing 67 | COMMON_C_FLAGS += -Wstrict-aliasing=3 68 | endif 69 | 70 | COMMON_C_FLAGS = -Wformat=2 -Wcomment 71 | COMMON_C_FLAGS += -Wall -Wextra 72 | COMMON_C_FLAGS += -Wno-unused-parameter 73 | COMMON_C_FLAGS += -D_GNU_SOURCE 74 | 75 | #-v #-Wall -Wparentheses 76 | #COMMON_C_FLAGS += ${COMMON_C_FLAGS} -Wpacked -Wpadded -v 77 | #COMMON_C_FLAGS += ${COMMON_C_FLAGS} -Winvalid-pch 78 | #COMMON_C_FLAGS += ${COMMON_C_FLAGS} -fmem-report 79 | 80 | ifeq "$(shell expr substr ${COMPILER} 1 5)" "clang" 81 | COMMON_C_FLAGS += -fcolor-diagnostics 82 | endif 83 | 84 | #CXXFLAGS += 85 | #CXXFLAGS += -fpermissive 86 | #CXXFLAGS += -fexceptions 87 | #CXXFLAGS += -fdump-translation-unit -fdump-class-hierarchy 88 | 89 | override CFLAGS += ${COMMON_C_FLAGS} 90 | override CXXFLAGS += ${COMMON_C_FLAGS} 91 | 92 | DEFS := -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE 93 | override CFLAGS += ${DEFS} 94 | override CXXFLAGS += ${DEFS} 95 | 96 | override INCS := ${NARK_INC} ${INCS} 97 | 98 | ifeq (, $(findstring ${BOOST_INC}, ${INCS} /usr/include /usr/local/include)) 99 | override INCS += -I${BOOST_INC} 100 | endif 101 | 102 | ifeq (, $(findstring ${BOOST_LIB}, /usr/lib64 /usr/lib /usr/local/lib)) 103 | override LIBS += -L${BOOST_LIB} 104 | endif 105 | 106 | LIBS += -L../nark-bone/lib 107 | LIBS += -L../nark-serialization/lib 108 | 109 | #override INCS += -I/usr/include 110 | 111 | LIBBOOST ?= \ 112 | -lboost_thread${BOOST_SUFFIX} \ 113 | -lboost_date_time${BOOST_SUFFIX} \ 114 | -lboost_system${BOOST_SUFFIX} 115 | 116 | LIBS += -L/usr/local/lib64 -L/usr/local/lib 117 | LIBS += -L/usr/lib64 -L/usr/lib 118 | 119 | extf = -pie -fno-stack-protector 120 | #extf+=-fno-stack-protector-all 121 | override CFLAGS += ${extf} 122 | #override CFLAGS += -g3 123 | override CXXFLAGS += ${extf} 124 | #override CXXFLAGS += -g3 125 | #CXXFLAGS += -fnothrow-opt 126 | 127 | override INCS += -I${BDB_HOME}/include 128 | LIBS += -L${BDB_HOME}/lib 129 | 130 | ifeq (, ${prefix}) 131 | ifeq (root, ${USER}) 132 | prefix := /usr 133 | else 134 | prefix := /home/${USER} 135 | endif 136 | endif 137 | 138 | #$(warning prefix=${prefix} BDB_HOME=${BDB_HOME}: LIBS=${LIBS}) 139 | 140 | rpc_src := \ 141 | $(wildcard src/nark/util/*.cpp) \ 142 | $(wildcard src/nark/inet/*.cpp) \ 143 | $(wildcard src/nark/io/*.cpp) \ 144 | $(wildcard src/nark/rpc/*.cpp) 145 | 146 | #function definition 147 | #@param:${1} -- targets var prefix, such as bdb_util | bone 148 | #@param:${2} -- build type: d | r 149 | objs = $(addprefix ${${2}dir}/, $(addsuffix .o, $(basename ${${1}_src}))) 150 | 151 | rpc_d_o := $(call objs,rpc,d) 152 | rpc_r_o := $(call objs,rpc,r) 153 | rpc_d := lib/libnark-rpc-${COMPILER}-d${DLL_SUFFIX} 154 | rpc_r := lib/libnark-rpc-${COMPILER}-r${DLL_SUFFIX} 155 | static_rpc_d := lib/libnark-rpc-${COMPILER}-d.a 156 | static_rpc_r := lib/libnark-rpc-${COMPILER}-r.a 157 | 158 | ALL_TARGETS = rpc 159 | DBG_TARGETS = ${rpc_d} 160 | RLS_TARGETS = ${rpc_r} 161 | 162 | .PHONY : rpc 163 | rpc: ${rpc_d} ${rpc_r} ${static_rpc_d} ${static_rpc_r} 164 | 165 | allsrc = ${rpc_src} 166 | alldep = $(addprefix ${rdir}/, $(addsuffix .dep, $(basename ${allsrc}))) \ 167 | $(addprefix ${ddir}/, $(addsuffix .dep, $(basename ${allsrc}))) 168 | 169 | .PHONY : dbg rls 170 | dbg: ${DBG_TARGETS} 171 | rls: ${RLS_TARGETS} 172 | 173 | ${rpc_d} ${rpc_r} : LIBS += ${LIBBOOST} -lpthread 174 | ${rpc_d} : LIBS += -lnark-serialization-${COMPILER}-d -lnark-bone-${COMPILER}-d 175 | ${rpc_r} : LIBS += -lnark-serialization-${COMPILER}-r -lnark-bone-${COMPILER}-r 176 | 177 | ${rpc_d} : $(call objs,rpc,d) 178 | ${rpc_r} : $(call objs,rpc,r) 179 | ${static_rpc_d} : $(call objs,rpc,d) 180 | ${static_rpc_r} : $(call objs,rpc,r) 181 | 182 | %${DLL_SUFFIX}: 183 | @echo "----------------------------------------------------------------------------------" 184 | @echo "Creating dynamic library: $@" 185 | @echo BOOST_INC=${BOOST_INC} BOOST_SUFFIX=${BOOST_SUFFIX} 186 | @echo -e "OBJS:" $(addprefix "\n ",$(sort $(filter %.o,$^))) 187 | @echo -e "LIBS:" $(addprefix "\n ",${LIBS}) 188 | @mkdir -p lib 189 | @ln -sfT $(notdir $@) $(subst -${COMPILER},, $@) 190 | @${LD} -shared $(sort $(filter %.o,$^)) ${LDFLAGS} ${LIBS} -o ${CYG_DLL_FILE} ${CYGWIN_LDFLAGS} 191 | ifeq (CYGWIN, ${UNAME_System}) 192 | @cp -l -f ${CYG_DLL_FILE} /usr/bin 193 | endif 194 | 195 | %.a: 196 | @echo "----------------------------------------------------------------------------------" 197 | @echo "Creating static library: $@" 198 | @echo BOOST_INC=${BOOST_INC} BOOST_SUFFIX=${BOOST_SUFFIX} 199 | @echo -e "OBJS:" $(addprefix "\n ",$(sort $(filter %.o,$^))) 200 | @echo -e "LIBS:" $(addprefix "\n ",${LIBS}) 201 | @mkdir -p lib 202 | @ln -sfT $(notdir $@) $(subst -${COMPILER},, $@) 203 | @${AR} rcs $@ $(filter %.o,$^) 204 | 205 | .PHONY : clean 206 | clean: 207 | -rm -rf lib/libnark* ${BUILD_ROOT} ${PRECOMPILED_HEADER_GCH} 208 | 209 | .PHONY : depends 210 | depends : ${alldep} 211 | 212 | -include ${alldep} 213 | 214 | ${ddir}/%.o: %.cpp 215 | @echo file: $< "->" $@ 216 | @echo NARK_INC=${NARK_INC} 217 | @echo BOOST_INC=${BOOST_INC} BOOST_SUFFIX=${BOOST_SUFFIX} 218 | mkdir -p $(dir $@) 219 | ${CXX} ${CXX_STD} ${CPU} -c ${DBG_FLAGS} ${CXXFLAGS} ${INCS} $< -o $@ 220 | 221 | ${rdir}/%.o: %.cpp 222 | @echo file: $< "->" $@ 223 | @echo NARK_INC=${NARK_INC} 224 | @echo BOOST_INC=${BOOST_INC} BOOST_SUFFIX=${BOOST_SUFFIX} 225 | mkdir -p $(dir $@) 226 | ${CXX} ${CXX_STD} ${CPU} -c ${RLS_FLAGS} ${CXXFLAGS} ${INCS} $< -o $@ 227 | 228 | ${ddir}/%.o: %.cc 229 | @echo file: $< "->" $@ 230 | @echo NARK_INC=${NARK_INC} 231 | @echo BOOST_INC=${BOOST_INC} BOOST_SUFFIX=${BOOST_SUFFIX} 232 | mkdir -p $(dir $@) 233 | ${CXX} ${CXX_STD} ${CPU} -c ${DBG_FLAGS} ${CXXFLAGS} ${INCS} $< -o $@ 234 | 235 | ${rdir}/%.o: %.cc 236 | @echo file: $< "->" $@ 237 | @echo NARK_INC=${NARK_INC} 238 | @echo BOOST_INC=${BOOST_INC} BOOST_SUFFIX=${BOOST_SUFFIX} 239 | mkdir -p $(dir $@) 240 | ${CXX} ${CXX_STD} ${CPU} -c ${RLS_FLAGS} ${CXXFLAGS} ${INCS} $< -o $@ 241 | 242 | ${ddir}/%.o : %.c 243 | @echo file: $< "->" $@ 244 | mkdir -p $(dir $@) 245 | ${CC} -c ${CPU} ${DBG_FLAGS} ${CFLAGS} ${INCS} $< -o $@ 246 | 247 | ${rdir}/%.o : %.c 248 | @echo file: $< "->" $@ 249 | mkdir -p $(dir $@) 250 | ${CC} -c ${CPU} ${RLS_FLAGS} ${CFLAGS} ${INCS} $< -o $@ 251 | 252 | ${ddir}/%.s : %.cpp ${PRECOMPILED_HEADER_GCH} 253 | @echo file: $< "->" $@ 254 | ${CXX} -S ${CPU} ${DBG_FLAGS} ${CXXFLAGS} ${INCS} $< -o $@ 255 | 256 | ${rdir}/%.s : %.cpp ${PRECOMPILED_HEADER_GCH} 257 | @echo file: $< "->" $@ 258 | ${CXX} -S ${CPU} ${RLS_FLAGS} ${CXXFLAGS} ${INCS} $< -o $@ 259 | 260 | ${ddir}/%.s : %.c ${PRECOMPILED_HEADER_GCH} 261 | @echo file: $< "->" $@ 262 | ${CC} -S ${CPU} ${DBG_FLAGS} ${CXXFLAGS} ${INCS} $< -o $@ 263 | 264 | ${rdir}/%.s : %.c ${PRECOMPILED_HEADER_GCH} 265 | @echo file: $< "->" $@ 266 | ${CC} -S ${CPU} ${RLS_FLAGS} ${CXXFLAGS} ${INCS} $< -o $@ 267 | 268 | ${rdir}/%.dep : %.c 269 | @echo file: $< "->" $@ 270 | @echo INCS = ${INCS} 271 | mkdir -p $(dir $@) 272 | ${CC} -M -MT $(basename $@).o ${INCS} $< > $@ 273 | 274 | ${ddir}/%.dep : %.c 275 | @echo file: $< "->" $@ 276 | @echo INCS = ${INCS} 277 | mkdir -p $(dir $@) 278 | ${CC} -M -MT $(basename $@).o ${INCS} $< > $@ 279 | 280 | ${rdir}/%.dep : %.cpp 281 | @echo file: $< "->" $@ 282 | @echo INCS = ${INCS} 283 | mkdir -p $(dir $@) 284 | ${CXX} -M -MT $(basename $@).o ${INCS} $< > $@ 285 | 286 | ${ddir}/%.dep : %.cpp 287 | @echo file: $< "->" $@ 288 | @echo INCS = ${INCS} 289 | mkdir -p $(dir $@) 290 | ${CXX} -M -MT $(basename $@).o ${INCS} $< > $@ 291 | 292 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | nark-rpc 2 | ======== 3 | ## Now the newest version is in [topling-ark](https://github.com/topling/topling-ark) 4 | 5 | RPC(Remote Procedure Call) on top of nark-serialization 6 | 7 | ## Prerequisite 8 | 9 | 10 | 11 | 12 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
boost-1.41 or newer 13 |
    14 |
  • 15 | Require `boost_thread`, `boost_date_time`, `boost_system` to be built 16 |
  • 17 |
  • 18 | Other boost libraries are used as header-only 19 |
  • 20 |
      21 |
nark-serializationRequire binary library
nark-hashmapheader only
nark-boneRequire binary library
36 | 37 | **Note:** All `nark` repositories should be in the same directory. 38 | 39 | ## Compile 40 | 1. Compile `boost_thread`, `boost_date_time`, `boost_system` 41 | 2. Compile 42 | ```bash 43 | $ cd /path/to/nark-bone 44 | $ make 45 | $ cd ../nark-serialization 46 | $ make 47 | $ cd ../nark-rpc 48 | $ make 49 | $ cd samples # /path/to/nark-rpc/samples 50 | $ make 51 | $ build/*/dbg/echo_server/echo_server.exe # run echo server 52 | $ # 53 | $ # open a new terminal 54 | $ build/*/dbg/echo_client/echo_client.exe # run echo client 55 | $ # Have Fun! 56 | ``` 57 | 58 | ## Quick Start 59 | ### IDL 60 | nark-rpc are all in C++, even its IDL is C++, `samples/ifile.h` is a good example: 61 | 62 | ```c++ 63 | BEGIN_RPC_INTERFACE(FileObj, SessionScope) 64 | RPC_ADD_MF(open) 65 | RPC_ADD_MF(read) 66 | RPC_ADD_MF(write) 67 | RPC_ADD_MF(close) 68 | END_RPC_ADD_MF() 69 | RPC_DECLARE_MF(open, (const string& fname, const string& mode)) 70 | RPC_DECLARE_MF(read, (vector* buffer, uint32_t length)) 71 | RPC_DECLARE_MF(write, (const vector& buffer, uint32_t* length)) 72 | RPC_DECLARE_MF(close, ()) 73 | END_RPC_INTERFACE() 74 | ``` 75 | 76 | This can be thought of as nark-rpc's IDL, as it declared, `FileObj` is in `SessionScope`. 77 | 78 | There is another scope: `GlobaleScope`, `samples/echo.h` is such an example: 79 | ```c++ 80 | BEGIN_RPC_INTERFACE(Echo, GlobaleScope) 81 | RPC_ADD_MF(echo) 82 | END_RPC_ADD_MF() 83 | RPC_DECLARE_MF_D(echo, (const string& msg, string* echoFromServer)) 84 | END_RPC_INTERFACE() 85 | ``` 86 | 87 | ### Notes 88 | 1. Function overload is not allowed in IDL. 89 | 2. `RPC_DECLARE_MF` or `RPC_DECLARE_MF_D` should be used consitently in the same RPC interface. 90 | 91 | ### Client 92 | 93 | RPC client just call the (member) functions defined in IDL, the functions seem defined as normal functions. 94 | `RPC_DECLARE_MF` and `RPC_DECLARE_MF_D` are the same at client side. 95 | 96 | See [samples/file\_client/file\_client.cpp](samples/file_client/file_client.cpp#L22)
97 | See [samples/echo\_client/echo\_client.cpp](samples/echo_client/echo_client.cpp#L23) 98 | 99 | ### Server 100 | 101 | RPC server implement the (member) functions, these functions are called by the client through network. 102 | 103 | Writing a RPC server is as simple as writing a normal class: 104 | 105 | Functions declared by `RPC_DECLARE_MF` are **pure virtual**, so you must define an implementation class:
106 | See [samples/file\_server/file\_server.cpp](samples/file_server/file_server.cpp#L24) 107 | 108 | Functions declared by `RPC_DECLARE_MF_D` are not **pure virtual**, `_D` means `Direct`:
109 | See [samples/echo\_server/echo\_server.cpp](samples/echo_server/echo_server.cpp#L24) 110 | 111 | ## More 112 | 113 | To be written... 114 | -------------------------------------------------------------------------------- /doc/rpc.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockeet/nark-rpc/af7ce41ed03ddb8bef3e49572ccf8dd97f27c83e/doc/rpc.doc -------------------------------------------------------------------------------- /doc/rpc_inspecting.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockeet/nark-rpc/af7ce41ed03ddb8bef3e49572ccf8dd97f27c83e/doc/rpc_inspecting.doc -------------------------------------------------------------------------------- /doc/rpc_message.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockeet/nark-rpc/af7ce41ed03ddb8bef3e49572ccf8dd97f27c83e/doc/rpc_message.txt -------------------------------------------------------------------------------- /gen_env_conf.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #set -x 3 | 4 | CXX=$1 5 | COMPILER=$2 6 | EnvConf=$3 7 | echo COMPILER=$COMPILER 1>&2 8 | 9 | #EnvConf=Make.env.conf-${COMPILER} 10 | 11 | rm -f $EnvConf 12 | mkdir -p `dirname $EnvConf` 13 | 14 | hasboost=0 15 | if [ -z "$BOOST_INC" ]; then 16 | boost_prefix="" 17 | else 18 | boost_prefix=`dirname $BOOST_INC` 19 | fi 20 | for dir in "$boost_prefix" /usr /usr/local /opt $HOME $HOME/opt 21 | do 22 | vf=${dir}/include/boost/version.hpp 23 | # echo dir=$dir >&2 24 | if test -s $vf; then 25 | if test -d ${dir}/lib32; then 26 | DIR_LIB32=${dir}/lib32 27 | else 28 | DIR_LIB32=${dir}/lib 29 | fi 30 | if test -d ${dir}/lib64; then 31 | DIR_LIB64=${dir}/lib64 32 | else 33 | DIR_LIB64=${dir}/lib 34 | fi 35 | WORD_BITS=`uname -m | sed 's/.*_\(64\|32\)/\1/'` 36 | DIR_LIB="DIR_LIB${WORD_BITS}" 37 | BOOST_VERSION=`sed -n '/define\s\+BOOST_VERSION/s/^.*BOOST_VERSION\s\+\([0-9]*\).*/\1/p' $vf` 38 | BOOST_LIB_VERSION=`sed -n '/define\s\+BOOST_LIB_VERSION/s/.*BOOST_LIB_VERSION[^"]*"\([0-9_.]*\)".*/\1/p' $vf` 39 | if test -z "$BOOST_SUFFIX"; then 40 | for lib in $DIR_LIB32 $DIR_LIB64; do 41 | for suf in \ 42 | -${COMPILER}-mt-d-${BOOST_LIB_VERSION}.a \ 43 | -${COMPILER}-mt-d-${BOOST_LIB_VERSION}.so \ 44 | -${COMPILER}-mt-d-${BOOST_LIB_VERSION}.so \ 45 | -mt.so \ 46 | -mt.so.5 \ 47 | -mt.so.6 \ 48 | ".a" 49 | do 50 | if test -e $lib/libboost_thread$suf -a -z "$BOOST_SUFFIX"; then 51 | BOOST_SUFFIX=$suf 52 | fi 53 | done 54 | done 55 | if expr match "$BOOST_SUFFIX" '.*\.a$' > /dev/null; then 56 | BOOST_SUFFIX=${BOOST_SUFFIX%.a*} 57 | fi 58 | if expr match "$BOOST_SUFFIX" '.*\.so' > /dev/null; then 59 | BOOST_SUFFIX=${BOOST_SUFFIX%.so*} 60 | fi 61 | fi 62 | cat >> $EnvConf <<- EOF 63 | WORD_BITS := ${WORD_BITS} 64 | DIR_LIB32 := ${DIR_LIB32} 65 | DIR_LIB64 := ${DIR_LIB64} 66 | DIR_LIB := `eval 'echo ${'$DIR_LIB'}'` 67 | BOOST_LIB_VERSION := ${BOOST_LIB_VERSION} 68 | BOOST_INC := ${dir}/include 69 | BOOST_LIB := ${dir}/lib64 70 | BOOST_SUFFIX := ${BOOST_SUFFIX} 71 | EOF 72 | if test "${COMPILER%-*}" = gcc && expr "${COMPILER#*-} < 4.7"; then 73 | if test ${BOOST_VERSION} -lt 104900; then 74 | echo BOOST_VERSION=${BOOST_VERSION} will wrongly define BOOST_DISABLE_THREADS for ${COMPILER} >&2 75 | fi 76 | fi 77 | hasboost=1 78 | break 79 | fi 80 | done 81 | 82 | if [ $hasboost -eq 0 ]; then 83 | echo $'\33[31m\33[1mFATAL: can not find boost\33[0m' 1>&2 84 | exit 1 85 | fi 86 | 87 | cat > is_cygwin.cpp << "EOF" 88 | #include 89 | int main() { 90 | #ifdef __CYGWIN__ 91 | printf("1"); 92 | #else 93 | printf("0"); 94 | #endif 95 | return 0; 96 | } 97 | EOF 98 | if $CXX is_cygwin.cpp -o is_cygwin.exe; then 99 | IS_CYGWIN=`./is_cygwin.exe` 100 | echo IS_CYGWIN=$IS_CYGWIN >> $EnvConf 101 | fi 102 | rm -f is_cygwin.* 103 | 104 | if [ "$IS_CYGWIN" = 0 ]; then 105 | cat > get_glibc_version.cpp << "EOF" 106 | #include 107 | int main() { 108 | printf("%d.%d\n", __GLIBC__, __GLIBC_MINOR__); 109 | return 0; 110 | } 111 | EOF 112 | if $CXX get_glibc_version.cpp -o get_glibc_version.exe; then 113 | GLIBC_VERSION=`./get_glibc_version.exe` 114 | echo GLIBC_VERSION_FULL=${GLIBC_VERSION} >> $EnvConf 115 | echo GLIBC_VERSION_MAJOR=`echo ${GLIBC_VERSION} | cut -d. -f1` >> $EnvConf 116 | echo GLIBC_VERSION_MINOR=`echo ${GLIBC_VERSION} | cut -d. -f2` >> $EnvConf 117 | else 118 | echo "can not detect glibc version" 1>&2 119 | fi 120 | rm -f get_glibc_version.* 121 | fi 122 | 123 | cat > has_inheriting_cons.cpp << "EOF" 124 | struct A { 125 | A(int) {} 126 | A(int,int){} 127 | }; 128 | struct B : public A { 129 | using A::A; 130 | }; 131 | int main() { 132 | B b1(111); 133 | B b2(2,2); 134 | return 0; 135 | } 136 | EOF 137 | rm -f src/nark/my_auto_config.hpp 138 | touch src/nark/my_auto_config.hpp 139 | if $CXX -std=c++11 has_inheriting_cons.cpp > /dev/null 2>&1; then 140 | echo '#define NARK_HAS_INHERITING_CONSTRUCTORS' >> src/nark/my_auto_config.hpp 141 | fi 142 | rm -f has_inheriting_cons.cpp 143 | 144 | if [ "$IS_CYGWIN" -eq 1 ]; then 145 | rm -f a.exe 146 | else 147 | rm -f a.out 148 | fi 149 | 150 | -------------------------------------------------------------------------------- /samples/Makefile: -------------------------------------------------------------------------------- 1 | DBG_FLAGS ?= -g3 -D_DEBUG 2 | RLS_FLAGS ?= -O3 -DNDEBUG 3 | 4 | ifeq "$(origin LD)" "default" 5 | LD := ${CXX} 6 | endif 7 | 8 | COMPILER := $(shell ${CXX} --version | head -1 | awk '{split($$3, Ver, "."); printf("%s-%d.%d", $$1, Ver[1], Ver[2]);}') 9 | #$(error COMPILER=${COMPILER}) 10 | UNAME_MachineSystem := $(shell uname -m -s | sed 's:[ /]:-:g') 11 | BUILD_ROOT := build/${COMPILER}-${UNAME_MachineSystem} 12 | ddir:=${BUILD_ROOT}/dbg 13 | rdir:=${BUILD_ROOT}/rls 14 | 15 | NARK_INC := -I../src \ 16 | -I../../nark-hashmap/src \ 17 | -I../../nark-serialization/src \ 18 | -I../../nark-bone/src 19 | NARK_LIB := -L../lib \ 20 | -L../../nark-serialization/lib \ 21 | -L../../nark-bone/lib 22 | 23 | NARK_LIB_D := ${NARK_LIB} -lnark-rpc-d -lnark-serialization-d -lnark-bone-d 24 | NARK_LIB_R := ${NARK_LIB} -lnark-rpc-r -lnark-serialization-r -lnark-bone-r 25 | 26 | UNAME_System := $(shell uname | sed 's/^\([0-9a-zA-Z]*\).*/\1/') 27 | ifeq (CYGWIN, ${UNAME_System}) 28 | FPIC = 29 | # lazy expansion 30 | CYGWIN_LDFLAGS = -Wl,--out-implib=$@ \ 31 | -Wl,--export-all-symbols \ 32 | -Wl,--enable-auto-import 33 | DLL_SUFFIX = .dll.a 34 | CYG_DLL_FILE = $(shell echo $@ | sed 's:\(.*\)/lib\([^/]*\)\.a$$:\1/cyg\2:') 35 | else 36 | FPIC = -fPIC 37 | DLL_SUFFIX = .so 38 | CYG_DLL_FILE = $@ 39 | endif 40 | override CFLAGS += ${FPIC} 41 | override CXXFLAGS += ${FPIC} 42 | override LDFLAGS += ${FPIC} 43 | 44 | ifeq "$(shell expr substr ${COMPILER} 1 3)" "g++" 45 | override LDFLAGS += -rdynamic 46 | override CXXFLAGS += -time 47 | ifeq "$(shell echo ${COMPILER} | awk -F- '{if ($$2 >= 4.8) print 1;}')" "1" 48 | CXX_STD := -std=gnu++1y 49 | endif 50 | endif 51 | 52 | ifeq "${CXX_STD}" "" 53 | CXX_STD := -std=gnu++11 54 | endif 55 | 56 | # icc or icpc 57 | ifeq "$(shell expr substr ${COMPILER} 1 2)" "ic" 58 | override CXXFLAGS += -xHost -fasm-blocks 59 | CPU = -xHost 60 | else 61 | CPU = -march=native 62 | COMMON_C_FLAGS += -Wno-deprecated-declarations 63 | COMMON_C_FLAGS += -fstrict-aliasing 64 | COMMON_C_FLAGS += -Wstrict-aliasing=3 65 | endif 66 | 67 | COMMON_C_FLAGS = -Wformat=2 -Wcomment 68 | COMMON_C_FLAGS += -Wall -Wextra 69 | COMMON_C_FLAGS += -Wno-unused-parameter 70 | COMMON_C_FLAGS += -D_GNU_SOURCE 71 | 72 | #-v #-Wall -Wparentheses 73 | #COMMON_C_FLAGS += ${COMMON_C_FLAGS} -Wpacked -Wpadded -v 74 | #COMMON_C_FLAGS += ${COMMON_C_FLAGS} -Winvalid-pch 75 | #COMMON_C_FLAGS += ${COMMON_C_FLAGS} -fmem-report 76 | 77 | ifeq "$(shell expr substr ${COMPILER} 1 5)" "clang" 78 | COMMON_C_FLAGS += -fcolor-diagnostics 79 | endif 80 | 81 | #CXXFLAGS += 82 | #CXXFLAGS += -fpermissive 83 | #CXXFLAGS += -fexceptions 84 | #CXXFLAGS += -fdump-translation-unit -fdump-class-hierarchy 85 | 86 | override CFLAGS += ${COMMON_C_FLAGS} 87 | override CXXFLAGS += ${COMMON_C_FLAGS} 88 | 89 | DEFS := -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE 90 | override CFLAGS += ${DEFS} 91 | override CXXFLAGS += ${DEFS} 92 | 93 | INCS = ${NARK_INC} 94 | 95 | LIBBOOST ?= \ 96 | -lboost_thread${BOOST_SUFFIX} \ 97 | -lboost_date_time${BOOST_SUFFIX} \ 98 | -lboost_system${BOOST_SUFFIX} 99 | 100 | LIBS += -L/usr/local/lib64 -L/usr/local/lib 101 | LIBS += -L/usr/lib64 -L/usr/lib 102 | LIBS += -lpthread 103 | LIBS += ${LIBBOOST} 104 | 105 | extf = -pie -fno-stack-protector 106 | #extf+=-fno-stack-protector-all 107 | override CFLAGS += ${extf} 108 | #override CFLAGS += -g3 109 | override CXXFLAGS += ${extf} 110 | #override CXXFLAGS += -g3 111 | #CXXFLAGS += -fnothrow-opt 112 | 113 | allsrc := $(shell find * -name '*.cpp' -not -name 'stdafx.cpp') 114 | alldep := $(addprefix ${rdir}/, $(addsuffix .dep, $(basename ${allsrc}))) \ 115 | $(addprefix ${ddir}/, $(addsuffix .dep, $(basename ${allsrc}))) 116 | 117 | allsrc_d_o := $(addprefix ${ddir}/, $(addsuffix .o, $(basename ${allsrc}))) 118 | allsrc_r_o := $(addprefix ${rdir}/, $(addsuffix .o, $(basename ${allsrc}))) 119 | 120 | #$(warning ${allsrc_d_o} ${allsrc_r_o}) 121 | 122 | .PHONY : all 123 | all : dbg rls 124 | 125 | .PHONY : dbg rls 126 | dbg: $(addsuffix .exe, $(basename ${allsrc_d_o})) 127 | rls: $(addsuffix .exe, $(basename ${allsrc_r_o})) 128 | 129 | .PHONY : clean 130 | clean: 131 | -rm -rf ${BUILD_ROOT} ${PRECOMPILED_HEADER_GCH} 132 | 133 | .PHONY : depends 134 | depends : ${alldep} 135 | 136 | -include ${alldep} 137 | 138 | ${rdir}/%.exe: ${rdir}/%.o 139 | @echo file: $< "->" $@ 140 | mkdir -p $(dir $@) 141 | ${LD} ${DBG_FLAGS} ${CXXFLAGS} $< ${NARK_LIB_R} ${LIBS} -o $@ 142 | 143 | ${ddir}/%.exe: ${ddir}/%.o 144 | @echo file: $< "->" $@ 145 | mkdir -p $(dir $@) 146 | ${LD} ${DBG_FLAGS} ${CXXFLAGS} $< ${NARK_LIB_D} ${LIBS} -o $@ 147 | 148 | ${rdir}/%.o: %.cpp 149 | @echo file: $< "->" $@ 150 | @echo NARK_INC=${NARK_INC} 151 | @echo BOOST_INC=${BOOST_INC} BOOST_SUFFIX=${BOOST_SUFFIX} 152 | mkdir -p $(dir $@) 153 | ${CXX} ${CXX_STD} ${CPU} -c ${RLS_FLAGS} ${CXXFLAGS} ${INCS} $< -o $@ 154 | 155 | ${ddir}/%.o: %.cpp 156 | @echo file: $< "->" $@ 157 | @echo NARK_INC=${NARK_INC} 158 | @echo BOOST_INC=${BOOST_INC} BOOST_SUFFIX=${BOOST_SUFFIX} 159 | mkdir -p $(dir $@) 160 | ${CXX} ${CXX_STD} ${CPU} -c ${DBG_FLAGS} ${CXXFLAGS} ${INCS} $< -o $@ 161 | 162 | ${rdir}/%.o: %.cpp 163 | @echo file: $< "->" $@ 164 | @echo NARK_INC=${NARK_INC} 165 | @echo BOOST_INC=${BOOST_INC} BOOST_SUFFIX=${BOOST_SUFFIX} 166 | mkdir -p $(dir $@) 167 | ${CXX} ${CXX_STD} ${CPU} -c ${RLS_FLAGS} ${CXXFLAGS} ${INCS} $< -o $@ 168 | 169 | ${ddir}/%.o: %.cc 170 | @echo file: $< "->" $@ 171 | @echo NARK_INC=${NARK_INC} 172 | @echo BOOST_INC=${BOOST_INC} BOOST_SUFFIX=${BOOST_SUFFIX} 173 | mkdir -p $(dir $@) 174 | ${CXX} ${CXX_STD} ${CPU} -c ${DBG_FLAGS} ${CXXFLAGS} ${INCS} $< -o $@ 175 | 176 | ${rdir}/%.o: %.cc 177 | @echo file: $< "->" $@ 178 | @echo NARK_INC=${NARK_INC} 179 | @echo BOOST_INC=${BOOST_INC} BOOST_SUFFIX=${BOOST_SUFFIX} 180 | mkdir -p $(dir $@) 181 | ${CXX} ${CXX_STD} ${CPU} -c ${RLS_FLAGS} ${CXXFLAGS} ${INCS} $< -o $@ 182 | 183 | ${ddir}/%.o : %.c 184 | @echo file: $< "->" $@ 185 | mkdir -p $(dir $@) 186 | ${CC} -c ${CPU} ${DBG_FLAGS} ${CFLAGS} ${INCS} $< -o $@ 187 | 188 | ${rdir}/%.o : %.c 189 | @echo file: $< "->" $@ 190 | mkdir -p $(dir $@) 191 | ${CC} -c ${CPU} ${RLS_FLAGS} ${CFLAGS} ${INCS} $< -o $@ 192 | 193 | ${ddir}/%.s : %.cpp ${PRECOMPILED_HEADER_GCH} 194 | @echo file: $< "->" $@ 195 | ${CXX} -S ${CPU} ${DBG_FLAGS} ${CXXFLAGS} ${INCS} $< -o $@ 196 | 197 | ${rdir}/%.s : %.cpp ${PRECOMPILED_HEADER_GCH} 198 | @echo file: $< "->" $@ 199 | ${CXX} -S ${CPU} ${RLS_FLAGS} ${CXXFLAGS} ${INCS} $< -o $@ 200 | 201 | ${ddir}/%.s : %.c ${PRECOMPILED_HEADER_GCH} 202 | @echo file: $< "->" $@ 203 | ${CC} -S ${CPU} ${DBG_FLAGS} ${CXXFLAGS} ${INCS} $< -o $@ 204 | 205 | ${rdir}/%.s : %.c ${PRECOMPILED_HEADER_GCH} 206 | @echo file: $< "->" $@ 207 | ${CC} -S ${CPU} ${RLS_FLAGS} ${CXXFLAGS} ${INCS} $< -o $@ 208 | 209 | ${rdir}/%.dep : %.c 210 | @echo file: $< "->" $@ 211 | @echo INCS = ${INCS} 212 | mkdir -p $(dir $@) 213 | ${CC} -M -MT $(basename $@).o ${INCS} $< > $@ 214 | 215 | ${ddir}/%.dep : %.c 216 | @echo file: $< "->" $@ 217 | @echo INCS = ${INCS} 218 | mkdir -p $(dir $@) 219 | ${CC} -M -MT $(basename $@).o ${INCS} $< > $@ 220 | 221 | ${rdir}/%.dep : %.cpp 222 | @echo file: $< "->" $@ 223 | @echo INCS = ${INCS} 224 | mkdir -p $(dir $@) 225 | ${CXX} -M -MT $(basename $@).o ${INCS} $< > $@ 226 | 227 | ${ddir}/%.dep : %.cpp 228 | @echo file: $< "->" $@ 229 | @echo INCS = ${INCS} 230 | mkdir -p $(dir $@) 231 | ${CXX} -M -MT $(basename $@).o ${INCS} $< > $@ 232 | 233 | -------------------------------------------------------------------------------- /samples/async_client/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | CONSOLE APPLICATION : test_rpc_client Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this test_rpc_client application for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your test_rpc_client application. 9 | 10 | 11 | test_rpc_client.vcproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | test_rpc_client.cpp 18 | This is the main application source file. 19 | 20 | ///////////////////////////////////////////////////////////////////////////// 21 | Other standard files: 22 | 23 | StdAfx.h, StdAfx.cpp 24 | These files are used to build a precompiled header (PCH) file 25 | named test_rpc_client.pch and a precompiled types file named StdAfx.obj. 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | Other notes: 29 | 30 | AppWizard uses "TODO:" comments to indicate parts of the source code you 31 | should add to or customize. 32 | 33 | ///////////////////////////////////////////////////////////////////////////// 34 | -------------------------------------------------------------------------------- /samples/async_client/async_client.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | using namespace nark; 8 | using namespace nark::rpc; 9 | 10 | #include "../test.h" 11 | 12 | #ifdef _MSC_VER 13 | #pragma comment(lib, "Ws2_32.lib") 14 | #endif 15 | 16 | void printVec(const vint_vec& vec) 17 | { 18 | for (size_t i = 0; i != vec.size(); ++i) 19 | { 20 | cout << "vec[" << i << "]=" << vec[i] << "\n"; 21 | } 22 | } 23 | 24 | class AsyncImpl : public AsyncInterface 25 | { 26 | public: 27 | AsyncImpl() 28 | { 29 | this->multiVec.set_async_callback(&AsyncImpl::on_multiVec); 30 | } 31 | private: 32 | void on_multiVec(const client_packet_base& packet, vint_vec& z, vint_vec& x, vint_vec& y) 33 | { 34 | printf("AsyncImpl::on_multiVec\n"); 35 | printf("ret=%u, z=%zu, x=%zu, y=%zu\n", packet.retv, z.size(), x.size(), y.size()); 36 | } 37 | }; 38 | RPC_TYPEDEF_PTR(AsyncImpl); 39 | 40 | int main0(int argc, char* argv[]) 41 | try { 42 | auto_ptr cs(ConnectSocket("127.0.0.1:8001")); 43 | rpc_client client(cs.get()); 44 | 45 | AsyncImplPtr obj1 = client.create("obj1"); 46 | SampleRPC_Interface2Ptr obj2 = client.create("obj2"); 47 | 48 | int ret = client.retrieve(obj2, "obj2"); 49 | (void)ret; 50 | 51 | rpc_ret_t val = obj1->get_val(100); 52 | cout << "obj1->get_val(100)=" << val << "\n"; 53 | 54 | val = obj1->get_len("hello, world!"); 55 | cout << "obj1->get_len(\"hello, world!\")=" << val << "\n"; 56 | 57 | std::vector vec; 58 | vec.push_back((1)); 59 | vec.push_back((2)); 60 | vec.push_back((3)); 61 | vec.push_back((4)); 62 | vec.push_back((11)); 63 | vec.push_back((22)); 64 | vec.push_back((33)); 65 | vec.push_back((44)); 66 | 67 | val = obj1->squareVec(vec); 68 | printVec(vec); 69 | val = obj1->squareVec(vec); 70 | printVec(vec); 71 | 72 | std::vector vec2; 73 | for (size_t i = 0; i != vec.size(); ++i) 74 | { 75 | vec2.push_back(i + 1); 76 | } 77 | // obj1->multiVec.on_return = &AsyncInterface::on_multiVec; 78 | for (size_t i = 0; i < 5; ++i) 79 | { 80 | std::vector vec3; 81 | obj1->multiVec.async(vec3, vec, vec2); 82 | cout << "obj1->multiVec(vec3, vec, vec2) = " << val << "\n"; 83 | printVec(vec3); 84 | } 85 | client.wait_pending_async(); 86 | return 0; 87 | } 88 | catch (const std::exception& exp) 89 | { 90 | printf("exception: what=%s\n", exp.what()); 91 | return 1; 92 | } 93 | 94 | int main(int argc, char* argv[]) 95 | { 96 | #if defined(_WIN32) || defined(_WIN64) 97 | WSADATA information; 98 | WSAStartup(MAKEWORD(2, 2), &information); 99 | int ret = main0(argc, argv); 100 | WSACleanup(); 101 | return ret; 102 | #else 103 | return main0(argc, argv); 104 | #endif 105 | } 106 | 107 | -------------------------------------------------------------------------------- /samples/async_client/async_client.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 55 | 58 | 61 | 64 | 74 | 77 | 80 | 83 | 86 | 89 | 92 | 95 | 96 | 104 | 107 | 110 | 113 | 116 | 119 | 129 | 132 | 135 | 138 | 150 | 153 | 156 | 159 | 162 | 165 | 168 | 171 | 172 | 173 | 174 | 175 | 176 | 181 | 184 | 187 | 191 | 192 | 195 | 199 | 200 | 201 | 204 | 205 | 206 | 211 | 214 | 215 | 218 | 219 | 220 | 225 | 226 | 229 | 230 | 231 | 232 | 233 | 234 | -------------------------------------------------------------------------------- /samples/async_client/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // test_rpc_client.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /samples/async_client/stdafx.h: -------------------------------------------------------------------------------- 1 | #ifndef __stdafx_h__ 2 | #define __stdafx_h__ 3 | 4 | #if defined(_MSC_VER) && (_MSC_VER >= 1020) 5 | # pragma once 6 | #endif 7 | 8 | // stdafx.h : include file for standard system include files, 9 | // or project specific include files that are used frequently, but 10 | // are changed infrequently 11 | // 12 | 13 | 14 | #ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. 15 | #define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. 16 | #endif 17 | 18 | #include 19 | //#include 20 | 21 | 22 | 23 | // TODO: reference additional headers your program requires here 24 | 25 | #endif // __stdafx_h__ 26 | 27 | -------------------------------------------------------------------------------- /samples/async_server/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | CONSOLE APPLICATION : test_rpc_server Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this test_rpc_server application for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your test_rpc_server application. 9 | 10 | 11 | test_rpc_server.vcproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | test_rpc_server.cpp 18 | This is the main application source file. 19 | 20 | ///////////////////////////////////////////////////////////////////////////// 21 | Other standard files: 22 | 23 | StdAfx.h, StdAfx.cpp 24 | These files are used to build a precompiled header (PCH) file 25 | named test_rpc_server.pch and a precompiled types file named StdAfx.obj. 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | Other notes: 29 | 30 | AppWizard uses "TODO:" comments to indicate parts of the source code you 31 | should add to or customize. 32 | 33 | ///////////////////////////////////////////////////////////////////////////// 34 | -------------------------------------------------------------------------------- /samples/async_server/async_server.cpp: -------------------------------------------------------------------------------- 1 | // test_rpc_server.cpp : Defines the entry point for the console application. 2 | // 3 | 4 | #include "stdafx.h" 5 | 6 | #ifdef _MSC_VER 7 | #pragma warning(disable: 4251) // needs to have dll-interface 8 | #pragma warning(disable: 4267) // conversion from 'size_t' to 'long', possible loss of data 9 | #pragma warning(disable: 4244) // conversion from '__w64 const unsigned int' to 'unsigned int', possible loss of data 10 | #pragma comment(lib, "Ws2_32.lib") 11 | #endif 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | using namespace nark; 18 | using namespace nark::rpc; 19 | 20 | #include "../test.h" 21 | 22 | // use macro for convenient 23 | BEGIN_RPC_IMP_INTERFACE(SampleRPC_Imp1, AsyncInterface) 24 | rpc_ret_t get_val(rpc_in x) 25 | { 26 | std::cout << "AsyncInterface::get_val(rpc_in x=" << x.r << ")\n"; 27 | return x.r; 28 | } 29 | rpc_ret_t get_len(const std::string& x) 30 | { 31 | std::cout << "AsyncInterface::get_len(const std::string& x=\"" << x << "\")\n"; 32 | return x.size(); 33 | } 34 | rpc_ret_t squareVec(vint_vec& x) 35 | { 36 | for (vint_vec::iterator i = x.begin(); i != x.end(); ++i) 37 | { 38 | *i *= *i; 39 | } 40 | return x.size(); 41 | } 42 | rpc_ret_t multiVec(vint_vec& z, vint_vec& x, vint_vec& y) 43 | { 44 | z.clear(); 45 | for (size_t i = 0; i != x.size(); ++i) 46 | { 47 | z.push_back(x[i] * y[i]); 48 | } 49 | return 0x12345678; 50 | } 51 | END_RPC_IMP_INTERFACE() 52 | 53 | // don't use macro for more control 54 | class SampleRPC_Imp2 : public SampleRPC_Interface2 55 | { 56 | rpc_ret_t get_val(rpc_in x) 57 | { 58 | std::cout << BOOST_CURRENT_FUNCTION << "x=" < server(&acceptor); 82 | 83 | // register rpc implementation class... 84 | RPC_SERVER_AUTO_CREATE(server, SampleRPC_Imp1); 85 | server.auto_create((SampleRPC_Imp2*)0, &SampleRPC_Imp2::create); 86 | 87 | server.start(); 88 | } 89 | catch (const std::exception& exp) 90 | { 91 | printf("exception: what=%s\n", exp.what()); 92 | } 93 | return 0; 94 | } 95 | 96 | int main(int argc, char* argv[]) 97 | { 98 | #if defined(_WIN32) || defined(_WIN64) 99 | WSADATA information; 100 | WSAStartup(MAKEWORD(2, 2), &information); 101 | int ret = main0(argc, argv); 102 | WSACleanup(); 103 | return ret; 104 | #else 105 | return main0(argc, argv); 106 | #endif 107 | } 108 | 109 | -------------------------------------------------------------------------------- /samples/async_server/async_server.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 54 | 57 | 60 | 63 | 73 | 76 | 79 | 82 | 85 | 88 | 91 | 94 | 95 | 103 | 106 | 109 | 112 | 115 | 118 | 128 | 131 | 134 | 137 | 149 | 152 | 155 | 158 | 161 | 164 | 167 | 170 | 171 | 172 | 173 | 174 | 175 | 180 | 183 | 186 | 190 | 191 | 194 | 198 | 199 | 200 | 203 | 204 | 205 | 210 | 213 | 214 | 217 | 218 | 219 | 224 | 225 | 228 | 229 | 230 | 231 | 232 | 233 | -------------------------------------------------------------------------------- /samples/async_server/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // test_rpc_server.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /samples/async_server/stdafx.h: -------------------------------------------------------------------------------- 1 | #ifndef __stdafx_h__ 2 | #define __stdafx_h__ 3 | 4 | #if defined(_MSC_VER) && (_MSC_VER >= 1020) 5 | # pragma once 6 | #endif 7 | 8 | // stdafx.h : include file for standard system include files, 9 | // or project specific include files that are used frequently, but 10 | // are changed infrequently 11 | // 12 | 13 | 14 | #ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. 15 | #define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. 16 | #endif 17 | 18 | #include 19 | //#include 20 | 21 | 22 | 23 | // TODO: reference additional headers your program requires here 24 | 25 | #endif // __stdafx_h__ 26 | 27 | -------------------------------------------------------------------------------- /samples/echo.h: -------------------------------------------------------------------------------- 1 | 2 | // sample usage... 3 | // echo.h 4 | 5 | BEGIN_RPC_INTERFACE(Echo, GlobaleScope) 6 | RPC_ADD_MF(echo) 7 | END_RPC_ADD_MF() 8 | RPC_DECLARE_MF_D(echo, (const std::string& msg, std::string* y)) 9 | END_RPC_INTERFACE() 10 | 11 | -------------------------------------------------------------------------------- /samples/echo_client/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | CONSOLE APPLICATION : test_rpc_client Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this test_rpc_client application for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your test_rpc_client application. 9 | 10 | 11 | test_rpc_client.vcproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | test_rpc_client.cpp 18 | This is the main application source file. 19 | 20 | ///////////////////////////////////////////////////////////////////////////// 21 | Other standard files: 22 | 23 | StdAfx.h, StdAfx.cpp 24 | These files are used to build a precompiled header (PCH) file 25 | named test_rpc_client.pch and a precompiled types file named StdAfx.obj. 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | Other notes: 29 | 30 | AppWizard uses "TODO:" comments to indicate parts of the source code you 31 | should add to or customize. 32 | 33 | ///////////////////////////////////////////////////////////////////////////// 34 | -------------------------------------------------------------------------------- /samples/echo_client/echo_client.cpp: -------------------------------------------------------------------------------- 1 | // echo_client.cpp : Defines the entry point for the console application. 2 | // 3 | 4 | #include "stdafx.h" 5 | 6 | #ifdef _MSC_VER 7 | #pragma comment(lib, "Ws2_32.lib") 8 | #endif 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | using namespace nark; 17 | using namespace nark::rpc; 18 | 19 | #include "../echo.h" 20 | 21 | int main0(int argc, char* argv[]) 22 | try { 23 | auto_ptr cs(ConnectSocket("127.0.0.1:8001")); 24 | rpc_client client(cs.get()); 25 | EchoPtr ec = client.create("echo"); 26 | while (!cin.eof()) 27 | { 28 | string msg, y; 29 | cin >> msg; 30 | ec->echo(msg, &y); 31 | cout << "msg:" << msg << endl; 32 | cout << "y__:" << y << endl; 33 | } 34 | return 0; 35 | } 36 | catch (const std::exception& exp) 37 | { 38 | printf("exception: what=%s\n", exp.what()); 39 | return 1; 40 | } 41 | 42 | int main(int argc, char* argv[]) 43 | { 44 | #if defined(_WIN32) || defined(_WIN64) 45 | WSADATA information; 46 | WSAStartup(MAKEWORD(2, 2), &information); 47 | int ret = main0(argc, argv); 48 | WSACleanup(); 49 | return ret; 50 | #else 51 | return main0(argc, argv); 52 | #endif 53 | } 54 | 55 | -------------------------------------------------------------------------------- /samples/echo_client/echo_client.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 55 | 58 | 61 | 64 | 74 | 77 | 80 | 83 | 86 | 89 | 92 | 95 | 96 | 104 | 107 | 110 | 113 | 116 | 119 | 129 | 132 | 135 | 138 | 150 | 153 | 156 | 159 | 162 | 165 | 168 | 171 | 172 | 173 | 174 | 175 | 176 | 181 | 184 | 185 | 188 | 191 | 195 | 196 | 199 | 203 | 204 | 205 | 206 | 211 | 214 | 215 | 218 | 219 | 220 | 225 | 226 | 229 | 230 | 231 | 232 | 233 | 234 | -------------------------------------------------------------------------------- /samples/echo_client/echo_client.vcproj.leipeng-PC.leipeng.user: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 35 | 36 | 39 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /samples/echo_client/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // echo_client.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /samples/echo_client/stdafx.h: -------------------------------------------------------------------------------- 1 | #ifndef __stdafx_h__ 2 | #define __stdafx_h__ 3 | 4 | #if defined(_MSC_VER) && (_MSC_VER >= 1020) 5 | # pragma once 6 | #endif 7 | 8 | // stdafx.h : include file for standard system include files, 9 | // or project specific include files that are used frequently, but 10 | // are changed infrequently 11 | // 12 | 13 | 14 | #ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. 15 | #define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. 16 | #endif 17 | 18 | #include 19 | //#include 20 | 21 | 22 | 23 | // TODO: reference additional headers your program requires here 24 | 25 | #endif // __stdafx_h__ 26 | 27 | -------------------------------------------------------------------------------- /samples/echo_server/echo_server.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockeet/nark-rpc/af7ce41ed03ddb8bef3e49572ccf8dd97f27c83e/samples/echo_server/echo_server.cpp -------------------------------------------------------------------------------- /samples/echo_server/echo_server.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 54 | 57 | 60 | 63 | 73 | 76 | 79 | 82 | 85 | 88 | 91 | 94 | 95 | 103 | 106 | 109 | 112 | 115 | 118 | 128 | 131 | 134 | 137 | 149 | 152 | 155 | 158 | 161 | 164 | 167 | 170 | 171 | 172 | 173 | 174 | 175 | 180 | 183 | 184 | 187 | 190 | 194 | 195 | 198 | 202 | 203 | 204 | 205 | 210 | 213 | 214 | 217 | 218 | 219 | 224 | 225 | 228 | 229 | 230 | 231 | 232 | 233 | -------------------------------------------------------------------------------- /samples/echo_server/echo_server.vcproj.leipeng-PC.leipeng.user: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 35 | 36 | 39 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /samples/echo_server/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // test_rpc_server.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /samples/echo_server/stdafx.h: -------------------------------------------------------------------------------- 1 | #ifndef __stdafx_h__ 2 | #define __stdafx_h__ 3 | 4 | #if defined(_MSC_VER) && (_MSC_VER >= 1020) 5 | # pragma once 6 | #endif 7 | 8 | // stdafx.h : include file for standard system include files, 9 | // or project specific include files that are used frequently, but 10 | // are changed infrequently 11 | // 12 | 13 | 14 | #ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. 15 | #define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. 16 | #endif 17 | 18 | #include 19 | //#include 20 | 21 | 22 | 23 | // TODO: reference additional headers your program requires here 24 | 25 | #endif // __stdafx_h__ 26 | 27 | -------------------------------------------------------------------------------- /samples/employee.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | using namespace nark; 5 | using namespace nark::rpc; 6 | 7 | struct Employee 8 | { 9 | typedef unsigned key_type; // for id, used by kmapdset 10 | 11 | std::string name, department; 12 | unsigned id; 13 | 14 | void print(ostream& os) const 15 | { 16 | os << "id=" << dec << id << "[" << hex << id << "]" 17 | << ", name=" << name << ", department=" << department << endl; 18 | } 19 | #ifdef _DEBUG 20 | // for set break point and step into 21 | friend 22 | void DataIO_loadObject(PortableDataInput& dio, Employee& x) 23 | { 24 | dio >> x.name; 25 | dio >> x.department; 26 | dio >> x.id; 27 | } 28 | friend 29 | void DataIO_loadObject(PortableDataInput& dio, Employee& x) 30 | { 31 | dio >> x.name; 32 | dio >> x.department; 33 | dio >> x.id; 34 | } 35 | template 36 | friend 37 | void DataIO_loadObject(DataIO& dio, Employee& x) 38 | { 39 | dio >> x.name; 40 | dio >> x.department; 41 | dio >> x.id; 42 | } 43 | template 44 | friend 45 | void DataIO_saveObject(DataIO& dio, const Employee& x) 46 | { 47 | dio << x.name; 48 | dio << x.department; 49 | dio << x.id; 50 | } 51 | friend 52 | void DataIO_loadObject(PortableDataInput& dio, Employee& x) 53 | { 54 | dio >> x.name; 55 | dio >> x.department; 56 | dio >> x.id; 57 | } 58 | friend 59 | void DataIO_saveObject(PortableDataOutput& dio, const Employee& x) 60 | { 61 | dio << x.name; 62 | dio << x.department; 63 | dio << x.id; 64 | } 65 | #else 66 | DATA_IO_LOAD_SAVE(Employee, &name&department&id) 67 | #endif 68 | }; 69 | 70 | BEGIN_RPC_INTERFACE(DbEmployee, GlobaleScope) 71 | RPC_ADD_MF(fillData) 72 | RPC_ADD_MF(getByID) 73 | RPC_ADD_MF(getByName) 74 | RPC_ADD_MF(getByDepartment) 75 | END_RPC_ADD_MF() 76 | RPC_DECLARE_MF(fillData, ()) 77 | RPC_DECLARE_MF(getByID, (unsigned id, Employee& em)) 78 | RPC_DECLARE_MF(getByName, (const std::string& name, std::vector& ems)) // maybe multi employee has same 79 | RPC_DECLARE_MF(getByDepartment, (const std::string& name, std::vector& ems)) 80 | END_RPC_INTERFACE() 81 | -------------------------------------------------------------------------------- /samples/employee_client/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | CONSOLE APPLICATION : employee_client Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this employee_client application for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your employee_client application. 9 | 10 | 11 | employee_client.vcproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | employee_client.cpp 18 | This is the main application source file. 19 | 20 | ///////////////////////////////////////////////////////////////////////////// 21 | Other standard files: 22 | 23 | StdAfx.h, StdAfx.cpp 24 | These files are used to build a precompiled header (PCH) file 25 | named employee_client.pch and a precompiled types file named StdAfx.obj. 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | Other notes: 29 | 30 | AppWizard uses "TODO:" comments to indicate parts of the source code you 31 | should add to or customize. 32 | 33 | ///////////////////////////////////////////////////////////////////////////// 34 | -------------------------------------------------------------------------------- /samples/employee_client/employee_client.cpp: -------------------------------------------------------------------------------- 1 | // employee_client.cpp : Defines the entry point for the console application. 2 | // 3 | 4 | #include "stdafx.h" 5 | #ifdef _MSC_VER 6 | #pragma comment(lib, "Ws2_32.lib") 7 | #endif 8 | 9 | #include 10 | #include "../employee.h" 11 | 12 | int main0(int argc, char* argv[]) 13 | try { 14 | auto_ptr cs(ConnectSocket("127.0.0.1:8001")); 15 | rpc_client client(cs.get()); 16 | 17 | DbEmployeePtr dbem = client.create("DbEmployeeObject"); 18 | 19 | Employee em; 20 | vector ems; 21 | rpc_ret_t ret; 22 | ret = dbem->fillData(); 23 | if (0 == ret) 24 | { 25 | cout << "fillData success\n"; 26 | } 27 | for (;;) 28 | { 29 | cout << "getByID:\n"; 30 | ret = dbem->getByID(1, em); 31 | if (0 == ret) 32 | { 33 | em.print(cout); 34 | } 35 | cout << "getByName:\n"; 36 | ret = dbem->getByName("leipeng", ems); 37 | if (0 == ret) 38 | { 39 | for (vector::const_iterator i = ems.begin(); i != ems.end(); ++i) 40 | i->print(cout); 41 | } 42 | cout << "getByDepartment:\n"; 43 | ret = dbem->getByDepartment("tech", ems); 44 | if (0 == ret) 45 | { 46 | for (vector::const_iterator i = ems.begin(); i != ems.end(); ++i) 47 | i->print(cout); 48 | } 49 | else 50 | { 51 | cout << "failed, ret=" << ret << endl; 52 | } 53 | if (getchar() == EOF) 54 | break; 55 | } 56 | return 0; 57 | } 58 | catch (const std::exception& exp) 59 | { 60 | printf("exception: what=%s\n", exp.what()); 61 | return 1; 62 | } 63 | 64 | int main(int argc, char* argv[]) 65 | { 66 | #if defined(_WIN32) || defined(_WIN64) 67 | WSADATA information; 68 | WSAStartup(MAKEWORD(2, 2), &information); 69 | int ret = main0(argc, argv); 70 | WSACleanup(); 71 | return ret; 72 | #else 73 | return main0(argc, argv); 74 | #endif 75 | } 76 | 77 | -------------------------------------------------------------------------------- /samples/employee_client/employee_client.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 53 | 56 | 59 | 62 | 70 | 73 | 76 | 79 | 82 | 85 | 88 | 91 | 92 | 100 | 103 | 106 | 109 | 112 | 115 | 126 | 129 | 132 | 135 | 145 | 148 | 151 | 154 | 157 | 160 | 163 | 166 | 167 | 168 | 169 | 170 | 171 | 176 | 179 | 180 | 183 | 186 | 190 | 191 | 194 | 198 | 199 | 200 | 201 | 206 | 209 | 210 | 213 | 214 | 215 | 220 | 221 | 224 | 225 | 226 | 227 | 228 | 229 | -------------------------------------------------------------------------------- /samples/employee_client/employee_client.vcproj.leipeng-PC.leipeng.user: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 35 | 36 | 39 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /samples/employee_client/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // employee_client.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /samples/employee_client/stdafx.h: -------------------------------------------------------------------------------- 1 | #ifndef __stdafx_h__ 2 | #define __stdafx_h__ 3 | 4 | #if defined(_MSC_VER) && (_MSC_VER >= 1020) 5 | # pragma once 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | 15 | #endif // __stdafx_h__ 16 | -------------------------------------------------------------------------------- /samples/employee_server/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | CONSOLE APPLICATION : employee_server Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this employee_server application for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your employee_server application. 9 | 10 | 11 | employee_server.vcproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | employee_server.cpp 18 | This is the main application source file. 19 | 20 | ///////////////////////////////////////////////////////////////////////////// 21 | Other standard files: 22 | 23 | StdAfx.h, StdAfx.cpp 24 | These files are used to build a precompiled header (PCH) file 25 | named employee_server.pch and a precompiled types file named StdAfx.obj. 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | Other notes: 29 | 30 | AppWizard uses "TODO:" comments to indicate parts of the source code you 31 | should add to or customize. 32 | 33 | ///////////////////////////////////////////////////////////////////////////// 34 | -------------------------------------------------------------------------------- /samples/employee_server/employee_server.cpp: -------------------------------------------------------------------------------- 1 | // employee_server.cpp : Defines the entry point for the console application. 2 | // 3 | 4 | #include "stdafx.h" 5 | 6 | #ifdef _MSC_VER 7 | #pragma comment(lib, "Ws2_32.lib") 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | #include "../employee.h" 14 | 15 | // not need auto create 16 | class DbEmployeeImp : public DbEmployee 17 | { 18 | private: 19 | #ifdef EMPLOYEE_USE_BDB 20 | DbEnv m_env; 21 | auto_ptr > m_byID; 22 | auto_ptr > m_byName, m_byDepartment; 23 | #else 24 | int m_env; // dummy 25 | std::map m_byID; 26 | std::map > m_byName, m_byDepartment; 27 | #endif 28 | 29 | public: 30 | DbEmployeeImp() : m_env(0) 31 | { 32 | #ifdef EMPLOYEE_USE_BDB 33 | u_int32_t envFlags = 0 34 | |DB_CREATE 35 | |DB_THREAD 36 | |DB_INIT_MPOOL 37 | ; 38 | // printf("open env\n"); 39 | m_env.open("db", envFlags, 0); 40 | // printf("open env success\n"); 41 | m_byID.reset(new dbmap(&m_env, "byid")); 42 | m_byName.reset(new kmapdset(&m_env, "byname")); 43 | m_byDepartment.reset(new kmapdset(&m_env, "bydepartment")); 44 | #endif 45 | } 46 | 47 | rpc_ret_t fillData() 48 | { 49 | Employee e; 50 | e.id = 1; 51 | e.name = "leipeng"; 52 | e.department = "tech"; 53 | #ifdef EMPLOYEE_USE_BDB 54 | m_byID->insert(e.id, e); 55 | m_byName->insert(e.name, e); 56 | m_byDepartment->insert(e.department, e); 57 | #else 58 | m_byID[e.id] = e; 59 | m_byName[e.name].push_back(e); 60 | m_byDepartment[e.department].push_back(e); 61 | #endif 62 | // BOOST_CURRENT_FUNCTION/BOOST_STATIC_CONSTANT 63 | // WM_ACTIVATETOPLEVEL 64 | // CreateFile 65 | // abcdefghijklmnopqrstuvwxyz 66 | return 0; 67 | } 68 | 69 | rpc_ret_t getByID(unsigned id, Employee& em) 70 | { 71 | #ifdef EMPLOYEE_USE_BDB 72 | dbmap::iterator iter = m_byID->find(id); 73 | if (iter.exist()) 74 | { 75 | em = iter->second; 76 | return 0; 77 | } 78 | #else 79 | std::map::iterator iter = m_byID.find(id); 80 | if (m_byID.end() == iter) { 81 | em = iter->second; 82 | return 0; 83 | } 84 | #endif 85 | return 1; // not found 86 | } 87 | 88 | rpc_ret_t getByName(const string& name, std::vector& em) 89 | { 90 | #ifdef EMPLOYEE_USE_BDB 91 | kmapdset::iterator iter = m_byName->find(name); 92 | if (iter.exist()) 93 | { 94 | em.swap(iter.get_mutable().second); 95 | return 0; 96 | } 97 | #else 98 | std::map >::iterator iter = m_byName.find(name); 99 | if (m_byName.end() != iter) { 100 | em = iter->second; 101 | return 0; 102 | } 103 | #endif 104 | return 1; // not found 105 | } 106 | 107 | rpc_ret_t getByDepartment(const string& department, std::vector& em) 108 | { 109 | #ifdef EMPLOYEE_USE_BDB 110 | kmapdset::iterator iter = m_byDepartment->find(department); 111 | if (iter.exist()) 112 | { 113 | em.swap(iter.get_mutable().second); 114 | return 0; 115 | } 116 | #else 117 | std::map >::iterator iter = m_byDepartment.find(department); 118 | if (m_byDepartment.end() != iter) { 119 | em = iter->second; 120 | return 0; 121 | } 122 | #endif 123 | return 1; // not found 124 | } 125 | }; 126 | 127 | int main0(int argc, char* argv[]) 128 | { 129 | try { 130 | SocketAcceptor acceptor("0.0.0.0:8001"); 131 | rpc_server server(&acceptor); 132 | 133 | server.add_servant( 134 | new DbEmployeeImp, 135 | "DbEmployeeObject", 136 | 0 // 0 will not auto create GlobaleScope Object 137 | ); 138 | server.start(); 139 | } 140 | catch (const std::exception& exp) 141 | { 142 | printf("exception: what=%s\n", exp.what()); 143 | } 144 | return 0; 145 | } 146 | 147 | int main(int argc, char* argv[]) 148 | { 149 | #if defined(_WIN32) || defined(_WIN64) 150 | WSADATA information; 151 | WSAStartup(MAKEWORD(2, 2), &information); 152 | int ret = main0(argc, argv); 153 | WSACleanup(); 154 | return ret; 155 | #else 156 | return main0(argc, argv); 157 | #endif 158 | } 159 | 160 | -------------------------------------------------------------------------------- /samples/employee_server/employee_server.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 53 | 56 | 59 | 62 | 70 | 73 | 76 | 79 | 82 | 85 | 88 | 91 | 92 | 100 | 103 | 106 | 109 | 112 | 115 | 126 | 129 | 132 | 135 | 145 | 148 | 151 | 154 | 157 | 160 | 163 | 166 | 167 | 168 | 169 | 170 | 171 | 176 | 179 | 180 | 183 | 186 | 190 | 191 | 194 | 198 | 199 | 200 | 201 | 206 | 209 | 210 | 213 | 214 | 215 | 220 | 221 | 224 | 225 | 226 | 227 | 228 | 229 | -------------------------------------------------------------------------------- /samples/employee_server/employee_server.vcproj.leipeng-PC.leipeng.user: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 35 | 36 | 39 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /samples/employee_server/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // employee_server.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /samples/employee_server/stdafx.h: -------------------------------------------------------------------------------- 1 | #ifndef __stdafx_h__ 2 | #define __stdafx_h__ 3 | 4 | #if defined(_MSC_VER) && (_MSC_VER >= 1020) 5 | # pragma once 6 | #endif 7 | 8 | #include 9 | #include 10 | 11 | #ifdef EMPLOYEE_USE_BDB 12 | #include 13 | #include 14 | #include 15 | #else 16 | #include 17 | #include 18 | #endif 19 | 20 | #endif // __stdafx_h__ 21 | -------------------------------------------------------------------------------- /samples/file_client/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | CONSOLE APPLICATION : test_rpc_client Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this test_rpc_client application for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your test_rpc_client application. 9 | 10 | 11 | test_rpc_client.vcproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | test_rpc_client.cpp 18 | This is the main application source file. 19 | 20 | ///////////////////////////////////////////////////////////////////////////// 21 | Other standard files: 22 | 23 | StdAfx.h, StdAfx.cpp 24 | These files are used to build a precompiled header (PCH) file 25 | named test_rpc_client.pch and a precompiled types file named StdAfx.obj. 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | Other notes: 29 | 30 | AppWizard uses "TODO:" comments to indicate parts of the source code you 31 | should add to or customize. 32 | 33 | ///////////////////////////////////////////////////////////////////////////// 34 | -------------------------------------------------------------------------------- /samples/file_client/file_client.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | #ifdef _MSC_VER 4 | #pragma warning(disable: 4251) // needs to have dll-interface 5 | #pragma warning(disable: 4267) // conversion from 'size_t' to 'long', possible loss of data 6 | #pragma warning(disable: 4244) // conversion from '__w64 const unsigned int' to 'unsigned int', possible loss of data 7 | #pragma comment(lib, "Ws2_32.lib") 8 | #endif 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | using namespace nark; 16 | using namespace nark::rpc; 17 | 18 | #include "../ifile.h" 19 | 20 | int main0(int argc, char* argv[]) 21 | try { 22 | auto_ptr cs(ConnectSocket("127.0.0.1:8001")); 23 | rpc_client client(cs.get()); 24 | FileObjPtr file = client.create(); 25 | string fname = "test.txt"; 26 | vector buffer; 27 | int ret = file->open(fname, "w+"); 28 | if (0 == ret) 29 | { 30 | printf("open file for write successed\n"); 31 | string txt = "Hello, world, this is a test file\n"; 32 | buffer.resize(txt.size()); 33 | std::copy(txt.begin(), txt.end(), buffer.begin()); 34 | uint32_t nWritten; 35 | file->write(buffer, &nWritten); 36 | printf("write=%zd, written=%d\n", buffer.size(), nWritten); 37 | file->close(); 38 | } 39 | ret = file->open("test.txt", "r"); 40 | if (0 == ret) 41 | { 42 | printf("open file for read successed\n"); 43 | uint32_t nRead = buffer.size(); 44 | file->read(&buffer, nRead); 45 | printf("read=%d, readed=%zd\n", nRead, buffer.size()); 46 | string txt; 47 | txt.resize(buffer.size()); 48 | std::copy(buffer.begin(), buffer.end(), txt.begin()); 49 | printf("readed text=%s\n", txt.c_str()); 50 | } 51 | else 52 | { 53 | printf("open file for read failed\n"); 54 | } 55 | return 0; 56 | } 57 | catch (const std::exception& exp) 58 | { 59 | printf("exception: what=%s\n", exp.what()); 60 | return 1; 61 | } 62 | 63 | int main(int argc, char* argv[]) 64 | { 65 | #if defined(_WIN32) || defined(_WIN64) 66 | WSADATA information; 67 | WSAStartup(MAKEWORD(2, 2), &information); 68 | int ret = main0(argc, argv); 69 | WSACleanup(); 70 | return ret; 71 | #else 72 | return main0(argc, argv); 73 | #endif 74 | } 75 | 76 | -------------------------------------------------------------------------------- /samples/file_client/file_client.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 55 | 58 | 61 | 64 | 74 | 77 | 80 | 83 | 86 | 89 | 92 | 95 | 96 | 104 | 107 | 110 | 113 | 116 | 119 | 129 | 132 | 135 | 138 | 150 | 153 | 156 | 159 | 162 | 165 | 168 | 171 | 172 | 173 | 174 | 175 | 176 | 181 | 184 | 185 | 188 | 191 | 195 | 196 | 199 | 203 | 204 | 205 | 206 | 211 | 214 | 215 | 218 | 219 | 220 | 225 | 226 | 229 | 230 | 231 | 232 | 233 | 234 | -------------------------------------------------------------------------------- /samples/file_client/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // echo_client.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /samples/file_client/stdafx.h: -------------------------------------------------------------------------------- 1 | #ifndef __stdafx_h__ 2 | #define __stdafx_h__ 3 | 4 | #if defined(_MSC_VER) && (_MSC_VER >= 1020) 5 | # pragma once 6 | #endif 7 | 8 | // stdafx.h : include file for standard system include files, 9 | // or project specific include files that are used frequently, but 10 | // are changed infrequently 11 | // 12 | 13 | 14 | #ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. 15 | #define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. 16 | #endif 17 | 18 | #include 19 | 20 | 21 | // TODO: reference additional headers your program requires here 22 | 23 | #endif // __stdafx_h__ 24 | 25 | -------------------------------------------------------------------------------- /samples/file_server/file_server.cpp: -------------------------------------------------------------------------------- 1 | // test_rpc_server.cpp : Defines the entry point for the console application. 2 | // 3 | 4 | #include "stdafx.h" 5 | 6 | #ifdef _MSC_VER 7 | #pragma warning(disable: 4251) // needs to have dll-interface 8 | #pragma warning(disable: 4267) // conversion from 'size_t' to 'long', possible loss of data 9 | #pragma warning(disable: 4244) // conversion from '__w64 const unsigned int' to 'unsigned int', possible loss of data 10 | #pragma comment(lib, "Ws2_32.lib") 11 | #endif 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | using namespace std; 19 | using namespace nark; 20 | using namespace nark::rpc; 21 | 22 | #include "../ifile.h" 23 | 24 | BEGIN_RPC_IMP_INTERFACE(FileObjImp, FileObj) 25 | FileObjImp() 26 | { 27 | fp = 0; 28 | } 29 | 30 | ~FileObjImp() 31 | { 32 | if (fp) 33 | { 34 | fclose(fp); 35 | } 36 | } 37 | 38 | rpc_ret_t open(const std::string& fname, const std::string& mode) 39 | { 40 | fp = fopen(fname.c_str(), mode.c_str()); 41 | if (0 == fp) 42 | return errno; 43 | return 0; 44 | } 45 | 46 | rpc_ret_t read(vector* buffer, uint32_t length) 47 | { 48 | buffer->resize(length); 49 | size_t nRead = fread(&*buffer->begin(), 1, length, fp); 50 | buffer->resize(nRead); 51 | return 0; 52 | } 53 | 54 | rpc_ret_t write(const vector& buffer, uint32_t* length) 55 | { 56 | *length = fwrite(&*buffer.begin(), 1, buffer.size(), fp); 57 | return 0; 58 | } 59 | 60 | rpc_ret_t close() 61 | { 62 | fclose(fp); 63 | fp = 0; 64 | return 0; 65 | } 66 | 67 | private: 68 | FILE* fp; 69 | END_RPC_IMP_INTERFACE() 70 | 71 | int main0(int argc, char* argv[]) 72 | { 73 | try { 74 | SocketAcceptor acceptor("0.0.0.0:8001"); 75 | rpc_server server(&acceptor); 76 | 77 | // FileObjImp will auto created by client call 78 | RPC_SERVER_AUTO_CREATE(server, FileObjImp); 79 | 80 | server.start(); 81 | } 82 | catch (const std::exception& exp) 83 | { 84 | printf("exception: what=%s\n", exp.what()); 85 | } 86 | return 0; 87 | } 88 | 89 | int main(int argc, char* argv[]) 90 | { 91 | #if defined(_WIN32) || defined(_WIN64) 92 | WSADATA information; 93 | WSAStartup(MAKEWORD(2, 2), &information); 94 | int ret = main0(argc, argv); 95 | WSACleanup(); 96 | return ret; 97 | #else 98 | return main0(argc, argv); 99 | #endif 100 | } 101 | 102 | -------------------------------------------------------------------------------- /samples/file_server/file_server.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 54 | 57 | 60 | 63 | 73 | 76 | 79 | 82 | 85 | 88 | 91 | 94 | 95 | 103 | 106 | 109 | 112 | 115 | 118 | 128 | 131 | 134 | 137 | 149 | 152 | 155 | 158 | 161 | 164 | 167 | 170 | 171 | 172 | 173 | 174 | 175 | 180 | 183 | 184 | 187 | 190 | 194 | 195 | 198 | 202 | 203 | 204 | 205 | 210 | 213 | 214 | 217 | 218 | 219 | 224 | 225 | 228 | 229 | 230 | 231 | 232 | 233 | -------------------------------------------------------------------------------- /samples/file_server/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // test_rpc_server.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /samples/file_server/stdafx.h: -------------------------------------------------------------------------------- 1 | #ifndef __stdafx_h__ 2 | #define __stdafx_h__ 3 | 4 | #if defined(_MSC_VER) && (_MSC_VER >= 1020) 5 | # pragma once 6 | #endif 7 | 8 | // stdafx.h : include file for standard system include files, 9 | // or project specific include files that are used frequently, but 10 | // are changed infrequently 11 | // 12 | 13 | 14 | #ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. 15 | #define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. 16 | #endif 17 | 18 | #include 19 | //#include 20 | 21 | 22 | 23 | // TODO: reference additional headers your program requires here 24 | 25 | #endif // __stdafx_h__ 26 | 27 | -------------------------------------------------------------------------------- /samples/file_server/test.txt: -------------------------------------------------------------------------------- 1 | Hello, world, this is a test file 2 | -------------------------------------------------------------------------------- /samples/ifile.h: -------------------------------------------------------------------------------- 1 | // sample usage... 2 | // ifile.h 3 | 4 | BEGIN_RPC_INTERFACE(FileObj, SessionScope) 5 | RPC_ADD_MF(open) 6 | RPC_ADD_MF(read) 7 | RPC_ADD_MF(write) 8 | RPC_ADD_MF(close) 9 | END_RPC_ADD_MF() 10 | RPC_DECLARE_MF(open, (const std::string& fname, const std::string& mode)) 11 | RPC_DECLARE_MF(read, (vector* buffer, uint32_t length)) 12 | RPC_DECLARE_MF(write, (const vector& buffer, uint32_t* length)) 13 | RPC_DECLARE_MF(close, ()) 14 | END_RPC_INTERFACE() 15 | -------------------------------------------------------------------------------- /samples/test.h: -------------------------------------------------------------------------------- 1 | 2 | ////////////////////////////////////////////////////////////////////////// 3 | // sample usage... 4 | // test.h 5 | 6 | typedef std::vector vint_vec; 7 | 8 | class AsyncInterface : public GlobaleScope 9 | { 10 | public: 11 | BEGIN_RPC_ADD_MF(AsyncInterface) 12 | RPC_ADD_MF(get_val) 13 | RPC_ADD_MF(get_len) 14 | RPC_ADD_MF(squareVec) 15 | RPC_ADD_MF(multiVec) 16 | END_RPC_ADD_MF() 17 | 18 | RPC_DECLARE_MF(get_val, (rpc_in x)) 19 | RPC_DECLARE_MF(get_len, (const std::string& x)) 20 | RPC_DECLARE_MF(squareVec, (vint_vec& x)) 21 | RPC_DECLARE_MF(multiVec, (vint_vec& z, vint_vec& x, vint_vec& y)) 22 | }; 23 | RPC_TYPEDEF_PTR(AsyncInterface); 24 | 25 | // more convenient way than AsyncInterface... 26 | BEGIN_RPC_INTERFACE(SampleRPC_Interface2, SessionScope) 27 | RPC_ADD_MF(get_val) 28 | RPC_ADD_MF(get_len) 29 | END_RPC_ADD_MF() 30 | RPC_DECLARE_MF(get_val, (rpc_in x)) 31 | RPC_DECLARE_MF(get_len, (const std::string& x)) 32 | END_RPC_INTERFACE() 33 | -------------------------------------------------------------------------------- /samples/test_rpc.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual Studio 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "async_client", "async_client\async_client.vcproj", "{81D3A192-7717-4A4C-A842-F11B8039B2F9}" 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "async_server", "async_server\async_server.vcproj", "{78EA9F46-4979-4BDC-8118-BC302DFC001E}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "employee_client", "employee_client\employee_client.vcproj", "{F334B8A7-6C01-4862-ABE9-DAA7A94306F3}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "employee_server", "employee_server\employee_server.vcproj", "{EAEA0E3D-6B8E-4D06-94FE-5C1803D4DCC3}" 11 | EndProject 12 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echo_client", "echo_client\echo_client.vcproj", "{81D3A192-7717-4A4C-A842-F11B8038B2F9}" 13 | EndProject 14 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echo_server", "echo_server\echo_server.vcproj", "{DCE65FFD-9CC9-4FC3-A9BD-9D02FB2805A2}" 15 | EndProject 16 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "file_server", "file_server\file_server.vcproj", "{8CB32600-F475-4748-8B07-0E3C68FF660E}" 17 | EndProject 18 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "file_client", "file_client\file_client.vcproj", "{0A3D395E-6481-4922-BACC-F216177CA265}" 19 | EndProject 20 | Global 21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 22 | Debug|Win32 = Debug|Win32 23 | Release|Win32 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 26 | {81D3A192-7717-4A4C-A842-F11B8039B2F9}.Debug|Win32.ActiveCfg = Debug|Win32 27 | {81D3A192-7717-4A4C-A842-F11B8039B2F9}.Debug|Win32.Build.0 = Debug|Win32 28 | {81D3A192-7717-4A4C-A842-F11B8039B2F9}.Release|Win32.ActiveCfg = Release|Win32 29 | {81D3A192-7717-4A4C-A842-F11B8039B2F9}.Release|Win32.Build.0 = Release|Win32 30 | {78EA9F46-4979-4BDC-8118-BC302DFC001E}.Debug|Win32.ActiveCfg = Debug|Win32 31 | {78EA9F46-4979-4BDC-8118-BC302DFC001E}.Debug|Win32.Build.0 = Debug|Win32 32 | {78EA9F46-4979-4BDC-8118-BC302DFC001E}.Release|Win32.ActiveCfg = Release|Win32 33 | {78EA9F46-4979-4BDC-8118-BC302DFC001E}.Release|Win32.Build.0 = Release|Win32 34 | {F334B8A7-6C01-4862-ABE9-DAA7A94306F3}.Debug|Win32.ActiveCfg = Debug|Win32 35 | {F334B8A7-6C01-4862-ABE9-DAA7A94306F3}.Debug|Win32.Build.0 = Debug|Win32 36 | {F334B8A7-6C01-4862-ABE9-DAA7A94306F3}.Release|Win32.ActiveCfg = Release|Win32 37 | {F334B8A7-6C01-4862-ABE9-DAA7A94306F3}.Release|Win32.Build.0 = Release|Win32 38 | {EAEA0E3D-6B8E-4D06-94FE-5C1803D4DCC3}.Debug|Win32.ActiveCfg = Debug|Win32 39 | {EAEA0E3D-6B8E-4D06-94FE-5C1803D4DCC3}.Debug|Win32.Build.0 = Debug|Win32 40 | {EAEA0E3D-6B8E-4D06-94FE-5C1803D4DCC3}.Release|Win32.ActiveCfg = Release|Win32 41 | {EAEA0E3D-6B8E-4D06-94FE-5C1803D4DCC3}.Release|Win32.Build.0 = Release|Win32 42 | {81D3A192-7717-4A4C-A842-F11B8038B2F9}.Debug|Win32.ActiveCfg = Debug|Win32 43 | {81D3A192-7717-4A4C-A842-F11B8038B2F9}.Debug|Win32.Build.0 = Debug|Win32 44 | {81D3A192-7717-4A4C-A842-F11B8038B2F9}.Release|Win32.ActiveCfg = Release|Win32 45 | {81D3A192-7717-4A4C-A842-F11B8038B2F9}.Release|Win32.Build.0 = Release|Win32 46 | {DCE65FFD-9CC9-4FC3-A9BD-9D02FB2805A2}.Debug|Win32.ActiveCfg = Debug|Win32 47 | {DCE65FFD-9CC9-4FC3-A9BD-9D02FB2805A2}.Debug|Win32.Build.0 = Debug|Win32 48 | {DCE65FFD-9CC9-4FC3-A9BD-9D02FB2805A2}.Release|Win32.ActiveCfg = Release|Win32 49 | {DCE65FFD-9CC9-4FC3-A9BD-9D02FB2805A2}.Release|Win32.Build.0 = Release|Win32 50 | {8CB32600-F475-4748-8B07-0E3C68FF660E}.Debug|Win32.ActiveCfg = Debug|Win32 51 | {8CB32600-F475-4748-8B07-0E3C68FF660E}.Debug|Win32.Build.0 = Debug|Win32 52 | {8CB32600-F475-4748-8B07-0E3C68FF660E}.Release|Win32.ActiveCfg = Release|Win32 53 | {8CB32600-F475-4748-8B07-0E3C68FF660E}.Release|Win32.Build.0 = Release|Win32 54 | {0A3D395E-6481-4922-BACC-F216177CA265}.Debug|Win32.ActiveCfg = Debug|Win32 55 | {0A3D395E-6481-4922-BACC-F216177CA265}.Debug|Win32.Build.0 = Debug|Win32 56 | {0A3D395E-6481-4922-BACC-F216177CA265}.Release|Win32.ActiveCfg = Release|Win32 57 | {0A3D395E-6481-4922-BACC-F216177CA265}.Release|Win32.Build.0 = Release|Win32 58 | EndGlobalSection 59 | GlobalSection(SolutionProperties) = preSolution 60 | HideSolutionNode = FALSE 61 | EndGlobalSection 62 | EndGlobal 63 | -------------------------------------------------------------------------------- /src/nark/inet/MessageInputStream.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if BOOST_VERSION < 103301 4 | # include 5 | #else 6 | # include 7 | #endif 8 | 9 | #if !defined(BOOST_BIG_ENDIAN) && !defined(BOOST_LITTLE_ENDIAN) 10 | #error must define byte endian 11 | #endif 12 | 13 | #include "MessageInputStream.hpp" 14 | #include 15 | #include 16 | #include 17 | 18 | namespace nark { namespace rpc { 19 | 20 | 21 | void MessageHeader::convert() 22 | { 23 | #ifdef BOOST_LITTLE_ENDIAN 24 | length = byte_swap(length); 25 | seqid = byte_swap(seqid); 26 | partid = byte_swap(partid); 27 | #endif 28 | } 29 | 30 | MessageInputStream::MessageInputStream(IInputStream* stream) 31 | : stream(stream) 32 | { 33 | } 34 | 35 | MessageInputStream::~MessageInputStream() 36 | { 37 | } 38 | 39 | void MessageInputStream::read_hello() 40 | { 41 | 42 | } 43 | 44 | void MessageInputStream::read_until(void* data, size_t length) 45 | { 46 | 47 | } 48 | 49 | size_t MessageInputStream::read(void* vbuf, size_t length) 50 | { 51 | if (m_readed == curheader.length) 52 | { 53 | m_readed = 0; 54 | MessageHeader h2; 55 | read_until(&h2, sizeof(h2)); 56 | h2.convert(); 57 | if (0 == h2.length) 58 | { 59 | throw RequestCanceledException(); 60 | } 61 | if (h2.seqid == curheader.seqid) 62 | { 63 | assert(MSG_HEADER_GET_PARTID(h2.partid) == MSG_HEADER_GET_PARTID(curheader.partid) + 1); 64 | } 65 | curheader = h2; 66 | } 67 | // int ptype = MSG_HEADER_GET_TYPE(curheader.partid); 68 | using namespace std; 69 | size_t n = min(size_t(curheader.length), length); 70 | read_until(m_readed + (char*)vbuf, n); 71 | m_readed += n; 72 | 73 | return n; 74 | } 75 | 76 | bool MessageInputStream::eof() 77 | { 78 | return false; 79 | } 80 | 81 | } } // namespace nark::rpc 82 | -------------------------------------------------------------------------------- /src/nark/inet/MessageInputStream.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockeet/nark-rpc/af7ce41ed03ddb8bef3e49572ccf8dd97f27c83e/src/nark/inet/MessageInputStream.hpp -------------------------------------------------------------------------------- /src/nark/inet/ReactAcceptor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __nark_ReactAcceptor_h__ 2 | #define __nark_ReactAcceptor_h__ 3 | 4 | #if defined(_MSC_VER) && (_MSC_VER >= 1020) 5 | # pragma once 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace nark { 15 | 16 | class ReactAcceptor : public IAcceptor 17 | { 18 | std::auto_ptr m_impl; 19 | public: 20 | ReactAcceptor(int port); 21 | IDuplexStream* accept(); ///< override 22 | }; 23 | 24 | class Request 25 | { 26 | class Session* session; 27 | public: 28 | }; 29 | 30 | class Fiber; 31 | 32 | class ReactServer 33 | { 34 | std::vector free_fiber; 35 | std::list all_session; 36 | volatile int m_run; 37 | 38 | Session* wait(); 39 | 40 | public: 41 | 42 | void run(); 43 | void putRequest(Request* req); 44 | void setAcceptTimeout(int timeoutMillisecond); 45 | void setClientTimeout(int timeoutMillisecond); 46 | }; 47 | 48 | class Session 49 | { 50 | public: 51 | int fd; 52 | Fiber* fiber; 53 | IDuplexStream* duplex; 54 | 55 | Session(IDuplexStream* duplex) 56 | { 57 | 58 | } 59 | virtual Request* decode(); 60 | }; 61 | 62 | class Fiber 63 | { 64 | Session* session; 65 | ReactServer* processor; 66 | std::vector* free_fiber; 67 | public: 68 | void setSession(Session* session) { this->session = session; } 69 | void yield(); 70 | void awake(); 71 | void run(); 72 | bool isFree(); 73 | }; 74 | 75 | class FiberSocketStream : public SocketStream 76 | { 77 | public: 78 | FiberSocketStream(::SOCKET sock); 79 | 80 | protected: 81 | bool waitfor_again(); 82 | 83 | Session* session; 84 | }; 85 | 86 | } // namespace nark 87 | 88 | 89 | #endif // __nark_ReactAcceptor_h__ 90 | -------------------------------------------------------------------------------- /src/nark/inet/SocketStream.cpp: -------------------------------------------------------------------------------- 1 | /* vim: set tabstop=4 : */ 2 | #include "SocketStream.hpp" 3 | 4 | #if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) 5 | //加入winsock库 6 | typedef int socklen_t; 7 | #pragma comment(lib, "Ws2_32.lib") 8 | #else 9 | # include 10 | # include 11 | # include 12 | # include 13 | # include 14 | # include 15 | # include 16 | # include 17 | # include 18 | # define closesocket close 19 | #endif 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | namespace nark { 27 | 28 | SocketException::SocketException(const char* szMsg) 29 | : IOException(lastError(), szMsg) 30 | { 31 | } 32 | 33 | SocketException::SocketException(int errCode, const char* szMsg) 34 | : IOException(errCode, szMsg) 35 | { 36 | } 37 | 38 | int SocketException::lastError() 39 | { 40 | #if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) 41 | return WSAGetLastError(); 42 | #else 43 | return errno; 44 | #endif 45 | } 46 | 47 | ////////////////////////////////////////////////////////////////////////// 48 | 49 | SocketStream::SocketStream(SOCKET socket, bool bAutoClose) 50 | { 51 | this->socket = socket; 52 | posg = 0; 53 | posp = 0; 54 | m_bAutoClose = bAutoClose; 55 | m_bEof = false; 56 | } 57 | 58 | SocketStream::~SocketStream(void) 59 | { 60 | if (m_bAutoClose) 61 | ::closesocket(socket); 62 | } 63 | 64 | bool SocketStream::waitfor_again() 65 | { 66 | #if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) 67 | #else 68 | #endif 69 | return false; 70 | } 71 | 72 | size_t SocketStream::read(void* data, size_t length) 73 | { 74 | if (m_bEof) 75 | { 76 | throw EndOfFileException("socket graceful closed"); 77 | } 78 | 79 | int n = ::recv(socket, (char*)data, length, 0); 80 | if (0 == n) 81 | { 82 | m_bEof = true; 83 | throw EndOfFileException("socket graceful closed"); 84 | } 85 | if (-1 == n && !waitfor_again()) 86 | { 87 | string_appender<> oss; 88 | oss << "recv packet error, socket=" << socket 89 | << ", want=" << length << ", received=" << n; 90 | ; 91 | throw SocketException(oss.str().c_str()); 92 | } 93 | posg += n; 94 | return n; 95 | } 96 | 97 | size_t SocketStream::write(const void* data, size_t length) 98 | { 99 | int n = ::send(socket, (const char*)data, (int)length, 0); 100 | if (0 == n || (-1 == n && !waitfor_again())) 101 | { 102 | string_appender<> oss; 103 | oss << "send packet error, socket=" << socket 104 | << ", want=" << length << ", sent=" << n; 105 | ; 106 | throw SocketException(oss.str().c_str()); 107 | } 108 | posp += n; 109 | return n; 110 | } 111 | ////////////////////////////////////////////////////////////////////////// 112 | 113 | SocketAcceptor::SocketAcceptor(const char* szBindAddr) 114 | { 115 | const char* colon = strchr(szBindAddr, ':'); 116 | std::string strAddr(szBindAddr, colon); 117 | u_short port = atoi(colon + 1); 118 | 119 | m_socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 120 | if (-1 == m_socket) 121 | { 122 | perror("error when create socket"); 123 | std::string err = "SocketAcceptor::SocketAcceptor("; 124 | err += szBindAddr; 125 | err += ")"; 126 | throw SocketException(err.c_str()); 127 | } 128 | struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); 129 | addr.sin_family = AF_INET; 130 | addr.sin_addr.s_addr = inet_addr(strAddr.c_str()); 131 | addr.sin_port = htons(port); 132 | 133 | int err = ::bind(m_socket, (struct sockaddr*)(&addr), sizeof(addr)); 134 | if (0 == err) { 135 | printf("bind send to listen socket[%d] at port:%d success!\n", m_socket, port); 136 | } else { 137 | std::string errText = IOException::errorText(SocketException::lastError()).c_str(); 138 | fprintf(stderr, "SocketConnection::listen, bind tcp socket error: %s", errText.c_str()); 139 | ::closesocket(m_socket); 140 | m_socket = -1; 141 | throw SocketException(errText.c_str()); 142 | } 143 | err = ::listen(m_socket, 5); 144 | if (0 == err) { 145 | printf("listen success\n"); 146 | } else { 147 | std::string errText = IOException::errorText(SocketException::lastError()).c_str(); 148 | fprintf(stderr, "listen tcp error: %s", errText.c_str()); 149 | ::closesocket(m_socket); 150 | m_socket = -1; 151 | throw SocketException(errText.c_str()); 152 | } 153 | } 154 | 155 | SocketStream* SocketAcceptor::accept() 156 | { 157 | struct sockaddr_in from; 158 | socklen_t size = sizeof(from); 159 | SOCKET client = ::accept(m_socket, (struct sockaddr*)&from, &size); 160 | if (-1 == client) 161 | { 162 | std::string errText = IOException::errorText(SocketException::lastError()).c_str(); 163 | fprintf(stderr, "error when accept:%s", errText.c_str()); 164 | return 0; 165 | } 166 | SocketStream* stream = new SocketStream(client); 167 | return stream; 168 | } 169 | 170 | SocketStream* ConnectSocket(const char* szServerAddr) 171 | { 172 | SOCKET hSocket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 173 | if (-1 == hSocket) 174 | return 0; 175 | const char* colon = strchr(szServerAddr, ':'); 176 | std::string strAddr(szServerAddr, colon); 177 | u_short port = atoi(colon + 1); 178 | 179 | struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); 180 | addr.sin_family = AF_INET; 181 | addr.sin_addr.s_addr = inet_addr(strAddr.c_str()); 182 | addr.sin_port = htons(port); 183 | int err = ::connect(hSocket, (sockaddr*)&addr, sizeof(addr)); 184 | if (0 == err) { 185 | DEBUG_printf("connect %s success\n", szServerAddr); 186 | } else { 187 | std::string errText = IOException::errorText(SocketException::lastError()).c_str(); 188 | fprintf(stderr, "error when connect: %s", errText.c_str()); 189 | ::closesocket(hSocket); 190 | hSocket = -1; 191 | throw SocketException(errText.c_str()); 192 | } 193 | SocketStream* stream = new SocketStream(hSocket); 194 | return stream; 195 | } 196 | 197 | 198 | } // nark 199 | -------------------------------------------------------------------------------- /src/nark/inet/SocketStream.hpp: -------------------------------------------------------------------------------- 1 | /* vim: set tabstop=4 : */ 2 | #ifndef __nark_io_SocketStream_h__ 3 | #define __nark_io_SocketStream_h__ 4 | 5 | #if defined(_MSC_VER) && (_MSC_VER >= 1020) 6 | # pragma once 7 | #endif 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) 15 | # if !defined(_WINSOCK2API_) && !defined(_WINSOCKAPI_) 16 | # include 17 | # endif 18 | #else 19 | typedef int SOCKET; 20 | #endif 21 | 22 | namespace nark { 23 | 24 | class NARK_DLL_EXPORT SocketException : public IOException 25 | { 26 | public: 27 | explicit SocketException(const char* szMsg = "SocketException"); 28 | explicit SocketException(int errCode, const char* szMsg = "SocketException"); 29 | 30 | static int lastError(); 31 | }; 32 | 33 | class NARK_DLL_EXPORT SocketStream : public RefCounter, public IDuplexStream 34 | { 35 | DECLARE_NONE_COPYABLE_CLASS(SocketStream) 36 | public: 37 | SocketStream(SOCKET socket, bool bAutoClose = true); 38 | ~SocketStream(); 39 | 40 | public: 41 | size_t read(void* data, size_t length); 42 | size_t write(const void* data, size_t length); 43 | 44 | void flush() { } 45 | bool eof() const { return m_bEof; } 46 | 47 | size_t tellp() { return posp; } 48 | size_t tellg() { return posg; } 49 | 50 | protected: 51 | virtual bool waitfor_again(); 52 | 53 | ::SOCKET socket; 54 | size_t posp; // sent size/pos 55 | size_t posg; // receive size/pos 56 | bool m_bEof; // for override IInputStream::eof 57 | bool m_bAutoClose; 58 | }; 59 | 60 | class NARK_DLL_EXPORT SocketAcceptor : public IAcceptor 61 | { 62 | ::SOCKET m_socket; 63 | public: 64 | SocketAcceptor(const char* szBindAddr); 65 | SocketStream* accept(); 66 | }; 67 | 68 | NARK_DLL_EXPORT SocketStream* ConnectSocket(const char* szServerAddr); 69 | 70 | } 71 | 72 | #endif // __nark_io_SocketStream_h__ 73 | -------------------------------------------------------------------------------- /src/nark/inet/epoll_reactor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __epoll_reactor_h__ 2 | #define __epoll_reactor_h__ 3 | 4 | #if defined(_MSC_VER) && (_MSC_VER >= 1020) 5 | # pragma once 6 | #endif 7 | 8 | #include "reactor.hpp" 9 | 10 | namespace nark { 11 | 12 | class Epoll_Reactor : public Reactor 13 | { 14 | int epfd; 15 | int listenfd; 16 | 17 | public: 18 | Epoll_Reactor(int port); 19 | 20 | void add(int fd, int evt); 21 | void modify(ConnectionStatePtr conn, int evt); 22 | void del(ConnectionStatePtr conn); 23 | 24 | void run(); 25 | void handle_events(ConnectionStatePtr conn, int events); 26 | }; 27 | 28 | } // namespace nark 29 | 30 | 31 | #endif // __epoll_reactor_h__ 32 | -------------------------------------------------------------------------------- /src/nark/inet/reactor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __nark_rpc_reactor_h__ 2 | #define __nark_rpc_reactor_h__ 3 | 4 | #if defined(_MSC_VER) && (_MSC_VER >= 1020) 5 | # pragma once 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace nark { 13 | 14 | class ConnectionState : public RefCounter 15 | { 16 | public: 17 | int fd; 18 | void* coro; 19 | 20 | ConnectionState(int fd); 21 | }; 22 | 23 | typedef boost::intrusive_ptr ConnectionStatePtr; 24 | 25 | class Reactor 26 | { 27 | int epfd; 28 | void* main_coro; 29 | public: 30 | Reactor(); 31 | }; 32 | 33 | } // namespace nark 34 | 35 | 36 | #endif // __nark_rpc_reactor_h__ 37 | -------------------------------------------------------------------------------- /src/nark/io/access_byid.cpp: -------------------------------------------------------------------------------- 1 | /* vim: set tabstop=4 : */ 2 | #include "access_byid.hpp" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #if defined(_MSC_VER) && (defined(_DEBUG) || !defined(NDEBUG)) 9 | // #undef NARK_RPC_DONT_USE_HASH_STRMAP 10 | #define NARK_RPC_DONT_USE_HASH_STRMAP 11 | #endif 12 | 13 | #ifdef NARK_RPC_DONT_USE_HASH_STRMAP 14 | #include 15 | typedef std::map NameMapBase; 16 | #else 17 | #include 18 | typedef nark::hash_strmap NameMapBase; 19 | #endif 20 | 21 | namespace nark { 22 | class NameMapForAccessByNameID : public NameMapBase {}; 23 | 24 | id_generator::id_generator(uintptr_t maxID) 25 | : id_list(maxID+1) 26 | { 27 | chain(0); 28 | m_nUsed = 0; 29 | } 30 | id_generator::~id_generator() 31 | { 32 | // must call this->clear() before destruct 33 | // otherwise, these assertion will fail! 34 | assert(0 == m_nUsed); 35 | assert(id_list.empty()); 36 | } 37 | 38 | void id_generator::chain(uintptr_t newHead) 39 | { 40 | for (uintptr_t i = newHead; i != id_list.size()-1; ++i) 41 | id_list[i] = i + 1; // id_list[i] link to id_list[i+1] 42 | id_list.back() = 0; // set 0 as tail 43 | } 44 | 45 | uintptr_t id_generator::alloc_id() 46 | { 47 | if (0 == id_list[0]) // out of space, enlarge id_list 48 | { 49 | uintptr_t newHead = id_list[0] = id_list.size(); 50 | id_list.resize(id_list.size()*2); 51 | chain(newHead); 52 | } 53 | ++m_nUsed; 54 | uintptr_t retid = id_list[0]; 55 | id_list[0] = id_list[retid]; 56 | return retid; 57 | } 58 | 59 | void id_generator::free_id(uintptr_t id) 60 | { 61 | assert(id >= 1); 62 | assert(id <= uintptr_t(id_list.size())); 63 | assert(m_nUsed >= 1); 64 | if (uintptr_t(id_list.size()) < id || id <= 0) 65 | { 66 | throw std::invalid_argument("void id_generator::free_id(uintptr_t id)"); 67 | } 68 | id_list[id] = id_list[0]; 69 | id_list[0] = id; 70 | --m_nUsed; 71 | } 72 | 73 | uintptr_t id_generator::add_val(uintptr_t val) 74 | { 75 | uintptr_t id = alloc_id(); 76 | id_list[id] = val; 77 | return id; 78 | } 79 | 80 | void id_generator::get_used_id(std::vector* used_id) const 81 | { 82 | assert(NULL != used_id); 83 | used_id->resize(0); 84 | used_id->reserve(id_list.size()); 85 | std::vector free_subscript; 86 | free_subscript.reserve(id_list.size()); 87 | free_subscript.push_back(0); 88 | for (uintptr_t h = id_list[0]; h != 0; h = id_list[h]) 89 | free_subscript.push_back(h); 90 | std::sort(free_subscript.begin(), free_subscript.end()); 91 | free_subscript.push_back(id_list.size()); 92 | for (uintptr_t i = 0; i != free_subscript.size()-1; ++i) 93 | { 94 | uintptr_t d1 = free_subscript[i+0]+1; 95 | uintptr_t d2 = free_subscript[i+1]; 96 | for (uintptr_t j = d1; j < d2; ++j) 97 | used_id->push_back(j); 98 | } 99 | } 100 | 101 | void* access_byid::get_ptr_imp(uintptr_t id, const char* func) const 102 | { 103 | if (this->is_valid(id)) 104 | { 105 | assert(this->get_val(id) > 1024); 106 | return (void*)(this->get_val(id)); 107 | } 108 | string_appender<> oss; 109 | oss << func << ": id too large"; 110 | throw std::invalid_argument(oss.str()); 111 | } 112 | 113 | void access_byid::on_destroy(void* vp) 114 | { 115 | ::free(vp); 116 | } 117 | 118 | void access_byid::destroy() 119 | { 120 | std::vector used_id; 121 | get_used_id(&used_id); 122 | for (uintptr_t i = 0; i != used_id.size(); ++i) 123 | { 124 | void* x = (void*)this->get_val(used_id[i]); 125 | on_destroy(x); 126 | } 127 | this->clear(); 128 | } 129 | 130 | access_byid::~access_byid() 131 | { 132 | // must called this->destroy() before destruct 133 | assert(0 == this->size()); 134 | } 135 | 136 | AccessByNameID::AccessByNameID() { 137 | m_byname = new NameMapForAccessByNameID; // must success 138 | } 139 | 140 | uintptr_t AccessByNameID::add_ptr(void* x, const std::string& name, void** existed) 141 | { 142 | assert(NULL != x); 143 | void*& y = (*m_byname)[name]; 144 | if (y) { 145 | *existed = y; 146 | return 0; 147 | } 148 | else { 149 | *existed = NULL; 150 | y = x; 151 | uintptr_t id = m_byid.add_ptr(x); 152 | return id; 153 | } 154 | } 155 | 156 | void* AccessByNameID::get_byname(const std::string& name) const 157 | { 158 | NameMapForAccessByNameID::const_iterator iter = m_byname->find(name); 159 | if (m_byname->end() != iter) 160 | return iter->second; 161 | else 162 | return 0; 163 | } 164 | 165 | void AccessByNameID::on_destroy(void* vp) 166 | { 167 | ::free(vp); 168 | } 169 | 170 | //! delete all object in list, and clear self 171 | void AccessByNameID::destroy() 172 | { 173 | std::vector used_id; 174 | m_byid.get_used_id(&used_id); 175 | std::vector bynamep(m_byname->size()); 176 | NameMapForAccessByNameID::iterator iter = m_byname->begin(); 177 | for (uintptr_t i = 0; iter != m_byname->end(); ++iter) 178 | bynamep[i++] = (uintptr_t)iter->second; 179 | for (uintptr_t i = 0; i != used_id.size(); ++i) 180 | used_id[i] = m_byid.get_val(used_id[i]); 181 | std::sort(used_id.begin(), used_id.end()); 182 | std::sort(bynamep.begin(), bynamep.end()); 183 | uintptr_t n = std::set_union(used_id.begin(), used_id.end(), 184 | bynamep.begin(), bynamep.end(), used_id.begin()) - used_id.begin(); 185 | assert(used_id.size() == n); 186 | if (used_id.size() != n) { 187 | THROW_STD(runtime_error, 188 | "(used_id.size=%zd) != (n=%zd)", used_id.size(), n); 189 | } 190 | for (uintptr_t i = 0; i != n; ++i) 191 | on_destroy((void*)used_id[i]); 192 | m_byid.clear(); 193 | m_byname->clear(); 194 | } 195 | 196 | void AccessByNameID::remove(uintptr_t id, const std::string& name) 197 | { 198 | void* p = m_byid.get_ptr(id); 199 | m_byid.free_id(id); 200 | m_byname->erase(name); 201 | on_destroy(p); 202 | } 203 | 204 | void AccessByNameID::remove(uintptr_t id) 205 | { 206 | void* p = m_byid.get_ptr(id); 207 | m_byid.free_id(id); 208 | on_destroy(p); 209 | } 210 | 211 | bool AccessByNameID::check_id(uintptr_t id, const char* szClassName, std::string& err) const 212 | { 213 | if (nark_unlikely(0 == id)) 214 | { 215 | assert(0); 216 | } 217 | if (!this->is_valid(id)) 218 | { 219 | string_appender<> oss; 220 | oss << "can not find " << szClassName << " object[id=" << id << "]" 221 | ; 222 | err = oss.str(); 223 | return false; 224 | } 225 | return true; 226 | } 227 | 228 | AccessByNameID::~AccessByNameID() 229 | { 230 | // must call destroy() before destructor was called 231 | assert(m_byid.size() == 0); 232 | delete m_byname; 233 | } 234 | 235 | 236 | } // namespace nark 237 | 238 | -------------------------------------------------------------------------------- /src/nark/io/access_byid.hpp: -------------------------------------------------------------------------------- 1 | /* vim: set tabstop=4 : */ 2 | #ifndef __nark_io_id_generator_h__ 3 | #define __nark_io_id_generator_h__ 4 | 5 | #if defined(_MSC_VER) && (_MSC_VER >= 1020) 6 | # pragma once 7 | #endif 8 | 9 | #if defined(__GNUC__) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L 10 | # include 11 | #endif 12 | 13 | #if defined(linux) || defined(__linux) || defined(__linux__) 14 | #include 15 | #elif defined(_MSC_VER) 16 | #include // for uintptr_t 17 | #else 18 | #include 19 | #endif 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | namespace nark { 30 | 31 | class NARK_DLL_EXPORT id_generator 32 | { 33 | // use free-list structure, same as memory management 34 | // id may not be 0 35 | std::vector id_list; // id_list[0] is linked list head 36 | uintptr_t m_nUsed; 37 | 38 | void chain(uintptr_t newHead); 39 | 40 | public: 41 | void clear() { m_nUsed = 0; id_list.clear(); } 42 | 43 | explicit id_generator(uintptr_t maxID); 44 | virtual ~id_generator(); 45 | 46 | uintptr_t alloc_id(); 47 | void free_id(uintptr_t id); 48 | 49 | uintptr_t add_val(uintptr_t val); 50 | uintptr_t get_val(uintptr_t id) const { 51 | assert(id >= 1); 52 | assert(id <= uintptr_t(id_list.size()-1)); 53 | return id_list[id]; 54 | } 55 | 56 | bool is_valid(uintptr_t id) const { 57 | return id >= 1 && id <= uintptr_t(id_list.size()-1); 58 | } 59 | 60 | uintptr_t maxid() const { return id_list.size()-1; } 61 | uintptr_t size() const { return m_nUsed; } 62 | 63 | void get_used_id(std::vector* used_id) const; 64 | }; 65 | 66 | class NARK_DLL_EXPORT access_byid : public id_generator 67 | { 68 | protected: 69 | virtual void on_destroy(void* vp); 70 | void* get_ptr_imp(uintptr_t id, const char* func) const; 71 | using id_generator::add_val; // hide it 72 | 73 | public: 74 | access_byid(uintptr_t maxID = 3) : id_generator(maxID) { } 75 | 76 | //! delete all object in list, and clear self 77 | void destroy(); 78 | 79 | //! get the object by id 80 | void* get_ptr(uintptr_t id) const { 81 | return get_ptr_imp(id, BOOST_CURRENT_FUNCTION); 82 | } 83 | 84 | //! add `x` to managed object pool 85 | //! @return a new allocated id for `x` 86 | uintptr_t add_ptr(void* x) { return this->add_val((uintptr_t)(x)); } 87 | 88 | ~access_byid(); 89 | }; 90 | 91 | // do not allow T to be non-pointer type 92 | template class AccessByNameID; 93 | 94 | template<> class NARK_DLL_EXPORT AccessByNameID 95 | { 96 | protected: 97 | access_byid m_byid; 98 | class NameMapForAccessByNameID* m_byname; 99 | virtual void on_destroy(void* vp); 100 | public: 101 | uintptr_t add_ptr(void* x, const std::string& name, void** existed); 102 | uintptr_t add_ptr(void* x) { return m_byid.add_ptr(x); } 103 | void* get_byid(uintptr_t id) const { return m_byid.get_ptr(id); } 104 | void* get_byname(const std::string& name) const; 105 | bool is_valid(uintptr_t id) const { return m_byid.is_valid(id); } 106 | void destroy(); 107 | 108 | void remove(uintptr_t id, const std::string& name); 109 | void remove(uintptr_t id); 110 | uintptr_t size() const { return m_byid.size(); } 111 | bool check_id(uintptr_t id, const char* szClassName, std::string& err) const; 112 | 113 | AccessByNameID(); 114 | virtual ~AccessByNameID(); 115 | }; 116 | 117 | template class AccessByNameID : public AccessByNameID 118 | { 119 | typedef AccessByNameID super; 120 | virtual void on_destroy(void* vp) { delete (T*)vp; } 121 | public: 122 | uintptr_t add_ptr(T* x, const std::string& name, T** existed) { 123 | return super::add_ptr(x, name, (void**)existed); 124 | } 125 | uintptr_t add_ptr(T* x) { // add without name 126 | assert(0 != x); 127 | return m_byid.add_ptr(x); 128 | } 129 | T* get_byid(uintptr_t id) const { return (T*)m_byid.get_ptr(id); } 130 | T* get_byname(const std::string& name) const { 131 | return (T*)super::get_byname(name); 132 | } 133 | ~AccessByNameID() { 134 | // must call destroy() before destructor was called 135 | assert(m_byid.size() == 0); 136 | } 137 | }; 138 | 139 | template 140 | class AccessByNameID > : public AccessByNameID 141 | { 142 | typedef boost::intrusive_ptr ptr_t; 143 | typedef AccessByNameID super; 144 | virtual void on_destroy(void* vp) { intrusive_ptr_release((T*)vp); } 145 | public: 146 | uintptr_t add_ptr(ptr_t x, const std::string& name, ptr_t* existed) { 147 | assert(0 != x.get()); 148 | T* vpExisted; 149 | uintptr_t id = super::add_ptr(x.get(), name, (void**)&vpExisted); 150 | if (0 == vpExisted) { 151 | intrusive_ptr_add_ref(x.get()); 152 | *existed = vpExisted; 153 | } 154 | return id; 155 | } 156 | uintptr_t add_ptr(ptr_t x) { // add without name 157 | assert(0 != x.get()); 158 | intrusive_ptr_add_ref(x.get()); 159 | return m_byid.add_ptr(x.get()); 160 | } 161 | uintptr_t add_ptr(T* x, const std::string& name, T** existed) { 162 | assert(0 != x); 163 | assert(0 != existed); 164 | uintptr_t id = super::add_ptr(x, name, (void**)existed); 165 | if (0 == *existed) 166 | intrusive_ptr_add_ref(x); 167 | return id; 168 | } 169 | uintptr_t add_ptr(T* x) { // add without name 170 | assert(0 != x); 171 | intrusive_ptr_add_ref(x); 172 | return m_byid.add_ptr(x); 173 | } 174 | ptr_t get_byid(uintptr_t id) const { return (T*)m_byid.get_ptr(id); } 175 | ptr_t get_byname(const std::string& name) const { 176 | return (T*)super::get_byname(name); 177 | } 178 | T* get_rawptr_byid(uintptr_t id) const { return (T*)m_byid.get_ptr(id); } 179 | T* get_rawptr_byname(const std::string& name) const { 180 | return (T*)super::get_byname(name); 181 | } 182 | 183 | ~AccessByNameID() { 184 | // must call destroy() before destructor was called 185 | assert(m_byid.size() == 0); 186 | } 187 | }; 188 | 189 | } // namespace nark 190 | 191 | #endif // __nark_io_id_generator_h__ 192 | -------------------------------------------------------------------------------- /src/nark/rpc/arg_traits.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockeet/nark-rpc/af7ce41ed03ddb8bef3e49572ccf8dd97f27c83e/src/nark/rpc/arg_traits.hpp -------------------------------------------------------------------------------- /src/nark/rpc/client.cpp: -------------------------------------------------------------------------------- 1 | /* vim: set tabstop=4 : */ 2 | #include "client.hpp" 3 | #include 4 | #include 5 | 6 | namespace nark { namespace rpc { 7 | 8 | client_stub_i::client_stub_i() 9 | : m_callid(0) 10 | { 11 | } 12 | 13 | client_stub_i::~client_stub_i() 14 | { 15 | } 16 | 17 | /** 18 | @brief rpc_client_base 19 | 20 | 每个不同的客户端类型可能会有多个实例,这些实例的stub->m_callid 会因为 server 的不同而不同。 21 | 因此不能由多个 client 共享同一个static client_stub,而必须 new 新的 stub 22 | */ 23 | rpc_client_base::rpc_client_base(IDuplexStream* duplex) 24 | : m_minseqid(0) 25 | , m_sequence_id(0) 26 | , m_duplex(duplex) 27 | { 28 | intrusive_ptr_add_ref(this); 29 | } 30 | 31 | rpc_client_base::~rpc_client_base() 32 | { 33 | while (!m_stubTable.empty()) 34 | { 35 | delete m_stubTable.begin()->second; 36 | m_stubTable.erase(m_stubTable.begin()); 37 | } 38 | } 39 | 40 | // void async_packet(boost::intrusive_ptr p) 41 | // { 42 | // boost::mutex::scoped_lock lock(m_mutex_pendings); 43 | // while (m_pendings.full()) 44 | // m_cond_pendings.wait(m_mutex_pendings); 45 | // m_pendings.push_back(p); 46 | // } 47 | 48 | /** 49 | @brief 将 client_packet 放入待决队列中,以便随后返回 50 | */ 51 | void rpc_client_base::async_packet(client_packet_base* p) 52 | { 53 | boost::mutex::scoped_lock lock(m_mutex_pendings); 54 | m_pendings.insert(std::make_pair(p->seqid, p)); 55 | } 56 | 57 | void rpc_client_base::wait_pending_async() 58 | { 59 | boost::intrusive_ptr packet; 60 | bool isEmpty; 61 | { 62 | boost::mutex::scoped_lock lockP(m_mutex_pendings); 63 | isEmpty = m_pendings.empty(); 64 | } 65 | while (!isEmpty) 66 | { 67 | { 68 | boost::mutex::scoped_lock lock(m_mutex_read); 69 | unsigned seqid = read_seqid(); 70 | { 71 | boost::mutex::scoped_lock lockP(m_mutex_pendings); 72 | pending_invokation_set::iterator iter = m_pendings.find(seqid); 73 | if (m_pendings.end() != iter) 74 | { 75 | packet = iter->second; 76 | m_pendings.erase(iter); 77 | isEmpty = m_pendings.empty(); 78 | } 79 | } 80 | } 81 | assert(packet); 82 | packet->on_return(); 83 | } 84 | } 85 | 86 | void rpc_client_base::wait_async_return_once() 87 | { 88 | boost::intrusive_ptr packet; 89 | { 90 | boost::mutex::scoped_lock lock(m_mutex_read); 91 | unsigned seqid = read_seqid(); 92 | { 93 | boost::mutex::scoped_lock lockP(m_mutex_pendings); 94 | pending_invokation_set::iterator iter = m_pendings.find(seqid); 95 | if (m_pendings.end() != iter) 96 | { 97 | packet = iter->second; 98 | m_pendings.erase(iter); 99 | } 100 | // m_cond_pendings.notify_all(); 101 | } 102 | // packet->read_args(this); 103 | } 104 | assert(packet); 105 | packet->on_return(); 106 | } 107 | 108 | /** 109 | @brief 轮询等待未返回的rpc调用 110 | */ 111 | void rpc_client_base::wait_async_return() 112 | { 113 | m_run = true; 114 | while (m_run) 115 | { 116 | wait_async_return_once(); 117 | } 118 | } 119 | 120 | //! 开启异步调用的等待线程 121 | void rpc_client_base::start_async(int nThreads) 122 | { 123 | assert(nThreads > 0); 124 | m_run = 1; 125 | m_threads.resize(nThreads); 126 | for (int i = 0; i != nThreads; ++i) 127 | { 128 | m_threads[i] = new boost::thread(boost::bind(&rpc_client_base::wait_async_return, this)); 129 | } 130 | } 131 | 132 | //! 查询 GlobaleScope object 133 | bool rpc_client_base::retrieve_1(GlobaleScope& x, const std::string& instanceName) 134 | { 135 | var_size_t proxyID; 136 | rpc_ret_t ret = this->retrieveGlobaleObject(&proxyID, instanceName); 137 | x.setID(proxyID.t); 138 | return (0 == ret); 139 | } 140 | 141 | //! 查询 SessionScope object 142 | bool rpc_client_base::retrieve_1(SessionScope& x, const std::string& instanceName) 143 | { 144 | var_size_t proxyID; 145 | rpc_ret_t ret = this->retrieveSessionObject(&proxyID,instanceName); 146 | x.setID(proxyID.t); 147 | return (0 == ret); 148 | } 149 | //! 创建 GlobaleScope object 150 | void rpc_client_base::create_1(GlobaleScope& x, const std::string& instanceName) 151 | { 152 | var_size_t proxyID; 153 | std::string className = x.getClassName(); 154 | rpc_ret_t ret = this->createNamedGlobaleObject(&proxyID,className, instanceName); 155 | if (0 != ret && className != x.getClassName()) 156 | { 157 | string_appender<> oss; 158 | oss << "instanceName=" << instanceName << " existed in server, " 159 | << "its class=" << className; 160 | throw std::logic_error(oss.str()); 161 | } 162 | x.setID(proxyID.t); 163 | } 164 | //! 创建 SessionScope object 165 | void rpc_client_base::create_1(SessionScope& x, const std::string& instanceName) 166 | { 167 | var_size_t proxyID; 168 | std::string className = x.getClassName(); 169 | rpc_ret_t ret = this->createNamedSessionObject(&proxyID,className, instanceName); 170 | if (0 != ret && className != x.getClassName()) 171 | { 172 | string_appender<> oss; 173 | oss << "instanceName=" << instanceName << " existed in server, " 174 | << "its class=" << className; 175 | throw std::logic_error(oss.str()); 176 | } 177 | x.setID(proxyID.t); 178 | } 179 | void rpc_client_base::create_0(GlobaleScope& x) 180 | { 181 | var_size_t proxyID; 182 | rpc_ret_t ret = this->createGlobaleObject(&proxyID, x.getClassName()); 183 | (void)ret; 184 | x.setID(proxyID.t); 185 | } 186 | void rpc_client_base::create_0(SessionScope& x) 187 | { 188 | var_size_t proxyID; 189 | rpc_ret_t ret = this->createSessionObject(&proxyID,x.getClassName()); 190 | (void)ret; 191 | x.setID(proxyID.t); 192 | } 193 | 194 | } } // namespace nark::rpc 195 | 196 | -------------------------------------------------------------------------------- /src/nark/rpc/client.hpp: -------------------------------------------------------------------------------- 1 | /* vim: set tabstop=4 : */ 2 | #ifndef __nark_rpc_client_h__ 3 | #define __nark_rpc_client_h__ 4 | 5 | #if defined(_MSC_VER) && (_MSC_VER >= 1020) 6 | # pragma once 7 | # pragma warning(disable: 4819) 8 | #endif 9 | 10 | /** 11 | @file rpc Client Side 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define IF_RPC_SERVER(Server, Client) Client 20 | 21 | #define RPC_CLIENT_SIDE 22 | 23 | #include "rpc_basic.hpp" 24 | #include "arg_traits.hpp" 25 | #include "client_io.hpp" 26 | #include 27 | 28 | namespace nark { namespace rpc { 29 | 30 | //BOOST_STATIC_CONSTANT(unsigned, rpc_call_byid = 1); 31 | //BOOST_STATIC_CONSTANT(unsigned, rpc_copy_args = 2); 32 | 33 | ////////////////////////////////////////////////////////////////////////// 34 | //! on client side... 35 | //! 36 | //! rpc 接口类中需要 typedef 一个类的别名: self_t 37 | //! 使用宏的目的只有一个:推导 FunName 的参数表,将参数表转化成 tuple 38 | //! 参数表一般是: (T1, T2, T3) 等等 39 | //! 因此无法变成直接转调其它函数的形式,使用 tuple,就可以在 mem_fun_binder 中转调其他函数 40 | //! 41 | #define RPC_DECLARE_MF_EX(FunName, ArgList, PureVirtualTagIgnored) \ 42 | typedef rpc_ret_t (self_t::*FunName##_stub_t) ArgList; \ 43 | client_stub_ref FunName; 44 | 45 | #define RPC_DECLARE_MF(FunName, ArgList) RPC_DECLARE_MF_EX(FunName, ArgList, =0) 46 | #define RPC_DECLARE_MF_D RPC_DECLARE_MF 47 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 48 | 49 | #define BEGIN_RPC_ADD_MF_EX(ThisClass, ClassName) \ 50 | typedef ThisClass self_t; \ 51 | NARK_RPC_GEN_full_mf_name(ClassName) \ 52 | template \ 53 | void bind_client(Client* client) \ 54 | { set_ext_ptr(client); 55 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 56 | #define BEGIN_RPC_ADD_MF(ThisClass) BEGIN_RPC_ADD_MF_EX(ThisClass, #ThisClass) 57 | 58 | #define RPC_ADD_MF(FunName) \ 59 | client->bind_stub(FunName, full_mf_name(#FunName), this); 60 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 61 | 62 | #define END_RPC_ADD_MF() } 63 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 64 | 65 | /// 66 | /// client packet hierarchy 67 | /// 68 | /// client_packet_base 69 | /// - client_packet_fun 70 | /// - client_packet_io 71 | /// - client_packet 72 | /// 73 | 74 | /// 75 | /// client stub hierarchy 76 | /// 77 | /// client_stub_i 78 | /// - client_stub 79 | /// 80 | 81 | /// 82 | /// rpc_client hierarchy 83 | // 84 | /// rpc_client_basebase(alias of SessionScope) 85 | /// rpc_client_base 86 | /// rpc_client 87 | 88 | typedef SessionScope rpc_client_basebase; 89 | class NARK_DLL_EXPORT client_packet_base; 90 | 91 | template class client_stub_ref; 92 | template class client_packet; 93 | 94 | class NARK_DLL_EXPORT client_stub_i 95 | { 96 | public: 97 | std::string m_className; 98 | std::string m_name; 99 | unsigned m_callid; 100 | 101 | client_stub_i(); 102 | virtual ~client_stub_i(); 103 | 104 | //! @brief 创建 refpacket 105 | //! 不创建调用时的实参副本,会改变原先的实参,用户需要保证原先的实参在异步返回时仍然有效 106 | //! 如果用户需要在 on_return 中使用原先传入的参数本身,将会创建 refpacket 107 | virtual boost::intrusive_ptr refpacket_create(void* argrefs) = 0; 108 | 109 | //! @brief 创建 valpacket 110 | //! 会创建调用时的实参副本,原先的实参不会被改变,用户的工作量最少 111 | //! 一般情况下会调用这个函数,它不需要用户自己管理原参数(async调用传入的参数引用)的分配与释放 112 | virtual boost::intrusive_ptr valpacket_create(void* argrefs) = 0; 113 | 114 | //! @brief 使用 stubID 来调用远程函数 115 | //! 如果 stubID 未知(=0),仍然会调用call_byname 116 | virtual rpc_ret_t call_byid(rpc_client_basebase* client, void* argrefs) = 0; 117 | 118 | //! 使用函数名来调用 119 | virtual rpc_ret_t call_byname(rpc_client_basebase* client, void* argrefs) = 0; 120 | 121 | //! 写入stubID和参数 122 | virtual void send_id_args(rpc_client_basebase* client, client_packet_base* packet) = 0; 123 | 124 | //! 写入stubName和参数 125 | virtual void send_nm_args(rpc_client_basebase* client, client_packet_base* packet) = 0; 126 | 127 | //! 读取参数 128 | virtual void read_args(rpc_client_basebase* client, client_packet_base* packet) = 0; 129 | }; 130 | 131 | class NARK_DLL_EXPORT client_packet_base : public RefCounter 132 | { 133 | public: 134 | class client_stub_i* stub; 135 | unsigned seqid; 136 | short how_call; 137 | bool isbyid; 138 | rpc_ret_t retv; 139 | 140 | virtual void send_id_args(rpc_client_basebase* client) = 0; 141 | virtual void send_nm_args(rpc_client_basebase* client) = 0; 142 | virtual void read_args(rpc_client_basebase* client) = 0; 143 | 144 | virtual void on_return() = 0; 145 | 146 | void async_packet(rpc_client_basebase* client); 147 | }; 148 | 149 | //! @brief 定义 client_packet 的回调函数 150 | //! 回调函数的原型是: 151 | //! void (ThisType::*)(const client_packet_base& + original param declare) 152 | template 153 | class client_packet_fun : public client_packet_base 154 | { 155 | public: 156 | CallBackFunction on_ret; 157 | }; 158 | 159 | //! 实现 client_packet io 160 | template 161 | class client_packet_io : public client_packet_fun 162 | { 163 | public: 164 | typedef arglist_ref arglist_ref_t; 165 | 166 | rpc_ret_t t_call_byid(rpc_client_basebase* vpclient, arglist_ref_t& refs) { 167 | Client* client = (Client*)(vpclient); 168 | this->how_call = rpc_call_synch; 169 | if (this->stub->m_callid) 170 | t_send_id_args(client, refs); 171 | else 172 | t_send_nm_args(client, refs); 173 | boost::mutex::scoped_lock lock(client->m_mutex_read); 174 | var_size_t vseqid1; 175 | client->m_co_input.get() >> vseqid1; 176 | assert(this->seqid == vseqid1.t); 177 | t_read_args(client, refs); 178 | return this->retv; 179 | } 180 | rpc_ret_t t_call_byname(rpc_client_basebase* vpclient, arglist_ref_t& refs) { 181 | Client* client = (Client*)(vpclient); 182 | this->how_call = rpc_call_synch; 183 | t_send_nm_args(client, refs); 184 | boost::mutex::scoped_lock lock(client->m_mutex_read); 185 | var_size_t vseqid1; 186 | client->m_co_input.get() >> vseqid1; 187 | t_read_args(client, refs); 188 | assert(this->seqid == vseqid1.t); 189 | return this->retv; 190 | } 191 | void t_read_args(rpc_client_basebase* vpclient, arglist_ref_t& refs) { 192 | Client* client = (Client*)(vpclient); 193 | client->m_co_input.get() >> this->retv; 194 | refs.load(client->m_co_input); 195 | if (!this->isbyid) { // called by name, read callid 196 | var_size_t stubID; 197 | client->m_co_input.get() >> stubID; 198 | this->stub->m_callid = stubID; 199 | } 200 | } 201 | void t_send_id_args(rpc_client_basebase* vpclient, arglist_ref_t& refs) { 202 | this->isbyid = true; 203 | Client* client = (Client*)(vpclient); 204 | boost::mutex::scoped_lock lock(client->m_mutex_write); 205 | this->seqid = client->next_sequence_id(); 206 | client->m_co_output.get() 207 | << var_size_t(this->seqid) 208 | << var_size_t(this->stub->m_callid) 209 | << var_size_t(this->how_call) 210 | ; 211 | refs.save(client->m_co_output); 212 | client->m_co_output.flush(); 213 | } 214 | void t_send_nm_args(rpc_client_basebase* vpclient, arglist_ref_t& refs) { 215 | this->isbyid = false; 216 | Client* client = (Client*)(vpclient); 217 | boost::mutex::scoped_lock lock(client->m_mutex_write); 218 | this->seqid = client->next_sequence_id(); 219 | client->m_co_output.get() 220 | << var_size_t(this->seqid) 221 | << (byte)(0) 222 | << this->stub->m_name 223 | << var_size_t(this->how_call) 224 | ; 225 | refs.save(client->m_co_output); 226 | client->m_co_output.flush(); 227 | } 228 | }; 229 | 230 | // 231 | //------------------------------------------------------------------------- 232 | // 233 | // partial specializations, use BOOST_PP.. 234 | // 235 | #include 236 | #define BOOST_PP_ITERATION_LIMITS (0, 9) 237 | #define BOOST_PP_FILENAME_1 238 | #include BOOST_PP_ITERATE() 239 | //------------------------------------------------------------------------- 240 | // 241 | 242 | class NARK_DLL_EXPORT rpc_client_base : public SessionScope 243 | { 244 | protected: 245 | std::map m_stubTable; 246 | // circular_queue > m_pendings; 247 | // boost::condition m_cond_pendings; 248 | typedef std::map > pending_invokation_set; 249 | pending_invokation_set m_pendings; 250 | boost::mutex m_mutex_pendings; 251 | unsigned m_minseqid; 252 | unsigned m_sequence_id; 253 | volatile int m_run; 254 | std::vector m_threads; 255 | IDuplexStream* m_duplex; 256 | 257 | protected: 258 | bool retrieve_1(GlobaleScope& x, const std::string& instanceName); 259 | bool retrieve_1(SessionScope& x, const std::string& instanceName); 260 | void create_1(GlobaleScope& x, const std::string& instanceName); 261 | void create_1(SessionScope& x, const std::string& instanceName); 262 | void create_0(GlobaleScope& x); 263 | void create_0(SessionScope& x); 264 | 265 | typedef rpc_client_base my_self_t; 266 | #include "rpc_interface.hpp" 267 | 268 | public: 269 | boost::mutex m_mutex_read, m_mutex_write; 270 | 271 | explicit rpc_client_base(IDuplexStream* duplex); 272 | virtual ~rpc_client_base(); 273 | 274 | void async_packet(client_packet_base* p); 275 | uint32_t next_sequence_id() { return ++m_sequence_id; } 276 | 277 | virtual unsigned read_seqid() = 0; 278 | 279 | void wait_pending_async(); 280 | void wait_async_return_once(); 281 | void wait_async_return(); 282 | void start_async(int nThreads); 283 | void stop_async() { m_run = 0; } 284 | }; 285 | 286 | /** 287 | @brief 实现一个客户端函数的 stub 288 | 由 client_stub_ref 来引用,多个 client_stub_ref 可以引用同一个 client_stub 289 | */ 290 | template 291 | class client_stub : public client_stub_i 292 | { 293 | public: 294 | typedef arglist_ref aref_t; 295 | typedef arglist_val aval_t; 296 | typedef client_packet refpacket_t; 297 | typedef client_packet valpacket_t; 298 | 299 | explicit client_stub(const std::string& name) { m_name = name; } 300 | 301 | boost::intrusive_ptr refpacket_create(void* argrefs) { 302 | return new refpacket_t(*(aref_t*)argrefs); 303 | } 304 | boost::intrusive_ptr valpacket_create(void* argrefs) { 305 | return new valpacket_t(*(aref_t*)argrefs); 306 | } 307 | 308 | virtual rpc_ret_t call_byid(rpc_client_basebase* client, void* refs) { 309 | client_packet packet(refs); 310 | packet.stub = this; 311 | return packet.t_call_byid(client, *(aref_t*)refs); 312 | } 313 | virtual rpc_ret_t call_byname(rpc_client_basebase* client, void* refs) { 314 | client_packet packet(refs); 315 | packet.stub = this; 316 | return packet.t_call_byname(client, *(aref_t*)refs); 317 | } 318 | 319 | virtual void send_id_args(rpc_client_basebase* client, client_packet_base* packet) { 320 | packet->stub = this; 321 | packet->send_id_args(client); 322 | } 323 | virtual void send_nm_args(rpc_client_basebase* client, client_packet_base* packet) { 324 | packet->stub = this; 325 | packet->send_nm_args(client); 326 | } 327 | virtual void read_args(rpc_client_basebase* client, client_packet_base* packet) { 328 | packet->stub = this; 329 | packet->read_args(client); 330 | } 331 | }; 332 | 333 | template class Input, 334 | template class Output 335 | > 336 | class rpc_client : public rpc_client_base 337 | { 338 | DECLARE_NONE_COPYABLE_CLASS(rpc_client) 339 | public: 340 | typedef rpc_client self_t; 341 | typedef Input input_t; 342 | typedef Output output_t; 343 | typedef client_object_input co_input_t; 344 | typedef client_object_output co_output_t; 345 | 346 | co_input_t m_co_input; 347 | co_output_t m_co_output; 348 | 349 | rpc_client(IDuplexStream* duplex) 350 | : rpc_client_base(duplex) 351 | { 352 | m_input.set_bufsize(8*1024); 353 | m_output.set_bufsize(8*1024); 354 | m_co_input.attach(&m_input); 355 | m_co_output.attach(&m_output); 356 | 357 | this->m_id = 1; // 358 | m_input.attach(m_duplex); 359 | m_output.attach(m_duplex); 360 | 361 | // 1st 'this' is as SessionObject 362 | // 2nd 'this' is as Client 363 | this->bind_client(this); 364 | } 365 | // @Override 366 | unsigned read_seqid() { 367 | var_size_t seqid; 368 | m_input >> seqid; 369 | return seqid.t; 370 | } 371 | 372 | //! @brief 查询远程对象 373 | //! 根据 Class 是 GlobaleScope, 还是 SessionScope, 自动决定如何查询 374 | template 375 | bool retrieve(boost::intrusive_ptr& x, const std::string& instanceName) { 376 | x.reset(new Class); 377 | x->bind_client(this); 378 | return this->retrieve_1(*x, instanceName); 379 | } 380 | //! @brief 创建远程对象 381 | //! 根据 Class 是 GlobaleScope, 还是 SessionScope, 自动决定如何创建 382 | template 383 | void create(boost::intrusive_ptr& x, const std::string& instanceName) { 384 | x.reset(new Class); 385 | x->bind_client(this); 386 | this->create_1(*x, instanceName); 387 | } 388 | //! @brief 创建匿名远程对象 389 | //! 根据 Class 是 GlobaleScope, 还是 SessionScope, 自动决定如何创建 390 | //! 匿名的远程对象只有ID,没有名字 391 | template 392 | void create(boost::intrusive_ptr& x) { 393 | x.reset(new Class); 394 | x->bind_client(this); 395 | this->create_0(*x); 396 | } 397 | //! @brief 将对象 x 绑定到该客户端 398 | //! @note 仅由 RPC_ADD_MF 来引用 399 | template 400 | void bind_stub(client_stub_ref& fref, const std::string& funName, Class* x) { 401 | client_stub_i*&rp = m_stubTable[funName]; 402 | if (NULL == rp) 403 | rp = new client_stub(funName); 404 | fref.bind(x, rp); 405 | } 406 | 407 | class CreateHelper0 { 408 | rpc_client* m_client; 409 | public: 410 | template 411 | operator boost::intrusive_ptr() const { 412 | boost::intrusive_ptr obj(new Class()); 413 | obj->bind_client(m_client); 414 | m_client->create_0(*obj); 415 | return obj; 416 | } 417 | explicit CreateHelper0(rpc_client* client) : m_client(client) {} 418 | }; 419 | class CreateHelper1 { 420 | rpc_client* m_client; 421 | const std::string* m_instanceName; 422 | public: 423 | template 424 | operator boost::intrusive_ptr() const { 425 | boost::intrusive_ptr obj(new Class()); 426 | obj->bind_client(m_client); 427 | m_client->create_1(*obj, *m_instanceName); 428 | return obj; 429 | } 430 | explicit CreateHelper1(rpc_client* client, const std::string* instanceName) 431 | : m_client(client), m_instanceName(instanceName) {} 432 | }; 433 | friend class CreateHelper0; 434 | friend class CreateHelper1; 435 | 436 | //! sample usage: FileObjPtr file = client.create(); 437 | CreateHelper0 create() { return CreateHelper0(this); } 438 | 439 | //! sample usage: EchoPtr echo = client.create("global_echo1"); 440 | CreateHelper1 create(const std::string& instanceName) 441 | { return CreateHelper1(this, &instanceName); } 442 | 443 | private: 444 | input_t m_input; 445 | output_t m_output; 446 | }; 447 | 448 | // must defined here, all required types are complete here 449 | inline void client_packet_base::async_packet(rpc_client_basebase* vpclient) { 450 | rpc_client_base* client = static_cast(vpclient); 451 | client->async_packet(this); 452 | } 453 | 454 | 455 | } } // namespace nark::rpc 456 | 457 | #endif // __nark_rpc_client_h__ 458 | 459 | 460 | -------------------------------------------------------------------------------- /src/nark/rpc/client_io.hpp: -------------------------------------------------------------------------------- 1 | /* vim: set tabstop=4 : */ 2 | #ifndef __nark_rpc_client_io_h__ 3 | #define __nark_rpc_client_io_h__ 4 | 5 | #if defined(_MSC_VER) && (_MSC_VER >= 1020) 6 | # pragma once 7 | # pragma warning(disable: 4819) 8 | #endif 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "rpc_basic.hpp" 15 | 16 | namespace nark { namespace rpc { 17 | 18 | template class client_object_input 19 | { 20 | Input* p; 21 | 22 | public: 23 | explicit client_object_input(Input* input = 0) : p(input) {} 24 | 25 | void attach(Input* input) { p = input; } 26 | Input& get() const { return *p; } 27 | 28 | template client_object_input& operator>>(boost::intrusive_ptr& x) 29 | { 30 | return *this >> *x; 31 | } 32 | 33 | template client_object_input& operator &(T& x) { return *this >> x; } 34 | 35 | // T must derived from remote_object 36 | template client_object_input& operator>>(T*& x) { return *this >> *x; } 37 | template client_object_input& operator>>(T& x) 38 | { 39 | // do nothing... 40 | typename T::SFINAE_ro_self_t* for_check = 0; 41 | (void)(for_check); 42 | // var_size_t objid; 43 | // *p >> objid; 44 | // if (x.getID() == 0) 45 | // { 46 | // if (0 == objid.t) 47 | // { 48 | // string_appender<> oss; 49 | // oss << "load remote_object from server failed, objid = 0"; 50 | // throw rpc_exception(oss.str()); 51 | // } 52 | // x.setID(objid.t); 53 | // } 54 | // else if (x.getID() != objid.t) 55 | // { 56 | // string_appender<> oss; 57 | // oss << "load remote_object from server failed, server_objid = " << objid.t 58 | // << "local objid = " << x.getID(); 59 | // throw rpc_exception(oss.str()); 60 | // } 61 | return *this; 62 | } 63 | 64 | // do nothing... 65 | template client_object_input& operator &(rpc_in x) { return *this; } 66 | template client_object_input& operator>>(rpc_in x) { return *this; } 67 | 68 | template client_object_input& operator &(rpc_out x) { *p >> x.r; return *this; } 69 | template client_object_input& operator>>(rpc_out x) { *p >> x.r; return *this; } 70 | 71 | template client_object_input& operator &(rpc_inout x) { *p >> x.r; return *this; } 72 | template client_object_input& operator>>(rpc_inout x) { *p >> x.r; return *this; } 73 | }; 74 | 75 | template class client_object_output 76 | { 77 | Output* p; 78 | 79 | public: 80 | explicit client_object_output(Output* output = 0) : p(output) {} 81 | 82 | void attach(Output* output) { p = output; } 83 | void flush() { p->flush(); } 84 | Output& get() const { return *p; } 85 | 86 | template client_object_output& operator<<(const boost::intrusive_ptr& x) 87 | { 88 | return *this << *x; 89 | } 90 | 91 | template client_object_output& operator &(const T& x) { return *this << x; } 92 | 93 | // T must derived from remote_object 94 | template client_object_output& operator<<( T* x) { return *this << *x; } 95 | template client_object_output& operator<<(const T* x) { return *this << *x; } 96 | template client_object_output& operator<<(const T& x) 97 | { 98 | typename T::SFINAE_ro_self_t* for_check = 0; 99 | (void)(for_check); 100 | *p << var_size_t(x.getID()); 101 | return *this; 102 | } 103 | 104 | template client_object_output& operator &(rpc_in x) { *p << x.r; return *this; } 105 | template client_object_output& operator<<(rpc_in x) { *p << x.r; return *this; } 106 | 107 | // do nothing... 108 | template client_object_output& operator &(rpc_out x) { return *this; } 109 | template client_object_output& operator<<(rpc_out x) { return *this; } 110 | 111 | template client_object_output& operator &(rpc_inout x) { *p << x.r; return *this; } 112 | template client_object_output& operator<<(rpc_inout x) { *p << x.r; return *this; } 113 | }; 114 | 115 | } } // namespace::nark::rpc 116 | 117 | 118 | #endif // __nark_rpc_client_io_h__ 119 | -------------------------------------------------------------------------------- /src/nark/rpc/doxygen_doc.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockeet/nark-rpc/af7ce41ed03ddb8bef3e49572ccf8dd97f27c83e/src/nark/rpc/doxygen_doc.hpp -------------------------------------------------------------------------------- /src/nark/rpc/pp_arglist_type.hpp: -------------------------------------------------------------------------------- 1 | /* vim: set tabstop=4 : */ 2 | #define ArgCount BOOST_PP_ITERATION() 3 | #define PP_ArgListRef(z, n, d) typename ArgVal::xref_t a##n d 4 | #define PP_ArgListVal(z, n, d) typename ArgVal::val_t a##n d 5 | #define PP_ArgListDeRef(z, n, d) d##n.r 6 | #define PP_InitMemList(z, n, d) a##n(d##n) 7 | #define PP_InitMemList2(z, n, d) a##n(ArgVal::val(d##n)) 8 | #define PP_InitMemList3(z, n, d) argval_sync(a##n,d##n); 9 | 10 | template 11 | struct arglist_val 12 | { 13 | // IF_RPC_SERVER(boost::intrusive_ptr, ThisType*) self; 14 | boost::intrusive_ptr self; 15 | BOOST_PP_REPEAT(ArgCount, PP_ArgListVal, ;) 16 | 17 | arglist_val(//IF_RPC_SERVER(boost::intrusive_ptr, ThisType*) self 18 | boost::intrusive_ptr self 19 | BOOST_PP_ENUM_TRAILING(ArgCount, PP_ArgListRef, BOOST_PP_EMPTY())) 20 | : self(self)BOOST_PP_ENUM_TRAILING(ArgCount, PP_InitMemList, a) 21 | {} 22 | template 23 | arglist_val(boost::mpl::true_ placeHolder, ArgListRef& y) 24 | : self(y.self)BOOST_PP_ENUM_TRAILING(ArgCount, PP_InitMemList2, y.a) 25 | {} 26 | arglist_val() {} 27 | 28 | template void sync(ArgListRef& refs) { 29 | // assert(0); // now disabled 30 | self = refs.self; 31 | BOOST_PP_REPEAT(ArgCount, PP_InitMemList3, refs.a) 32 | } 33 | }; 34 | template 35 | struct arglist_ref 36 | { 37 | // IF_RPC_SERVER(boost::intrusive_ptr, ThisType*) &self; 38 | boost::intrusive_ptr self; 39 | BOOST_PP_REPEAT(ArgCount, PP_ArgListRef, ;) 40 | 41 | arglist_ref(//IF_RPC_SERVER(boost::intrusive_ptr, ThisType*) &self 42 | boost::intrusive_ptr self 43 | BOOST_PP_ENUM_TRAILING(ArgCount, PP_ArgListRef, BOOST_PP_EMPTY())) 44 | : self(self)BOOST_PP_ENUM_TRAILING(ArgCount, PP_InitMemList, a) 45 | {} 46 | template 47 | arglist_ref(boost::mpl::true_ placeHolder, ArgListVal& y) 48 | : self(y.self)BOOST_PP_ENUM_TRAILING(ArgCount, PP_InitMemList, y.a) 49 | {} 50 | #define PP_IO_ArgList(z, n, load_save) load_save a##n 51 | template void load(DataIO& dio) { 52 | dio >> self BOOST_PP_REPEAT(ArgCount, PP_IO_ArgList, >>); 53 | } 54 | template void save(DataIO& dio) const { 55 | dio << self BOOST_PP_REPEAT(ArgCount, PP_IO_ArgList, <<); 56 | } 57 | #undef PP_IO_ArgList 58 | }; 59 | 60 | #undef PP_InitMemList3 61 | #undef PP_InitMemList2 62 | #undef PP_InitMemList 63 | #undef PP_ArgListDeRef 64 | #undef PP_ArgListVal 65 | #undef PP_ArgListRef 66 | #undef ArgCount 67 | 68 | 69 | -------------------------------------------------------------------------------- /src/nark/rpc/pp_client_stub.hpp: -------------------------------------------------------------------------------- 1 | /* vim: set tabstop=4 : */ 2 | #define ArgCount BOOST_PP_ITERATION() 3 | #define ArgDeclare(z, n, d) Arg##n a##n d 4 | #define PP_ArgListRef(z, n, d) typename ArgVal::xref_t a##n d 5 | #define PP_ArgListVal(z, n, d) typename ArgVal::val_t a##n d 6 | 7 | #define PP_ArgListDeRef(z, n, d) ArgVal::deref(d##n) 8 | //#define PP_ArgListGetVal(z, n, d) ArgVal::val(d##n) 9 | 10 | #define FunctionType rpc_ret_t (ThisType::*)(BOOST_PP_ENUM_PARAMS(ArgCount, Arg)) 11 | 12 | template 13 | class client_packet 14 | < Client 15 | , arglist_ref 16 | , FunctionType 17 | > 18 | : public client_packet_io 19 | < Client 20 | , FunctionType 21 | , void (ThisType::*)(const client_packet_base&BOOST_PP_ENUM_TRAILING_PARAMS(ArgCount, Arg)) 22 | > 23 | { 24 | public: 25 | typedef arglist_ref arglist_ref_t; 26 | arglist_ref_t refs; 27 | 28 | client_packet(ThisType* self BOOST_PP_ENUM_TRAILING(ArgCount, PP_ArgListRef, BOOST_PP_EMPTY())) 29 | : refs(*self BOOST_PP_ENUM_TRAILING_PARAMS(ArgCount, a)) 30 | {} 31 | 32 | explicit client_packet(arglist_ref_t& argrefs) : refs(argrefs) { } 33 | 34 | rpc_ret_t call_byid (rpc_client_basebase* client) { return this->t_call_byid (client, refs); } 35 | rpc_ret_t call_byname(rpc_client_basebase* client) { return this->t_call_byname(client, refs); } 36 | void send_id_args(rpc_client_basebase* client) { return this->t_send_id_args(client, refs); } 37 | void send_nm_args(rpc_client_basebase* client) { return this->t_send_nm_args(client, refs); } 38 | void read_args(rpc_client_basebase* client) { return this->t_read_args(client, refs); } 39 | 40 | virtual void on_return() { 41 | assert(NULL != this->on_ret); // on_ret is a function pointer 42 | rpc_client_basebase* client = refs.self->get_ext_ptr(); 43 | this->t_read_args(client, refs); 44 | (refs.self.get()->*this->on_ret)(*this BOOST_PP_ENUM_TRAILING(ArgCount, PP_ArgListDeRef, refs.a)); 45 | } 46 | }; 47 | 48 | template 49 | class client_packet 50 | < Client 51 | , arglist_ref * 52 | , FunctionType 53 | > 54 | : public client_packet_io 55 | < Client 56 | , FunctionType 57 | , void (ThisType::*)(const client_packet_base&BOOST_PP_ENUM_TRAILING_PARAMS(ArgCount, Arg)) 58 | > 59 | { 60 | public: 61 | typedef arglist_ref arglist_ref_t; 62 | arglist_ref_t* refs; 63 | 64 | explicit client_packet(void* refs) : refs((arglist_ref_t*)refs) {} 65 | 66 | rpc_ret_t call_byid (rpc_client_basebase* client) { return this->t_call_byid (client, *refs); } 67 | rpc_ret_t call_byname(rpc_client_basebase* client) { return this->t_call_byname(client, *refs); } 68 | void send_id_args(rpc_client_basebase* client) { return this->t_send_id_args(client, *refs); } 69 | void send_nm_args(rpc_client_basebase* client) { return this->t_send_nm_args(client, *refs); } 70 | void read_args(rpc_client_basebase* client) { return this->t_read_args(client, *refs); } 71 | virtual void on_return() { 72 | assert(NULL != this->on_ret); // on_ret is a function pointer 73 | rpc_client_basebase* client = refs->self->get_ext_ptr(); 74 | this->t_read_args(client, *refs); 75 | (refs->self.get()->*this->on_ret)(*this BOOST_PP_ENUM_TRAILING(ArgCount, PP_ArgListDeRef, refs->a)); 76 | } 77 | }; 78 | 79 | // hold args references 80 | template 81 | class client_packet 82 | < Client 83 | , arglist_val 84 | , FunctionType 85 | > 86 | : public client_packet_io 87 | < Client 88 | , FunctionType 89 | , void (ThisType::*)(const client_packet_base&BOOST_PP_ENUM_TRAILING_PARAMS(ArgCount, Arg)) 90 | > 91 | { 92 | public: 93 | typedef arglist_ref arglist_ref_t; 94 | typedef arglist_val arglist_val_t; 95 | arglist_val_t vals; 96 | 97 | client_packet(ThisType* self BOOST_PP_ENUM_TRAILING(ArgCount, ArgDeclare, BOOST_PP_EMPTY())) 98 | : vals(*self BOOST_PP_ENUM_TRAILING_PARAMS(ArgCount, a)) 99 | {} 100 | explicit client_packet(arglist_ref_t& argrefs) 101 | : vals(boost::mpl::true_(), argrefs) 102 | {} 103 | 104 | rpc_ret_t call_byid(rpc_client_basebase* client) { 105 | arglist_ref_t refs(boost::mpl::true_(), vals); 106 | return this->t_call_byid(client, refs); 107 | } 108 | rpc_ret_t call_byname(rpc_client_basebase* client) { 109 | arglist_ref_t refs(boost::mpl::true_(), vals); 110 | return this->t_call_byname(client, refs); 111 | } 112 | void send_id_args(rpc_client_basebase* client) { 113 | arglist_ref_t refs(boost::mpl::true_(), vals); 114 | return this->t_send_id_args(client, refs); 115 | } 116 | void send_nm_args(rpc_client_basebase* client) { 117 | arglist_ref_t refs(boost::mpl::true_(), vals); 118 | return this->t_send_nm_args(client, refs); 119 | } 120 | void read_args(rpc_client_basebase* client) { 121 | arglist_ref_t refs(boost::mpl::true_(), vals); 122 | return this->t_read_args(client, refs); 123 | } 124 | virtual void on_return() { 125 | assert(NULL != this->on_ret); // on_ret is a function pointer 126 | arglist_ref_t refs(boost::mpl::true_(), vals); 127 | rpc_client_basebase* client = vals.self->get_ext_ptr(); 128 | this->t_read_args(client, refs); 129 | (refs.self.get()->*this->on_ret)(*this BOOST_PP_ENUM_TRAILING(ArgCount, PP_ArgListDeRef, refs.a)); 130 | } 131 | }; 132 | 133 | //#undef PP_ArgListGetVal 134 | #undef PP_ArgListDeRef 135 | 136 | template 137 | class client_stub_ref 138 | { 139 | typedef void (ThisType::*myfun_t)(const client_packet_base&BOOST_PP_ENUM_TRAILING_PARAMS(ArgCount, Arg)); 140 | typedef arglist_ref arglist_ref_t; 141 | typedef arglist_val arglist_val_t; 142 | typedef client_packet_fun packet_fun_t; 143 | client_stub_i* m_meta; 144 | ThisType* m_self; 145 | myfun_t on_return; 146 | 147 | public: 148 | client_stub_ref() : m_meta(0), m_self(0), on_return(0) {} 149 | 150 | template 151 | void set_async_callback(void (ThisDerived::*pf)(const client_packet_base& 152 | BOOST_PP_ENUM_TRAILING_PARAMS(ArgCount, Arg))) 153 | { 154 | if (false) 155 | { // only do compile-time check, this sentence will be eliminated in obj-code 156 | ThisType* pbase = (ThisDerived*)NULL; 157 | (void)pbase; 158 | } 159 | on_return = static_cast(pf); 160 | } 161 | 162 | void bind(ThisType* self, client_stub_i* impl) { 163 | m_meta = impl; 164 | m_self = self; 165 | } 166 | 167 | rpc_ret_t operator()(BOOST_PP_ENUM(ArgCount, ArgDeclare, BOOST_PP_EMPTY())) { 168 | arglist_ref_t argrefs(m_self BOOST_PP_ENUM_TRAILING_PARAMS(ArgCount, a)); 169 | rpc_client_basebase* client = m_self->get_ext_ptr(); 170 | // call_byid will fall back to by name if callid is zero 171 | return m_meta->call_byid(client, &argrefs); 172 | } 173 | 174 | rpc_ret_t byname(BOOST_PP_ENUM(ArgCount, ArgDeclare, BOOST_PP_EMPTY())) { 175 | arglist_ref_t argrefs(m_self BOOST_PP_ENUM_TRAILING_PARAMS(ArgCount, a)); 176 | rpc_client_basebase* client = m_self->get_ext_ptr(); 177 | // always call by name 178 | return m_meta->call_byname(client, &argrefs); 179 | } 180 | 181 | void async(BOOST_PP_ENUM(ArgCount, ArgDeclare, BOOST_PP_EMPTY())) { 182 | arglist_ref_t args(m_self BOOST_PP_ENUM_TRAILING_PARAMS(ArgCount, a)); 183 | rpc_client_basebase* client = m_self->get_ext_ptr(); 184 | boost::intrusive_ptr packet = m_meta->valpacket_create(&args); 185 | packet_fun_t* p = (packet_fun_t*)(packet.get()); 186 | assert(NULL != on_return); 187 | p->on_ret = on_return; 188 | packet->stub = this->m_meta; 189 | packet->how_call = rpc_call_asynch_ordered; 190 | if (packet->stub->m_callid) // prefer by id 191 | m_meta->send_id_args(client, packet.get()); 192 | else // fall back to by name 193 | m_meta->send_nm_args(client, packet.get()); 194 | packet->async_packet(client); 195 | } 196 | void async_byname(BOOST_PP_ENUM(ArgCount, ArgDeclare, BOOST_PP_EMPTY())) { 197 | arglist_ref_t args(m_self BOOST_PP_ENUM_TRAILING_PARAMS(ArgCount, a)); 198 | boost::intrusive_ptr packet = m_meta->valpacket_create(&args); 199 | rpc_client_basebase* client = m_self->get_ext_ptr(); 200 | packet_fun_t* p = (packet_fun_t*)(packet.get()); 201 | assert(on_return); 202 | p->on_ret = on_return; 203 | packet->stub = this->m_meta; 204 | packet->how_call = rpc_call_asynch_ordered; 205 | m_meta->send_nm_args(client, packet.get()); 206 | packet->async_packet(client); 207 | } 208 | 209 | rpc_ret_t reap(BOOST_PP_ENUM(ArgCount, ArgDeclare, BOOST_PP_EMPTY())) { 210 | return this->retv; 211 | } 212 | }; 213 | 214 | #undef FunctionType 215 | #undef PP_ArgListVal 216 | #undef PP_ArgListRef 217 | #undef ArgDeclare 218 | #undef ArgCount 219 | 220 | -------------------------------------------------------------------------------- /src/nark/rpc/pp_server_stub.hpp: -------------------------------------------------------------------------------- 1 | /* vim: set tabstop=4 : */ 2 | #define ArgCount BOOST_PP_ITERATION() 3 | template 4 | class server_packet 5 | : public server_packet_base 6 | { 7 | public: 8 | typedef rpc_ret_t (ThisType::*function_t)(BOOST_PP_ENUM_PARAMS(ArgCount, Arg)); 9 | typedef arglist_val aval_t; 10 | typedef arglist_ref aref_t; 11 | aval_t argvals; 12 | #define PP_ArgListDeRef(z, n, d) ArgVal::deref(argvals.d##n) 13 | void invoke_f(function_t fun) 14 | { 15 | this->retv = (argvals.self.get()->*fun)(BOOST_PP_ENUM(ArgCount, PP_ArgListDeRef, a)); 16 | } 17 | #undef PP_ArgListDeRef 18 | }; 19 | #undef ArgCount 20 | -------------------------------------------------------------------------------- /src/nark/rpc/rpc_basic.cpp: -------------------------------------------------------------------------------- 1 | /* vim: set tabstop=4 : */ 2 | #include "rpc_basic.hpp" 3 | #include 4 | 5 | namespace nark { namespace rpc { 6 | 7 | RoCreator::~RoCreator() 8 | { 9 | } 10 | 11 | remote_object::~remote_object() 12 | { 13 | 14 | } 15 | 16 | rpc_exception::rpc_exception(const char* szMsg) 17 | : m_message(szMsg) 18 | { } 19 | rpc_exception::rpc_exception(const std::string& szMsg) 20 | : m_message(szMsg) 21 | { } 22 | rpc_exception::~rpc_exception() throw() {} 23 | 24 | const char* rpc_exception::what() const throw() { return m_message.c_str(); } 25 | 26 | 27 | //! 使用 classID 创建对象 28 | remote_object* ObjectFactoryBase::create(unsigned classID) const 29 | { 30 | const RoCreator* meta = m_map.get_byid(classID); 31 | remote_object* obj = meta->create(); 32 | obj->m_classMeta = meta; 33 | return obj; 34 | } 35 | //! 使用 className 创建对象 36 | remote_object* ObjectFactoryBase::create(const std::string& className) const 37 | { 38 | const RoCreator* meta = m_map.get_byname(className); 39 | if (meta) 40 | { 41 | remote_object* obj = meta->create(); 42 | obj->m_classMeta = meta; 43 | return obj; 44 | } 45 | string_appender<> oss; 46 | oss << "ObjectFactory::create: can not find class: " << className; 47 | throw std::runtime_error(oss.str()); 48 | } 49 | //! @brief 将类信息加入工厂 50 | //! 这个函数会为 meta 分配一个 id,该 id 在整个生存期都有效 51 | bool ObjectFactoryBase::add(RoCreator* meta) 52 | { 53 | assert(meta); 54 | RoCreator* meta2; 55 | long classID = m_map.add_ptr(meta, meta->className, &meta2); 56 | if (meta2 == meta) 57 | { 58 | return false; 59 | } 60 | else if (NULL != meta2) 61 | { 62 | throw std::runtime_error("class existed"); 63 | } 64 | meta->classID = classID; 65 | return true; 66 | } 67 | const RoCreator* ObjectFactoryBase::FindMetaByName(const std::string& className) const 68 | { 69 | const RoCreator* meta = m_map.get_byname(className); 70 | return meta; 71 | } 72 | 73 | } } // namespace nark::rpc 74 | 75 | -------------------------------------------------------------------------------- /src/nark/rpc/rpc_basic.hpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rockeet/nark-rpc/af7ce41ed03ddb8bef3e49572ccf8dd97f27c83e/src/nark/rpc/rpc_basic.hpp -------------------------------------------------------------------------------- /src/nark/rpc/rpc_interface.hpp: -------------------------------------------------------------------------------- 1 | BEGIN_RPC_ADD_MF_EX(my_self_t, "ServerMain") 2 | RPC_ADD_MF(createSessionObject) 3 | RPC_ADD_MF(createGlobaleObject) 4 | RPC_ADD_MF(createNamedGlobaleObject) 5 | RPC_ADD_MF(createNamedSessionObject) 6 | RPC_ADD_MF(retrieveGlobaleObject) 7 | RPC_ADD_MF(retrieveSessionObject) 8 | RPC_ADD_MF(removeSessionObject) 9 | END_RPC_ADD_MF() 10 | 11 | //! create an servant, and return its proxy. proxy.m_id will be got from server 12 | RPC_DECLARE_MF_EX(createGlobaleObject, (var_size_t* servantID, const std::string& className), ;) 13 | RPC_DECLARE_MF_EX(createSessionObject, (var_size_t* servantID, const std::string& className), ;) 14 | RPC_DECLARE_MF_EX(createNamedSessionObject, (var_size_t* servantID, std::string& className, const std::string& instanceName), ;) 15 | 16 | //! if failed, className take the existed className of the existed object 17 | RPC_DECLARE_MF_EX(createNamedGlobaleObject, (var_size_t* servantID, std::string& className, const std::string& instanceName), ;) 18 | 19 | RPC_DECLARE_MF_EX(retrieveGlobaleObject, (var_size_t* servantID, const std::string& instanceName), ;) 20 | RPC_DECLARE_MF_EX(retrieveSessionObject, (var_size_t* servantID, const std::string& instanceName), ;) 21 | 22 | RPC_DECLARE_MF_EX(removeSessionObject, (var_size_t servantID), ;) 23 | -------------------------------------------------------------------------------- /src/nark/rpc/server.cpp: -------------------------------------------------------------------------------- 1 | /* vim: set tabstop=4 : */ 2 | #include "server.hpp" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /** 9 | @brief 本地接口第一次调用远程对象的方法时,在 rpc server 上创建远程对象 10 | 11 | remote_object 就是一个 id,状态只在 rpc server 上保持 12 | */ 13 | 14 | namespace nark { namespace rpc { 15 | 16 | class rpc_server_base::MyMutex { 17 | public: 18 | boost::mutex sessionList; 19 | boost::mutex stubTable; 20 | boost::mutex globaleScopeObjects; 21 | boost::mutex globaleScopeFactory; 22 | boost::mutex sessionScopeFactory; 23 | }; 24 | 25 | server_stub_i::~server_stub_i() 26 | { 27 | } 28 | 29 | remote_object* session_base::create_object() 30 | { 31 | assert(0); 32 | return 0; 33 | } 34 | 35 | session_base::session_base(class rpc_server_base* owner) 36 | : m_owner(owner) 37 | , m_stubTable(&owner->m_stubTable) 38 | , m_globaleScopeObjects(&owner->m_globaleScopeObjects) 39 | , m_sessionScopeFactory(&owner->m_sessionScopeFactory) 40 | { 41 | // m_sessionScopeObjects.add_ptr(this); 42 | m_thread = NULL; 43 | } 44 | 45 | session_base::~session_base() 46 | { 47 | m_sessionScopeObjects.destroy(); 48 | delete m_thread; 49 | } 50 | 51 | void session_base::call(server_packet_base& header) 52 | { 53 | switch (header.how_call) { 54 | default: 55 | assert(0); 56 | break; 57 | case rpc_call_asynch_ordered: 58 | // break; 59 | case rpc_call_asynch_noorder: { 60 | // assert(!"implemented now"); 61 | header.stub->sync_call(this, &header); 62 | // QueueItem t; 63 | // t.args = stub->read_args(m_so_input); 64 | // t.stub = stub; 65 | } 66 | break; 67 | case rpc_call_synch: 68 | header.stub->sync_call(this, &header); 69 | break; 70 | } 71 | } 72 | 73 | void session_base::start() 74 | { 75 | m_thread = new boost::thread(boost::bind(&session_base::run, this)); 76 | } 77 | 78 | void session_base::run() 79 | { 80 | #if BOOST_VERSION > 103301 81 | boost::this_thread::at_thread_exit(boost::bind(&rpc_server_base::removeSession, m_owner, this)); 82 | #endif 83 | try { 84 | this->m_id = m_sessionScopeObjects.add_ptr(this); 85 | assert(1 == this->m_id); 86 | m_bRun = true; 87 | while (m_bRun) { 88 | server_packet_base header; 89 | this->read_header(header); 90 | call(header); 91 | } 92 | } 93 | catch (const SocketException& exp) { 94 | printf("catch: %s, close the session !\n", exp.what()); 95 | } 96 | catch (const EndOfFileException& exp) { 97 | printf("catch: %s, close the session!\n", exp.what()); 98 | } 99 | catch (const std::exception& exp) { 100 | printf("catch: %s, close the session!\n", exp.what()); 101 | } 102 | #if BOOST_VERSION <= 103301 103 | m_owner->removeSession(this); 104 | #endif 105 | } 106 | 107 | 108 | rpc_server_base::rpc_server_base(IAcceptor* acceptor) 109 | : m_acceptor(acceptor) 110 | { 111 | m_mutex = new MyMutex; 112 | } 113 | rpc_server_base::~rpc_server_base() 114 | { 115 | for (int nRetry = 0; nRetry < 100; ++nRetry) { 116 | long remainSessions; 117 | { 118 | boost::mutex::scoped_lock lock(m_mutex->sessionList); 119 | remainSessions = m_sessionList.size(); 120 | if (0 == remainSessions) 121 | break; 122 | } 123 | DEBUG_printf("%ld sessions is not still active\n", remainSessions); 124 | // thread::Thread::sleep(100); 125 | } 126 | m_globaleScopeObjects.destroy(); 127 | m_globaleScopeFactory.destroy(); 128 | m_sessionScopeFactory.destroy(); 129 | m_stubTable.destroy(); 130 | delete m_mutex; 131 | } 132 | 133 | bool rpc_server_base::addto_factroy(ClassMeta* meta, GlobaleScope* scopeTag) 134 | { 135 | return m_globaleScopeFactory.add(meta); 136 | } 137 | bool rpc_server_base::addto_factroy(ClassMeta* meta, SessionScope* scopeTag) 138 | { 139 | return m_sessionScopeFactory.add(meta); 140 | } 141 | 142 | void rpc_server_base::gen_stubs(ClassMeta* meta) 143 | { 144 | for (int i = 0, n = meta->stubs.size(); i != n; ++i) { 145 | server_stub_i* s = meta->stubs[i], *s2 = NULL; 146 | s->m_id = m_stubTable.add_ptr(s, s->m_name, &s2); 147 | assert(0 == s2); 148 | } 149 | } 150 | 151 | void rpc_server_base::removeSession(boost::intrusive_ptr session) 152 | { 153 | boost::mutex::scoped_lock lock(m_mutex->sessionList); 154 | m_sessionList.erase(session); 155 | } 156 | 157 | void rpc_server_base::start() 158 | { 159 | // m_pipeline.setQueueSize(50); 160 | // m_pipeline.add_step(); 161 | 162 | while (true) 163 | { 164 | // accept a server connection... 165 | 166 | if (session_base* session = createSession()) { 167 | { 168 | boost::mutex::scoped_lock lock(m_mutex->sessionList); 169 | m_sessionList.insert(session); 170 | } 171 | session->start(); 172 | } else 173 | break; 174 | } 175 | } 176 | 177 | void rpc_server_base::add_servant_imp(GlobaleScope* servant, const std::string& name) 178 | { 179 | boost::mutex::scoped_lock lock(m_mutex->globaleScopeObjects); 180 | assert(servant); 181 | GlobaleScope* servant2 = NULL; 182 | long id = m_globaleScopeObjects.add_ptr(servant, name, &servant2); 183 | servant->setID(id); 184 | servant->set_ext_ptr(this); 185 | } 186 | 187 | //! do not delete servant, only remove from rpc_server 188 | void rpc_server_base::remove_servant(GlobaleScopePtr servant) 189 | { 190 | boost::mutex::scoped_lock lock(m_mutex->globaleScopeObjects); 191 | assert(servant); 192 | m_globaleScopeObjects.remove(servant->getID()); 193 | } 194 | 195 | rpc_ret_t rpc_server_base:: 196 | createNamedGlobaleObject(var_size_t* servantID, std::string& className, const std::string& name) 197 | { 198 | GlobaleScope* x; 199 | { 200 | boost::mutex::scoped_lock lock(m_mutex->globaleScopeObjects); 201 | x = m_globaleScopeObjects.get_rawptr_byname(name); 202 | } 203 | if (0 == x) { 204 | const RoCreator* creator; 205 | { 206 | boost::mutex::scoped_lock lock(m_mutex->globaleScopeObjects); 207 | creator = m_globaleScopeFactory.FindMetaByName(className); 208 | } 209 | if (creator) { 210 | x = (GlobaleScope*)creator->create(); 211 | x->m_classMeta = creator; 212 | GlobaleScope* y; 213 | long id = m_globaleScopeObjects.add_ptr(x, name, &y); 214 | assert(0 == y); 215 | x->setID(id); 216 | servantID->t = id; 217 | return 0; 218 | } 219 | else 220 | return -1; // no creator, class not registered 221 | } 222 | else { 223 | className = x->getClassName(); 224 | servantID->t = x->getID(); 225 | return 1; 226 | } 227 | } 228 | 229 | rpc_ret_t rpc_server_base:: 230 | createGlobaleObject(var_size_t* servantID, const std::string& className) 231 | { 232 | const RoCreator* creator; 233 | { 234 | boost::mutex::scoped_lock lock(m_mutex->globaleScopeObjects); 235 | creator = m_globaleScopeFactory.FindMetaByName(className); 236 | } 237 | if (creator) { 238 | GlobaleScope* x = (GlobaleScope*)creator->create(); 239 | long id = m_globaleScopeObjects.add_ptr(x); 240 | x->m_classMeta = creator; 241 | x->setID(id); 242 | x->set_ext_ptr(this); 243 | servantID->t = id; 244 | return 0; 245 | } 246 | else 247 | return -1; 248 | } 249 | 250 | rpc_ret_t rpc_server_base:: 251 | retrieveGlobaleObject(var_size_t* servantID, const std::string& name) 252 | { 253 | boost::mutex::scoped_lock lock(m_mutex->globaleScopeObjects); 254 | GlobaleScopePtr x = m_globaleScopeObjects.get_byname(name); 255 | if (x) { 256 | servantID->t = x->getID(); 257 | return 0; 258 | } 259 | else { 260 | servantID->t = 0; 261 | return -1; 262 | } 263 | } 264 | 265 | rpc_ret_t session_base:: 266 | createSessionObject(var_size_t* servantID, const std::string& className) 267 | { 268 | SessionScopePtr x = m_owner->m_sessionScopeFactory.create(className); 269 | long id = m_sessionScopeObjects.add_ptr(x); 270 | x->setID(id); 271 | x->set_ext_ptr(this); 272 | servantID->t = id; 273 | return 0; 274 | } 275 | rpc_ret_t session_base:: 276 | createNamedSessionObject(var_size_t* servantID, std::string& className, const std::string& name) 277 | { 278 | SessionScope* x = m_sessionScopeObjects.get_rawptr_byname(name); 279 | if (NULL == x) { 280 | x = m_owner->m_sessionScopeFactory.create(className); 281 | SessionScope* y = NULL; 282 | long id = m_sessionScopeObjects.add_ptr(x, name, &y); 283 | assert(0 == y); 284 | x->setID(id); 285 | x->set_ext_ptr(this); 286 | servantID->t = id; 287 | return 0; 288 | } 289 | else { 290 | className = x->getClassName(); 291 | servantID->t = x->getID(); 292 | return -1; 293 | } 294 | } 295 | 296 | rpc_ret_t session_base:: 297 | retrieveSessionObject(var_size_t* servantID, const std::string& name) 298 | { 299 | SessionScopePtr x = m_sessionScopeObjects.get_byname(name); 300 | if (0 == x) { 301 | servantID->t = 0; 302 | return -1; 303 | } 304 | else { 305 | servantID->t = x->getID(); 306 | return 0; 307 | } 308 | } 309 | 310 | rpc_ret_t session_base:: 311 | createGlobaleObject(var_size_t* servantID, const std::string& className) 312 | { 313 | return m_owner->createGlobaleObject(servantID, className); 314 | } 315 | 316 | rpc_ret_t session_base:: 317 | createNamedGlobaleObject(var_size_t* servantID, std::string& className, const std::string& name) 318 | { 319 | return m_owner->createNamedGlobaleObject(servantID, className, name); 320 | } 321 | 322 | rpc_ret_t session_base:: 323 | retrieveGlobaleObject(var_size_t* servantID, const std::string& name) 324 | { 325 | return m_owner->retrieveGlobaleObject(servantID, name); 326 | } 327 | 328 | rpc_ret_t session_base::removeSessionObject(var_size_t servantID) 329 | { 330 | SessionScopePtr x = m_sessionScopeObjects.get_byid(servantID.t); 331 | m_sessionScopeObjects.remove(servantID.t); 332 | return 0; 333 | } 334 | 335 | } } // namespace::nark::rpc 336 | 337 | 338 | -------------------------------------------------------------------------------- /src/nark/rpc/server.hpp: -------------------------------------------------------------------------------- 1 | /* vim: set tabstop=4 : */ 2 | #ifndef __nark_rpc_server_h__ 3 | #define __nark_rpc_server_h__ 4 | 5 | #if defined(_MSC_VER) && (_MSC_VER >= 1020) 6 | # pragma once 7 | # pragma warning(disable: 4819) 8 | #endif 9 | 10 | /** 11 | @file rpc Server Side 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | //#include 21 | //#include 22 | //#include 23 | //#include 24 | //#include 25 | 26 | #define RPC_SERVER_SIDE 27 | 28 | #define IF_RPC_SERVER(Server, Client) Server 29 | 30 | #include "rpc_basic.hpp" 31 | #include "arg_traits.hpp" 32 | #include "server_io.hpp" 33 | #include 34 | 35 | namespace boost { 36 | class thread; // forward declaration 37 | } 38 | 39 | namespace nark { namespace rpc { 40 | 41 | /** 42 | * @{ 43 | * rpc 接口类中需要 typedef 一个类的别名: self_t 44 | * 45 | * - 使用宏的目的只有一个:推导 FunName 的参数表,将参数表转化成 tuple 46 | * - 参数表一般是: (T1, T2, T3) 等等 47 | * - 因此无法变成直接转调其它函数的形式,使用 tuple,就可以在 mem_fun_binder 中转调其他函数 48 | * 49 | * - 让一个成员函数成为远程方法,必须通过两个步骤来完成,一个步骤是声明,一个步骤是注册 50 | * - 声明时用 RPC_DECLARE_MF 51 | * - 注册时用 BEGIN_RPC_ADD_MF, RPC_ADD_MF, END_RPC_ADD_MF 52 | */ 53 | 54 | #define RPC_DECLARE_INTERFACE(Interface, Scope) \ 55 | class Interface : public Scope { \ 56 | public: \ 57 | BEGIN_RPC_ADD_MF(Interface, Scope) 58 | 59 | //! 在远程对象中声明一个成员函数 60 | #define RPC_DECLARE_MF_EX(FunName, ArgList, PureVirtualTag) \ 61 | virtual rpc_ret_t FunName ArgList PureVirtualTag \ 62 | typedef rpc_ret_t (self_t::*FunName##_stub_t)ArgList; 63 | 64 | #define RPC_DECLARE_MF(FunName, ArgList) RPC_DECLARE_MF_EX(FunName, ArgList, =0;) 65 | #define RPC_DECLARE_MF_D(FunName, ArgList) RPC_DECLARE_MF_EX(FunName, ArgList, ;) 66 | 67 | //! 开始在远程对象中注册成员函数组,只注册一次 68 | //! 使用这个宏,用户必须自己定义: static remote_object* create_object() 69 | //! get_meta 的返回值 pair.first 只是为了带上类型信息 70 | #define BEGIN_RPC_ADD_MF_EX(ThisClass,ClassName)\ 71 | typedef ThisClass self_t; \ 72 | public: \ 73 | NARK_RPC_GEN_full_mf_name(ClassName) \ 74 | template \ 75 | static std::pair \ 76 | get_meta(Session*tag) \ 77 | { \ 78 | std::pair meta;\ 79 | meta.second = new ClassMeta; \ 80 | meta.second->className = ClassName; \ 81 | meta.second->create = 0; 82 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 83 | 84 | #define BEGIN_RPC_ADD_MF(ThisClass) BEGIN_RPC_ADD_MF_EX(ThisClass, #ThisClass) 85 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 86 | 87 | //! 在远程对象中注册一个成员函数 88 | #define RPC_ADD_MF(FunName) \ 89 | meta.second->stubs.push_back(new server_stub(&self_t::FunName,full_mf_name(#FunName))); 90 | 91 | //! 结束在远程对象中注册成员函数组 92 | #define END_RPC_ADD_MF() return meta; } 93 | 94 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 95 | /* 96 | #define BEGIN_RPC_IMP_INTERFACE_EX(Impl, Interface) \ 97 | class Impl : public Interface { \ 98 | public: \ 99 | template \ 100 | static void reg_interface \ 101 | (Session* sess, create_fun_t pf_create) \ 102 | { ClassMeta* meta = Interface::get_meta(sess).second; \ 103 | meta->create = pf_create; \ 104 | } 105 | */ 106 | 107 | #define BEGIN_RPC_IMP_INTERFACE_EX(Impl, Interface) \ 108 | class Impl : public Interface { \ 109 | public: 110 | 111 | #define BEGIN_RPC_IMP_INTERFACE(Impl, Interface) \ 112 | BEGIN_RPC_IMP_INTERFACE_EX(Impl, Interface) \ 113 | static remote_object*create_object() { return new Impl; } 114 | 115 | #define END_RPC_IMP_INTERFACE() }; 116 | 117 | #define RPC_SERVER_AUTO_CREATE(server, ImpClass) \ 118 | (server).auto_create((ImpClass*)0, &ImpClass::create_object) 119 | 120 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 121 | 122 | class server_packet_base; 123 | class session_base; 124 | 125 | class NARK_DLL_EXPORT server_stub_i 126 | { 127 | public: 128 | std::string m_name; 129 | unsigned m_id; 130 | 131 | public: 132 | virtual ~server_stub_i(); 133 | 134 | virtual void invoke(server_packet_base* packet) const = 0; 135 | 136 | virtual void sync_call(session_base* session, const server_packet_base* packet) const = 0; 137 | virtual void send_args(session_base* session, server_packet_base* packet) const = 0; 138 | virtual server_packet_base* read_args(session_base* server, const server_packet_base* packet) const = 0; 139 | }; 140 | 141 | struct NARK_DLL_EXPORT ClassMeta : public RoCreator 142 | { 143 | std::vector stubs; 144 | }; 145 | 146 | class NARK_DLL_EXPORT server_packet_base : public RefCounter 147 | { 148 | public: 149 | server_stub_i* stub; 150 | unsigned seqid; 151 | short how_call; 152 | bool isbyid; 153 | rpc_ret_t retv; 154 | 155 | void copy(const server_packet_base* header) { 156 | stub = header->stub; 157 | seqid = header->seqid; 158 | how_call = header->how_call; 159 | isbyid = header->isbyid; 160 | } 161 | 162 | void invoke() { stub->invoke(this); } 163 | 164 | template 165 | void read_header(Input& input, const AccessByNameID& stubs) { 166 | stub = 0; 167 | var_size_t vint, callid; 168 | input >> vint >> callid; 169 | this->seqid = vint.t; 170 | if (0 == callid.t) { // call by name 171 | std::string funName; 172 | input >> funName; 173 | stub = stubs.get_byname(funName); 174 | if (0 == stub) { 175 | string_appender<> oss; 176 | oss << "can not find function [name=\"" << funName << "\" to call"; 177 | throw rpc_exception(oss.str()); 178 | } 179 | isbyid = false; 180 | } 181 | else { // call by id 182 | if (!stubs.is_valid(callid.t)) { 183 | string_appender<> oss; 184 | oss << "can not find function id=" << callid.t << " to call"; 185 | throw rpc_exception(oss.str()); 186 | } 187 | isbyid = true; 188 | stub = stubs.get_byid(callid.t); 189 | } 190 | input >> vint; 191 | how_call = vint.t; 192 | assert(stub); 193 | } 194 | }; 195 | 196 | 197 | ////////////////////////////////////////////////////////////////////////// 198 | ////////////////////////////////////////////////////////////////////////// 199 | // declare the template prototype 200 | template struct server_packet; 201 | 202 | // partial specializations, use BOOST_PP.. 203 | // 204 | #include 205 | #define BOOST_PP_ITERATION_LIMITS (0, 9) 206 | #define BOOST_PP_FILENAME_1 207 | #include BOOST_PP_ITERATE() 208 | 209 | 210 | template 211 | class server_stub : public server_stub_i 212 | { 213 | typedef arglist_val aval_t; 214 | typedef arglist_ref aref_t; 215 | typedef server_packet packet_t; 216 | 217 | Function m_pfun; 218 | 219 | public: 220 | server_stub(Function pfun, const std::string& name); 221 | 222 | virtual void sync_call(session_base* vpsession, const server_packet_base* header) const; 223 | 224 | virtual void invoke(server_packet_base* packet) const; 225 | 226 | virtual server_packet_base* read_args(session_base* vpsession, const server_packet_base* header) const; 227 | virtual void send_args(session_base* vpsession, server_packet_base* packet) const; 228 | 229 | private: 230 | void do_send_args(Session* session, packet_t* p) const; 231 | }; 232 | 233 | ////////////////////////////////////////////////////////////////////////// 234 | class NARK_DLL_EXPORT session_base : public SessionScope 235 | { 236 | protected: 237 | class rpc_server_base* m_owner; 238 | 239 | AccessByNameID* m_stubTable; 240 | AccessByNameID* m_globaleScopeObjects; 241 | // AccessByNameID m_globaleScopeObjectsRef; 242 | AccessByNameID m_sessionScopeObjects; 243 | ObjectFactory* m_sessionScopeFactory; 244 | boost::thread* m_thread; 245 | volatile bool m_bRun; 246 | 247 | void call(server_packet_base& header); 248 | 249 | typedef session_base my_self_t; 250 | 251 | static remote_object* create_object(); 252 | 253 | #include "rpc_interface.hpp" 254 | 255 | virtual void read_header(server_packet_base& header) = 0; 256 | void run(); 257 | 258 | public: 259 | session_base(class rpc_server_base* owner); 260 | virtual ~session_base(); 261 | 262 | void start(); 263 | }; 264 | 265 | class NARK_DLL_EXPORT rpc_server_base 266 | { 267 | friend class session_base; 268 | protected: 269 | std::set > m_sessionList; 270 | 271 | AccessByNameID m_stubTable; 272 | AccessByNameID m_globaleScopeObjects; 273 | ObjectFactory m_globaleScopeFactory; 274 | ObjectFactory m_sessionScopeFactory; 275 | class MyMutex; 276 | MyMutex* m_mutex; 277 | 278 | IAcceptor* m_acceptor; 279 | 280 | void gen_stubs(ClassMeta* meta); 281 | bool addto_factroy(ClassMeta* meta, GlobaleScope* scopeTag); 282 | bool addto_factroy(ClassMeta* meta, SessionScope* scopeTag); 283 | 284 | void add_servant_imp(GlobaleScope* servant, const std::string& name); 285 | 286 | public: 287 | rpc_ret_t createGlobaleObject(var_size_t* servantID, const std::string& className); 288 | rpc_ret_t createNamedGlobaleObject(var_size_t* servantID, std::string& className, const std::string& name); 289 | rpc_ret_t retrieveGlobaleObject(var_size_t* servantID, const std::string& name); 290 | 291 | void remove_servant(GlobaleScopePtr servant); 292 | 293 | void removeSession(boost::intrusive_ptr session); 294 | virtual session_base* createSession() = 0; 295 | 296 | rpc_server_base(IAcceptor* acceptor = 0); 297 | virtual ~rpc_server_base(); 298 | 299 | void start(); 300 | }; 301 | 302 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 303 | 304 | //@} 305 | 306 | /** 307 | * rpc_server 308 | * 309 | * concept of Connection 310 | * -# bool listen(const char* szName); 311 | * -# IDuplexStream* accept(); // return a stream connected with a server side 312 | */ 313 | template class Input, 314 | template class Output 315 | > 316 | class rpc_server : public rpc_server_base 317 | { 318 | typedef rpc_server self_t; 319 | typedef Input input_t; 320 | typedef Output output_t; 321 | typedef server_object_input so_input_t; 322 | typedef server_object_output so_output_t; 323 | /* 324 | class RpcTask : public nark::thread::PipelineTask 325 | { 326 | so_input_t* input; 327 | so_output_t* output; 328 | server_stub_i* stub; 329 | void* args; 330 | public: 331 | RpcTask(so_input_t* input, so_output_t* output) 332 | : input(input), output(output) 333 | { 334 | } 335 | 336 | void income() 337 | { 338 | 339 | } 340 | }; 341 | */ 342 | class RpcSession : public session_base 343 | { 344 | std::auto_ptr m_stream; 345 | input_t input; 346 | output_t output; 347 | 348 | protected: 349 | ///@Override 350 | void read_header(server_packet_base& header) { 351 | header.read_header(input, *m_stubTable); 352 | } 353 | public: 354 | so_input_t m_so_input; 355 | so_output_t m_so_output; 356 | 357 | RpcSession(rpc_server* owner, IDuplexStream* stream) 358 | : session_base(owner) 359 | , m_stream(stream) 360 | , m_so_input(&owner->m_globaleScopeObjects, &m_sessionScopeObjects, &input) 361 | , m_so_output(&owner->m_globaleScopeObjects, &m_sessionScopeObjects, &output) 362 | { 363 | input.attach(stream); 364 | input.set_bufsize(8*1024); 365 | output.attach(stream); 366 | output.set_bufsize(8*1024); 367 | } 368 | }; 369 | friend class RpcSession; 370 | 371 | session_base* createSession() { 372 | if (IDuplexStream* stream = m_acceptor->accept()) 373 | return new RpcSession(this, stream); 374 | else 375 | return 0; 376 | } 377 | 378 | public: 379 | rpc_server(IAcceptor* acceptor) 380 | : rpc_server_base(acceptor) 381 | { 382 | create_fun_t pf_create = 0; 383 | auto_create((RpcSession*)0, pf_create); 384 | } 385 | 386 | template 387 | void auto_create(Class* tag, create_fun_t pf_create) { 388 | ClassMeta* meta = Class::get_meta((RpcSession*)0).second; 389 | if (addto_factroy(meta, tag)) { 390 | meta->create = pf_create; 391 | gen_stubs(meta); 392 | } 393 | } 394 | template 395 | void add_servant(Class* x, const std::string& name, create_fun_t pf_create) { 396 | std::string className = Class::s_getClassName(); 397 | if (0 == m_globaleScopeFactory.FindMetaByName(className)) { 398 | ClassMeta* meta = Class::get_meta((RpcSession*)0).second; 399 | meta->create = pf_create; 400 | gen_stubs(meta); 401 | this->addto_factroy(meta, (Class*)0); 402 | } 403 | rpc_server_base::add_servant_imp(x, name); 404 | } 405 | template 406 | void add_servant(Class* x, const std::string& name) { 407 | add_servant(x, name, &Class::create_object); 408 | } 409 | template 410 | void add_servant(boost::intrusive_ptr x, const std::string& name, create_fun_t pf_create) { 411 | add_servant(x.get(), name, pf_create); 412 | } 413 | template 414 | void add_servant(boost::intrusive_ptr x, const std::string& name) { 415 | add_servant(x.get(), name, &Class::create_object); 416 | } 417 | }; 418 | 419 | //////////////////////////////////////////////////////////////////////////////////////////////// 420 | //////////////////////////////////////////////////////////////////////////////////////////////// 421 | // template class server_stub implementation 422 | 423 | template 424 | server_stub::server_stub(Function pfun, const std::string& name) 425 | { 426 | this->m_name = name; 427 | this->m_id = 0; 428 | m_pfun = pfun; 429 | } 430 | 431 | template 432 | void 433 | server_stub::sync_call(session_base* vpsession, const server_packet_base* header) const 434 | { 435 | Session* session = static_cast(vpsession); 436 | packet_t packet; 437 | packet.copy(header); 438 | 439 | aref_t refs(boost::mpl::true_(), packet.argvals); 440 | refs.load(session->m_so_input); 441 | packet.argvals.sync(refs); 442 | 443 | packet.invoke_f(m_pfun); 444 | do_send_args(session, &packet); 445 | } 446 | 447 | template 448 | void 449 | server_stub::invoke(server_packet_base* packet) const 450 | { 451 | packet_t* p = (packet_t*)packet; 452 | p->invoke_f(m_pfun); 453 | } 454 | 455 | template 456 | server_packet_base* 457 | server_stub::read_args(session_base* vpsession, const server_packet_base* header) const 458 | { 459 | Session* session = static_cast(vpsession); 460 | packet_t* p = 0; 461 | try { 462 | p = new packet_t; 463 | p->copy(header); 464 | aref_t refs(boost::mpl::true_(), p->argvals); 465 | refs.load(session->m_so_input); 466 | p->argvals.sync(refs); 467 | } 468 | catch (const std::exception& exp) { 469 | delete p; 470 | p = 0; 471 | fprintf(stderr, "fun=%s, exp.what=%s\n", BOOST_CURRENT_FUNCTION, exp.what()); 472 | } 473 | return p; 474 | } 475 | 476 | template 477 | void 478 | server_stub::send_args(session_base* vpsession, server_packet_base* packet) const 479 | { 480 | Session* session = static_cast(vpsession); 481 | packet_t* p = (packet_t*)packet; 482 | do_send_args(session, p); 483 | } 484 | 485 | template 486 | void 487 | server_stub::do_send_args(Session* session, packet_t* p) const 488 | { 489 | session->m_so_output.get() 490 | << var_size_t(p->seqid) 491 | << p->retv; 492 | 493 | aref_t refs(boost::mpl::true_(), p->argvals); 494 | refs.save(session->m_so_output); 495 | 496 | if (!p->isbyid) // called by name, tell client the callid 497 | session->m_so_output.get() << var_size_t(this->m_id); 498 | session->m_so_output.flush(); 499 | } 500 | 501 | //////////////////////////////////////////////////////////////////////////////////////////////// 502 | 503 | } } // namespace::nark::rpc 504 | 505 | 506 | #endif // __nark_rpc_server_h__ 507 | -------------------------------------------------------------------------------- /src/nark/rpc/server_io.cpp: -------------------------------------------------------------------------------- 1 | /* vim: set tabstop=4 : */ 2 | #include "rpc_basic.hpp" 3 | #include 4 | 5 | namespace nark { namespace rpc { 6 | 7 | void NARK_DLL_EXPORT 8 | incompitible_class_cast(remote_object* y, const char* szRequestClassName) 9 | { 10 | string_appender<> oss; 11 | oss << "object[id=" << y->getID() << ", type=" << y->getClassName() 12 | << "] is not " << szRequestClassName; 13 | throw rpc_exception(oss.str()); 14 | } 15 | 16 | 17 | } } // namespace::nark::rpc 18 | -------------------------------------------------------------------------------- /src/nark/rpc/server_io.hpp: -------------------------------------------------------------------------------- 1 | /* vim: set tabstop=4 : */ 2 | #ifndef __nark_rpc_server_io_h__ 3 | #define __nark_rpc_server_io_h__ 4 | 5 | #if defined(_MSC_VER) && (_MSC_VER >= 1020) 6 | # pragma once 7 | # pragma warning(disable: 4819) 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include "rpc_basic.hpp" 16 | #include "arg_traits.hpp" 17 | 18 | namespace nark { namespace rpc { 19 | 20 | void NARK_DLL_EXPORT 21 | incompitible_class_cast(remote_object* x, const char* szRequestClassName); 22 | 23 | template class server_object_input 24 | { 25 | AccessByNameID* m_globale; 26 | AccessByNameID* m_session; 27 | Input* p; 28 | 29 | template 30 | void load(T*& x, AccessByNameID >* byid) 31 | { 32 | typename T::SFINAE_ro_self_t* for_check = 0; 33 | (void)(for_check); 34 | var_size_t objid; 35 | *p >> objid; 36 | std::string err; 37 | if (!byid->check_id(objid.t, T::s_getClassName(), err)) { 38 | throw rpc_exception(err); 39 | } 40 | U* y = byid->get_rawptr_byid(objid.t); 41 | x = dynamic_cast(y); 42 | if (0 == x) 43 | incompitible_class_cast(y, T::s_getClassName()); 44 | } 45 | template void load(T*& x, GlobaleScope*) { load(x, m_globale); } 46 | template void load(T*& x, SessionScope*) { load(x, m_session); } 47 | 48 | public: 49 | server_object_input( AccessByNameID* globale 50 | , AccessByNameID* session 51 | , Input* input) 52 | : m_globale(globale), m_session(session), p(input) {} 53 | 54 | Input& get() const { return *p; } 55 | 56 | template server_object_input& operator &(rpc_in x) { *p >> x.r; return *this; } 57 | template server_object_input& operator>>(rpc_in x) { *p >> x.r; return *this; } 58 | 59 | template server_object_input& operator &(rpc_out x) { return *this; } 60 | template server_object_input& operator>>(rpc_out x) { return *this; } 61 | 62 | template server_object_input& operator &(rpc_inout x) { *p >> x.r; return *this; } 63 | template server_object_input& operator>>(rpc_inout x) { *p >> x.r; return *this; } 64 | 65 | template server_object_input& operator &(T*& x) { load(x, x); return *this; } 66 | template server_object_input& operator>>(T*& x) { load(x, x); return *this; } 67 | 68 | template server_object_input& operator &(boost::intrusive_ptr& x) 69 | { 70 | return *this >> x; 71 | } 72 | template server_object_input& operator>>(boost::intrusive_ptr& x) 73 | { 74 | T* y = 0; 75 | load(y, y); 76 | x.reset(y); 77 | return *this; 78 | } 79 | }; 80 | 81 | template class server_object_output 82 | { 83 | AccessByNameID* m_globale; 84 | AccessByNameID* m_session; 85 | Output* p; 86 | 87 | template 88 | void save(T* x, AccessByNameID >* byid, const char* szBaseName) 89 | { 90 | // do nothing... 91 | typename T::SFINAE_ro_self_t* for_check = 0; 92 | (void)(for_check); 93 | // var_size_t objid(x->getID()); 94 | // if (!byid->is_valid(objid.t)) 95 | // { 96 | // string_appender<> oss; 97 | // oss << "not found " << szBaseName << ": " << x->getClassName() << " :id=" << objid.t; 98 | // throw rpc_exception(oss.str()); 99 | // } 100 | // *p << objid; 101 | } 102 | template void save(T* x, GlobaleScope*) { save(x, m_globale, "GlobaleScope"); } 103 | template void save(T* x, SessionScope*) { save(x, m_session, "SessionScope"); } 104 | 105 | public: 106 | server_object_output( AccessByNameID* globale 107 | , AccessByNameID* session 108 | , Output* output) 109 | : m_globale(globale), m_session(session), p(output) {} 110 | 111 | void flush() { p->flush(); } 112 | 113 | Output& get() const { return *p; } 114 | 115 | template server_object_output& operator &(rpc_in x) { return *this; } 116 | template server_object_output& operator<<(rpc_in x) { return *this; } 117 | 118 | template server_object_output& operator &(rpc_out x) { *p << x.r; return *this; } 119 | template server_object_output& operator<<(rpc_out x) { *p << x.r; return *this; } 120 | 121 | template server_object_output& operator &(rpc_inout x) { *p << x.r; return *this; } 122 | template server_object_output& operator<<(rpc_inout x) { *p << x.r; return *this; } 123 | 124 | template server_object_output& operator &(const T& x) { return *this << x; } 125 | template server_object_output& operator<<(T* const& x) // only for derived from remote_object 126 | { 127 | save(x, x); 128 | return *this; 129 | } 130 | 131 | template server_object_output& operator &(const boost::intrusive_ptr& x) { return *this << x; } 132 | template server_object_output& operator<<(const boost::intrusive_ptr& x) // only for derived from remote_object 133 | { 134 | save(x.get(), x.get()); 135 | return *this; 136 | } 137 | }; 138 | 139 | 140 | } } // namespace::nark::rpc 141 | 142 | 143 | #endif // __nark_rpc_server_io_h__ 144 | --------------------------------------------------------------------------------