├── .devcontainer ├── .env ├── Dockerfile ├── devcontainer.json ├── docker-compose.yml ├── install-mariadb.sh ├── install-protobuf.sh ├── reinstall-cmake.sh └── tinyxml.sh ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── build.sh ├── conf ├── test_http_server.xml └── test_tinypb_server.xml ├── generator ├── template │ ├── business_exception.h.template │ ├── conf.xml.template │ ├── interface.cc.template │ ├── interface.h.template │ ├── interface_base.cc.template │ ├── interface_base.h.template │ ├── main.cc.template │ ├── makefile.template │ ├── run.sh │ ├── server.cc.template │ ├── server.h.template │ ├── shutdown.sh │ └── test_tinyrpc_client.cc.template └── tinyrpc_generator.py ├── imgs ├── block_async_call.drawio.png ├── execute.drawio.png ├── input.drawio.png ├── mine │ ├── alipay.png │ └── wechatpay.png ├── nonblock_async_call.drawio.png ├── tcp_server.drawio.png └── test_succ.png ├── makefile ├── testcases ├── test_coroutine.cc ├── test_http_server.cc ├── test_tinypb_server.cc ├── test_tinypb_server.proto └── test_tinypb_server_client.cc └── tinyrpc ├── comm ├── CMakeLists.txt ├── config.cc ├── config.h ├── error_code.h ├── log.cc ├── log.h ├── msg_req.cc ├── msg_req.h ├── mysql_instase.cc ├── mysql_instase.h ├── run_time.h ├── start.cc ├── start.h ├── string_util.cc ├── string_util.h ├── thread_pool.cc └── thread_pool.h ├── coroutine ├── CMakeLists.txt ├── coctx.h ├── coctx_swap.S ├── coroutine.cc ├── coroutine.h ├── coroutine_hook.cc ├── coroutine_hook.h ├── coroutine_pool.cc ├── coroutine_pool.h ├── memory.cc └── memory.h └── net ├── CMakeLists.txt ├── abstract_codec.h ├── abstract_data.h ├── abstract_dispatcher.h ├── byte.h ├── fd_event.cc ├── fd_event.h ├── http ├── CMakeLists.txt ├── http_codec.cc ├── http_codec.h ├── http_define.cc ├── http_define.h ├── http_dispatcher.cc ├── http_dispatcher.h ├── http_request.h ├── http_response.h ├── http_servlet.cc └── http_servlet.h ├── mutex.cc ├── mutex.h ├── net_address.cc ├── net_address.h ├── reactor.cc ├── reactor.h ├── tcp ├── CMakeLists.txt ├── abstract_slot.h ├── io_thread.cc ├── io_thread.h ├── tcp_buffer.cc ├── tcp_buffer.h ├── tcp_client.cc ├── tcp_client.h ├── tcp_connection.cc ├── tcp_connection.h ├── tcp_connection_time_wheel.cc ├── tcp_connection_time_wheel.h ├── tcp_server.cc └── tcp_server.h ├── timer.cc ├── timer.h └── tinypb ├── CMakeLists.txt ├── tinypb_codec.cc ├── tinypb_codec.h ├── tinypb_data.h ├── tinypb_rpc_async_channel.cc ├── tinypb_rpc_async_channel.h ├── tinypb_rpc_channel.cc ├── tinypb_rpc_channel.h ├── tinypb_rpc_closure.h ├── tinypb_rpc_controller.cc ├── tinypb_rpc_controller.h ├── tinypb_rpc_dispatcher.cc └── tinypb_rpc_dispatcher.h /.devcontainer/.env: -------------------------------------------------------------------------------- 1 | MARIADB_ROOT_PASSWORD=mariadb 2 | MARIADB_DATABASE=mariadb 3 | MARIADB_USER=mariadb 4 | MARIADB_PASSWORD=mariadb 5 | MARIADB_HOSTNAME=localhost -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/devcontainers/cpp:0-debian-11 2 | 3 | # Everything below this is needed for installing MariaDB 4 | # Instructions are copied and modified from: https://mariadb.com/docs/clients/mariadb-connectors/connector-cpp/install/ 5 | RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 6 | && apt-get -y install curl 7 | 8 | COPY ./install-mariadb.sh /tmp/ 9 | RUN chmod +x /tmp/install-mariadb.sh && /tmp/install-mariadb.sh && rm -f /tmp/install-mariadb.sh 10 | 11 | ARG REINSTALL_CMAKE_VERSION_FROM_SOURCE="3.21.5" 12 | 13 | # Optionally install the cmake for vcpkg 14 | COPY ./reinstall-cmake.sh /tmp/ 15 | 16 | RUN if [ "${REINSTALL_CMAKE_VERSION_FROM_SOURCE}" != "none" ]; then \ 17 | chmod +x /tmp/reinstall-cmake.sh && /tmp/reinstall-cmake.sh ${REINSTALL_CMAKE_VERSION_FROM_SOURCE}; \ 18 | fi \ 19 | && rm -f /tmp/reinstall-cmake.sh 20 | 21 | # [Optional] Uncomment this section to install additional vcpkg ports. 22 | # RUN su vscode -c "${VCPKG_ROOT}/vcpkg install " 23 | 24 | # [Optional] Uncomment this section to install additional packages. 25 | # RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 26 | # && apt-get -y install --no-install-recommends 27 | 28 | # install google protobuf 29 | ARG PROTOBUF_BRANCH="3.19.x" 30 | COPY ./install-protobuf.sh /tmp/ 31 | RUN chmod +x /tmp/install-protobuf.sh && /tmp/install-protobuf.sh && rm -f /tmp/install-protobuf.sh 32 | 33 | # install tiny xml 34 | ARG NUM_COMPILE_JOBS="3" 35 | COPY ./tinyxml.sh /tmp/ 36 | RUN chmod +x /tmp/tinyxml.sh && /tmp/tinyxml.sh && rm -f /tmp/tinyxml.sh -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/cpp-mariadb 3 | { 4 | "name": "TinyRPC", 5 | "dockerComposeFile": "docker-compose.yml", 6 | "service": "app", 7 | "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", 8 | "features": { 9 | // "ghcr.io/devcontainers-contrib/features/protoc-asdf:1":{}, 10 | // "ghcr.io/balazs23/devcontainers-features/bazel:1":{}, 11 | "ghcr.io/devcontainers-contrib/features/apt-get-packages:1": {} 12 | } 13 | 14 | // Features to add to the dev container. More info: https://containers.dev/features. 15 | // "features": {}, 16 | 17 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 18 | // This is the recommended way to access the container from the host 19 | // "forwardPorts": [3306], 20 | 21 | // Configure tool-specific properties. 22 | // "customizations": {}, 23 | 24 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 25 | // "remoteUser": "root" 26 | } 27 | -------------------------------------------------------------------------------- /.devcontainer/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | volumes: 4 | mariadb-data: 5 | 6 | services: 7 | app: 8 | build: 9 | context: . 10 | dockerfile: Dockerfile 11 | env_file: 12 | - .env 13 | 14 | volumes: 15 | - ../..:/workspaces:cached 16 | 17 | # Overrides default command so things don't shut down after the process ends. 18 | command: sleep infinity 19 | 20 | # Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function. 21 | network_mode: service:db 22 | 23 | # Use "forwardPorts" in **devcontainer.json** to forward an app port locally. 24 | # (Adding the "ports" property to this file will not forward from a Codespace.) 25 | 26 | db: 27 | image: mariadb:10.3.32-focal 28 | restart: unless-stopped 29 | volumes: 30 | - mariadb-data:/var/lib/MARIADB 31 | env_file: 32 | - .env 33 | # Add "forwardPorts": ["3306"] to **devcontainer.json** to forward DB locally. 34 | # (Adding the "ports" property to this file will not forward from a Codespace.) 35 | -------------------------------------------------------------------------------- /.devcontainer/install-mariadb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | OSURL="" 5 | OSTAG="" 6 | 7 | find_os_props() { 8 | . /etc/os-release 9 | case $ID in 10 | debian) 11 | case $VERSION_CODENAME in 12 | stretch) 13 | OSTAG="1683458" 14 | OSURL="debian-9-stretch-amd64" 15 | ;; 16 | *) 17 | OSTAG="1683461" 18 | OSURL="debian-buster-amd64" 19 | ;; 20 | esac 21 | ;; 22 | ubuntu) 23 | case $VERSION_CODENAME in 24 | bionic) 25 | OSTAG="1683439" 26 | OSURL="ubuntu-bionic-amd64" 27 | ;; 28 | groovy) 29 | OSTAG="1683454" 30 | OSURL="ubuntu-groovy-amd64" 31 | ;; 32 | *) 33 | OSTAG="1683444" 34 | OSURL="ubuntu-focal-amd64" 35 | ;; 36 | esac 37 | ;; 38 | *) 39 | echo "Unsupported OS choice." 40 | exit 1 41 | ;; 42 | esac 43 | } 44 | 45 | # Run apt-get if needed. 46 | apt_get_update_if_needed() { 47 | if [ ! -d "/var/lib/apt/lists" ] || [ "$(ls /var/lib/apt/lists/ | wc -l)" = "0" ]; then 48 | echo "Running apt-get update..." 49 | apt-get update 50 | else 51 | echo "Skipping apt-get update." 52 | fi 53 | } 54 | 55 | # Check if packages are installed and installs them if not. 56 | check_packages() { 57 | if ! dpkg -s "$@" > /dev/null 2>&1; then 58 | apt_get_update_if_needed 59 | apt-get -y install --no-install-recommends "$@" 60 | fi 61 | } 62 | 63 | TMP_DIR=$(mktemp -d -t maria-XXXXXXXXXX) 64 | MARIADB_CONNECTOR="" 65 | SOURCE_INCLUDE_DIR="" 66 | SOURCE_LIB_DIR="" 67 | SOURCE_PLUGIN_DIR="" 68 | 69 | cleanup() { 70 | EXIT_CODE=$? 71 | set +e 72 | if [[ -n ${TMP_DIR} ]]; then 73 | cd / 74 | rm -rf ${TMP_DIR} 75 | fi 76 | exit $EXIT_CODE 77 | } 78 | trap cleanup EXIT 79 | 80 | #Set up external repository and install C Connector 81 | check_packages libmariadb3 libmariadb-dev 82 | 83 | #Depending on the OS, install different C++ connectors 84 | find_os_props 85 | 86 | cd ${TMP_DIR} 87 | 88 | if [ "$(dpkg --print-architecture)" = "arm64" ] ; then 89 | # Instructions are copied and modified from: https://github.com/mariadb-corporation/mariadb-connector-cpp/blob/master/BUILD.md 90 | # and from: https://mariadb.com/docs/clients/mariadb-connectors/connector-cpp/install/ 91 | check_packages git cmake make gcc libssl-dev 92 | git clone https://github.com/MariaDB-Corporation/mariadb-connector-cpp.git 93 | mkdir build && cd build 94 | cmake ../mariadb-connector-cpp/ -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCONC_WITH_UNIT_TESTS=Off -DCMAKE_INSTALL_PREFIX=/usr/local -DWITH_SSL=OPENSSL 95 | cmake --build . --config RelWithDebInfo 96 | make install 97 | 98 | SOURCE_INCLUDE_DIR="../mariadb-connector-cpp/include" 99 | SOURCE_LIB_DIR="." 100 | SOURCE_PLUGIN_DIR="./libmariadb" 101 | else 102 | # Instructions are copied and modified from: https://mariadb.com/docs/clients/mariadb-connectors/connector-cpp/install/ 103 | MARIADB_CONNECTOR=mariadb-connector-cpp-1.0.1-$OSURL 104 | curl -Ls https://dlm.mariadb.com/$OSTAG/connectors/cpp/connector-cpp-1.0.1/${MARIADB_CONNECTOR}.tar.gz -o ${MARIADB_CONNECTOR}.tar.gz 105 | tar -xvzf ${MARIADB_CONNECTOR}.tar.gz && cd ${MARIADB_CONNECTOR} 106 | 107 | SOURCE_INCLUDE_DIR="./include/mariadb" 108 | if [ -d "lib64/mariadb" ] ; then 109 | SOURCE_LIB_DIR="lib64/mariadb" 110 | SOURCE_PLUGIN_DIR="lib64/mariadb/plugin" 111 | else 112 | SOURCE_LIB_DIR="lib/mariadb" 113 | SOURCE_PLUGIN_DIR="lib/mariadb/plugin" 114 | fi 115 | fi 116 | 117 | install -d /usr/include/mariadb/conncpp/compat 118 | install -d /usr/lib/mariadb/plugin 119 | 120 | #Header Files being copied into the necessary directories 121 | cp -R ${SOURCE_INCLUDE_DIR}/* /usr/include/mariadb/ 122 | cp -R ${SOURCE_INCLUDE_DIR}/conncpp/* /usr/include/mariadb/conncpp 123 | cp -R ${SOURCE_INCLUDE_DIR}/conncpp/compat/* /usr/include/mariadb/conncpp/compat 124 | 125 | #Shared libraries copied into usr/lib 126 | cp ${SOURCE_LIB_DIR}/libmariadbcpp.so /usr/lib 127 | cp ${SOURCE_PLUGIN_DIR}/*.so /usr/lib/mariadb/plugin 128 | -------------------------------------------------------------------------------- /.devcontainer/install-protobuf.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo "Building protobuf" 4 | 5 | sudo apt-get install autoconf automake libtool curl make g++ unzip 6 | git clone https://github.com/google/protobuf --depth 1 -b ${PROTOBUF_BRANCH} 7 | cd protobuf 8 | ./autogen.sh 9 | ./configure --prefix=/usr 10 | make -j 3 11 | make check 12 | sudo make install 13 | sudo ldconfig # refresh shared library cache. 14 | cd .. 15 | rm -rf protobuf -------------------------------------------------------------------------------- /.devcontainer/reinstall-cmake.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | #------------------------------------------------------------------------------------------------------------- 3 | # Copyright (c) Microsoft Corporation. All rights reserved. 4 | # Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. 5 | #------------------------------------------------------------------------------------------------------------- 6 | # 7 | set -e 8 | 9 | CMAKE_VERSION=${1:-"none"} 10 | 11 | if [ "${CMAKE_VERSION}" = "none" ]; then 12 | echo "No CMake version specified, skipping CMake reinstallation" 13 | exit 0 14 | fi 15 | 16 | # Cleanup temporary directory and associated files when exiting the script. 17 | cleanup() { 18 | EXIT_CODE=$? 19 | set +e 20 | if [[ -n "${TMP_DIR}" ]]; then 21 | echo "Executing cleanup of tmp files" 22 | rm -Rf "${TMP_DIR}" 23 | fi 24 | exit $EXIT_CODE 25 | } 26 | trap cleanup EXIT 27 | 28 | 29 | echo "Installing CMake..." 30 | apt-get -y purge --auto-remove cmake 31 | mkdir -p /opt/cmake 32 | 33 | architecture=$(dpkg --print-architecture) 34 | case "${architecture}" in 35 | arm64) 36 | ARCH=aarch64 ;; 37 | amd64) 38 | ARCH=x86_64 ;; 39 | *) 40 | echo "Unsupported architecture ${architecture}." 41 | exit 1 42 | ;; 43 | esac 44 | 45 | CMAKE_BINARY_NAME="cmake-${CMAKE_VERSION}-linux-${ARCH}.sh" 46 | CMAKE_CHECKSUM_NAME="cmake-${CMAKE_VERSION}-SHA-256.txt" 47 | TMP_DIR=$(mktemp -d -t cmake-XXXXXXXXXX) 48 | 49 | echo "${TMP_DIR}" 50 | cd "${TMP_DIR}" 51 | 52 | curl -sSL "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/${CMAKE_BINARY_NAME}" -O 53 | curl -sSL "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/${CMAKE_CHECKSUM_NAME}" -O 54 | 55 | sha256sum -c --ignore-missing "${CMAKE_CHECKSUM_NAME}" 56 | sh "${TMP_DIR}/${CMAKE_BINARY_NAME}" --prefix=/opt/cmake --skip-license 57 | 58 | ln -s /opt/cmake/bin/cmake /usr/local/bin/cmake 59 | -------------------------------------------------------------------------------- /.devcontainer/tinyxml.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | git clone git://git.code.sf.net/p/tinyxml/git tinyxml 4 | cd tinyxml 5 | make -j $NUM_COMPILE_JOBS 6 | ar cr libtinyxml.a *o 7 | sudo cp libtinyxml.a /usr/lib/ 8 | sudo mkdir /usr/include/tinyxml 9 | sudo cp *.h /usr/include/tinyxml -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | 3 | build/* 4 | bin/* 5 | lib/* 6 | .vscode/ 7 | 8 | *.swp 9 | *.swo 10 | *.log 11 | *.o 12 | *.a 13 | *.pb.h 14 | *.pb.cc 15 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | project(tinyrpc) 3 | 4 | SET(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR}) 5 | enable_language(ASM) 6 | 7 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -std=c++11 -Wall -Wno-deprecated -Wno-unused-but-set-variable") 8 | 9 | set(PATH_LIB lib) 10 | set(PATH_BIN bin) 11 | set(PATH_TESTCASES testcases) 12 | 13 | include_directories(${PROJECT_SOURCE_DIR}) 14 | # *.cc 15 | aux_source_directory(${PROJECT_SOURCE_DIR}/tinyrpc/comm COMM) 16 | aux_source_directory(${PROJECT_SOURCE_DIR}/tinyrpc/coroutine COR) 17 | aux_source_directory(${PROJECT_SOURCE_DIR}/tinyrpc/net NET) 18 | aux_source_directory(${PROJECT_SOURCE_DIR}/tinyrpc/net/http HTTP) 19 | aux_source_directory(${PROJECT_SOURCE_DIR}/tinyrpc/net/tcp TCP) 20 | aux_source_directory(${PROJECT_SOURCE_DIR}/tinyrpc/net/tinypb TINYPB) 21 | 22 | set(COXTX ${PROJECT_SOURCE_DIR}/tinyrpc/coroutine/coctx_swap.S) 23 | 24 | add_library(tinyrpc ${COMM} ${COR} ${NET} ${HTTP} ${TCP} ${TINYPB} ${COXTX}) 25 | install(TARGETS tinyrpc DESTINATION ${PATH_LIB}) 26 | 27 | 28 | find_package(Protobuf REQUIRED) 29 | if (${PROTOBUF_FOUND}) 30 | message("protobuf found") 31 | else () 32 | message(FATAL_ERROR "Cannot find Protobuf") 33 | endif () 34 | 35 | set(tinyxml /usr/lib/libtinyxml.a) 36 | 37 | set(LIBS 38 | tinyrpc 39 | ${Protobuf_LIBRARY} 40 | ${tinyxml} 41 | dl 42 | pthread 43 | ) 44 | 45 | # test_tinypb_server 46 | set( 47 | test_tinypb_server 48 | ${PROJECT_SOURCE_DIR}/${PATH_TESTCASES}/test_tinypb_server.cc 49 | ${PROJECT_SOURCE_DIR}/${PATH_TESTCASES}/test_tinypb_server.pb.cc 50 | ) 51 | add_executable(test_tinypb_server ${test_tinypb_server}) 52 | target_link_libraries(test_tinypb_server ${LIBS}) 53 | install(TARGETS test_tinypb_server DESTINATION ${PATH_BIN}) 54 | 55 | # test_tinypb_server_client 56 | set( 57 | test_tinypb_server_client 58 | ${PROJECT_SOURCE_DIR}/${PATH_TESTCASES}/test_tinypb_server_client.cc 59 | ${PROJECT_SOURCE_DIR}/${PATH_TESTCASES}/test_tinypb_server.pb.cc 60 | ) 61 | add_executable(test_tinypb_server_client ${test_tinypb_server_client}) 62 | target_link_libraries(test_tinypb_server_client ${LIBS}) 63 | install(TARGETS test_tinypb_server_client DESTINATION ${PATH_BIN}) 64 | 65 | # test_http_server 66 | set( 67 | test_http_server 68 | ${PROJECT_SOURCE_DIR}/${PATH_TESTCASES}/test_http_server.cc 69 | ${PROJECT_SOURCE_DIR}/${PATH_TESTCASES}/test_tinypb_server.pb.cc 70 | ) 71 | add_executable(test_http_server ${test_http_server}) 72 | target_link_libraries(test_http_server ${LIBS}) 73 | install(TARGETS test_http_server DESTINATION ${PATH_BIN}) 74 | 75 | # test_coroutine 76 | set( 77 | test_coroutine 78 | ${PROJECT_SOURCE_DIR}/${PATH_TESTCASES}/test_coroutine.cc 79 | ) 80 | add_executable(test_coroutine ${test_coroutine}) 81 | target_link_libraries(test_coroutine ${LIBS}) 82 | install(TARGETS test_coroutine DESTINATION ${PATH_BIN}) 83 | 84 | # install *.h 85 | add_subdirectory(tinyrpc/comm) 86 | add_subdirectory(tinyrpc/coroutine) 87 | add_subdirectory(tinyrpc/net) 88 | add_subdirectory(tinyrpc/net/http) 89 | add_subdirectory(tinyrpc/net/tcp) 90 | add_subdirectory(tinyrpc/net/tinypb) -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -x 4 | 5 | SOURCE_DIR=`pwd` 6 | BUILD_DIR=${BUILD_DIR:-./build} 7 | BIN_DIR=${BIN_DIR:-./bin} 8 | LIB_DIR=${LIB_DIR:-./lib} 9 | 10 | PATH_INSTALL_INC_ROOT=${PATH_INSTALL_INC_ROOT:-/usr/include} 11 | PATH_INSTALL_LIB_ROOT=${PATH_INSTALL_LIB_ROOT:-/usr/lib} 12 | INCLUDE_DIR=${INCLUDE_DIR:-./include} 13 | LIB=${LIB:-./lib/libtinyrpc.a} 14 | 15 | mkdir -p ${INCLUDE_DIR} \ 16 | && cd ${BUILD_DIR} \ 17 | && cmake .. \ 18 | && make install \ 19 | && cd .. \ 20 | && cp -r ${INCLUDE_DIR}/tinyrpc ${PATH_INSTALL_INC_ROOT} \ 21 | && cp ${LIB} ${PATH_INSTALL_LIB_ROOT} \ 22 | && rm -rf ${INCLUDE_DIR} 23 | 24 | -------------------------------------------------------------------------------- /conf/test_http_server.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ./ 7 | test_http_server 8 | 9 | 10 | 5 11 | 12 | 13 | DEBUG 14 | DEBUG 15 | 16 | 17 | 500 18 | 19 | 20 | 21 | 22 | 256 23 | 24 | 25 | 1000 26 | 27 | 28 | 29 | 20 30 | 31 | 32 | 75 33 | 34 | 35 | 1 36 | 37 | 38 | 3 39 | 40 | 41 | 5 42 | 43 | 44 | 45 | 127.0.0.1 46 | 19999 47 | HTTP 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /conf/test_tinypb_server.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ./ 7 | test_tinypb_server 8 | 9 | 10 | 5 11 | 12 | 13 | DEBUG 14 | DEBUG 15 | 16 | 17 | 500 18 | 19 | 20 | 21 | 22 | 256 23 | 24 | 25 | 1000 26 | 27 | 28 | 29 | 20 30 | 31 | 32 | 75 33 | 34 | 35 | 4 36 | 37 | 38 | 6 39 | 40 | 41 | 10 42 | 43 | 44 | 45 | 127.0.0.1 46 | 20000 47 | TinyPB 48 | 49 | 50 | 51 | 52 | 53 | 192.168.245.7 54 | 3306 55 | root 56 | Ikerli20220517!! 57 | 58 | utf8mb4 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /generator/template/business_exception.h.template: -------------------------------------------------------------------------------- 1 | /************************************************************* 2 | * 3 | * ##### ### # # # # ##### ##### #### 4 | * # # # # # # # # # # # # 5 | * # # # # # # ### ##### # 6 | * # ### # # # # # # #### 7 | * 8 | * *********************************************************** 9 | * Generated by tinyrpc framework tinyrpc_generator.py 10 | * This file will not be overwrite althrough protobuf file changed !!! 11 | * File can't overwrited while exist 12 | * *********************************************************** 13 | * File Name: ${FILE_NAME} 14 | * Create Time: ${CREATE_TIME} 15 | * Allow Edit: True 16 | *************************************************************/ 17 | 18 | 19 | 20 | #ifndef ${HEADER_DEFINE} 21 | #define ${HEADER_DEFINE} 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "tinyrpc/comm/log.h" 28 | 29 | 30 | 31 | namespace ${PROJECT_NAME} { 32 | 33 | class BusinessException : public std::exception { 34 | public: 35 | 36 | BusinessException(long long code, const std::string& err_info, const std::string& file_name, int line): 37 | m_error_code(code), m_error_info(err_info), m_file_name(file_name), m_line(line) { 38 | AppInfoLog("[%s:%d] throw BusinessException: {code: %d, error info %s}", file_name.c_str(), line, m_error_code, m_error_info.c_str()); 39 | } 40 | 41 | ~BusinessException() { 42 | 43 | } 44 | 45 | const char* what() { 46 | return m_error_info.c_str(); 47 | } 48 | 49 | std::string error() { 50 | return m_error_info; 51 | } 52 | 53 | long long code() { 54 | return m_error_code; 55 | } 56 | 57 | std::string file_name() { 58 | return m_file_name; 59 | } 60 | 61 | int line() { 62 | return m_line; 63 | } 64 | 65 | private: 66 | long long m_error_code {0}; 67 | std::string m_error_info; 68 | 69 | std::string m_file_name; 70 | int m_line {0}; 71 | 72 | }; 73 | 74 | } 75 | 76 | #endif -------------------------------------------------------------------------------- /generator/template/conf.xml.template: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ../log/ 10 | ${PROJECT_NAME} 11 | 12 | 13 | 5 14 | 15 | 16 | DEBUG 17 | DEBUG 18 | 19 | 20 | 500 21 | 22 | 23 | 24 | 25 | 256 26 | 27 | 28 | 1000 29 | 30 | 31 | 32 | 20 33 | 34 | 35 | 75 36 | 37 | 38 | 4 39 | 40 | 41 | 6 42 | 43 | 44 | 10 45 | 46 | 47 | 48 | 127.0.0.1 49 | 12345 50 | TinyPB 51 | 52 | 53 | -------------------------------------------------------------------------------- /generator/template/interface.cc.template: -------------------------------------------------------------------------------- 1 | /************************************************************* 2 | * 3 | * ##### ### # # # # ##### ##### #### 4 | * # # # # # # # # # # # # 5 | * # # # # # # ### ##### # 6 | * # ### # # # # # # #### 7 | * 8 | * Generated by tinyrpc framework tinyrpc_generator.py 9 | * Create Time: ${CREATE_TIME} 10 | * This file will not be overwrite althrough protobuf file changed !!! 11 | * Just write this file while not exist 12 | * File Name: ${FILE_NAME} 13 | * Create Time: ${CREATE_TIME} 14 | * Allow Edit: True 15 | *************************************************************/ 16 | 17 | 18 | #include 19 | ${INCLUDE_INTERFACE_HEADER} 20 | ${INCLUDE_INTERFACEBASE_HEADER} 21 | ${INCLUDE_PB_HEADER} 22 | 23 | namespace ${PROJECT_NAME} { 24 | 25 | ${CLASS_NAME}::${CLASS_NAME}(const ${REQUEST_TYPE}& request, ${RESPONSE_TYPE}& response, const tinyrpc::TinyPbRpcController& controller) 26 | : Interface(controller), 27 | m_request(request), 28 | m_response(response) { 29 | 30 | } 31 | 32 | ${CLASS_NAME}::~${CLASS_NAME}() { 33 | 34 | } 35 | 36 | void ${CLASS_NAME}::run() { 37 | // 38 | // Run your business at here 39 | // m_reponse.set_ret_code(0); 40 | // m_reponse.set_res_info("Succ"); 41 | // 42 | 43 | } 44 | 45 | 46 | } -------------------------------------------------------------------------------- /generator/template/interface.h.template: -------------------------------------------------------------------------------- 1 | /************************************************************* 2 | * 3 | * ##### ### # # # # ##### ##### #### 4 | * # # # # # # # # # # # # 5 | * # # # # # # ### ##### # 6 | * # ### # # # # # # #### 7 | * 8 | * *********************************************************** 9 | * Generated by tinyrpc framework tinyrpc_generator.py 10 | * This file will not be overwrite althrough protobuf file changed !!! 11 | * File can't overwrited while exist 12 | * *********************************************************** 13 | * File Name: ${FILE_NAME} 14 | * Create Time: ${CREATE_TIME} 15 | * Allow Edit: True 16 | *************************************************************/ 17 | 18 | #ifndef ${HEADER_DEFINE} 19 | #define ${HEADER_DEFINE} 20 | 21 | ${INCLUDE_PB_HEADER} 22 | ${INCLUDE_INTERFACEBASE_HEADER} 23 | 24 | 25 | namespace ${PROJECT_NAME} { 26 | 27 | /* 28 | * Rpc Interface Class 29 | * Alloc one object every time RPC call begin, and destroy this object while RPC call end 30 | */ 31 | 32 | class ${CLASS_NAME} : public Interface { 33 | public: 34 | 35 | ${CLASS_NAME}(const ${REQUEST_TYPE}& request, ${RESPONSE_TYPE}& response, const tinyrpc::TinyPbRpcController& controller); 36 | 37 | ~${CLASS_NAME}(); 38 | 39 | void run(); 40 | 41 | private: 42 | const ${REQUEST_TYPE}& m_request; // request object fron client 43 | 44 | ${RESPONSE_TYPE}& m_response; // response object that reply to client 45 | 46 | }; 47 | 48 | 49 | } 50 | 51 | 52 | #endif -------------------------------------------------------------------------------- /generator/template/interface_base.cc.template: -------------------------------------------------------------------------------- 1 | /************************************************************* 2 | * 3 | * ##### ### # # # # ##### ##### #### 4 | * # # # # # # # # # # # # 5 | * # # # # # # ### ##### # 6 | * # ### # # # # # # #### 7 | * 8 | * Generated by tinyrpc framework tinyrpc_generator.py 9 | * This file will not be overwrite althrough protobuf file changed !!! 10 | * Just write this file while not exist 11 | * File Name: ${FILE_NAME} 12 | * Create Time: ${CREATE_TIME} 13 | * Allow Edit: True 14 | *************************************************************/ 15 | 16 | 17 | #include 18 | #include 19 | ${INCLUDE_INTERFACEBASE_HEADER} 20 | 21 | namespace ${PROJECT_NAME} { 22 | 23 | 24 | Interface::Interface(const tinyrpc::TinyPbRpcController& controller) 25 | : m_controller(controller) { 26 | 27 | } 28 | 29 | Interface::~Interface() { 30 | 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /generator/template/interface_base.h.template: -------------------------------------------------------------------------------- 1 | /************************************************************* 2 | * 3 | * ##### ### # # # # ##### ##### #### 4 | * # # # # # # # # # # # # 5 | * # # # # # # ### ##### # 6 | * # ### # # # # # # #### 7 | * 8 | * Generated by tinyrpc framework tinyrpc_generator.py 9 | * This file will not be overwrite althrough protobuf file changed !!! 10 | * Just write this file while not exist 11 | * File Name: ${FILE_NAME} 12 | * Create Time: ${CREATE_TIME} 13 | * Allow Edit: True 14 | *************************************************************/ 15 | 16 | #ifndef ${HEADER_DEFINE} 17 | #define ${HEADER_DEFINE} 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | namespace ${PROJECT_NAME} { 24 | 25 | /* 26 | * Rpc Interface Base Class 27 | * All interface should extend this abstract class 28 | */ 29 | 30 | class Interface { 31 | public: 32 | Interface(const tinyrpc::TinyPbRpcController& controller); 33 | 34 | virtual ~Interface(); 35 | 36 | virtual void run() = 0; 37 | 38 | protected: 39 | const tinyrpc::TinyPbRpcController& m_controller; 40 | 41 | }; 42 | 43 | 44 | } 45 | 46 | 47 | #endif -------------------------------------------------------------------------------- /generator/template/main.cc.template: -------------------------------------------------------------------------------- 1 | /************************************************************* 2 | * 3 | * ##### ### # # # # ##### ##### #### 4 | * # # # # # # # # # # # # 5 | * # # # # # # ### ##### # 6 | * # ### # # # # # # #### 7 | * 8 | * Generated by tinyrpc framework tinyrpc_generator.py 9 | * Create Time: ${CREATE_TIME} 10 | * This file will not be overwrite althrough protobuf file changed !!! 11 | * Just write this file while not exist 12 | * File Name: ${FILE_NAME} 13 | * Create Time: ${CREATE_TIME} 14 | * Allow Edit: True 15 | *************************************************************/ 16 | 17 | 18 | #include 19 | #include 20 | ${INCLUDE_SERVER_HEADER} 21 | 22 | int main(int argc, char* argv[]) { 23 | if (argc != 2) { 24 | printf("Start ${PROJECT_NAME} server error, input argc is not 2!"); 25 | printf("Start ${PROJECT_NAME} like this: \n"); 26 | printf("./${PROJECT_NAME} ${PROJECT_NAME}.xml\n"); 27 | return 0; 28 | } 29 | 30 | tinyrpc::InitConfig(argv[1]); 31 | 32 | REGISTER_SERVICE(${PROJECT_NAME}::${CLASS_NAME}); 33 | 34 | tinyrpc::StartRpcServer(); 35 | 36 | return 0; 37 | } -------------------------------------------------------------------------------- /generator/template/makefile.template: -------------------------------------------------------------------------------- 1 | ##################################################################### 2 | ## 3 | ## ##### ### # # # # ##### ##### #### 4 | ## # # # # # # # # # # # # 5 | ## # # # # # # ### ##### # 6 | ## # ### # # # # # # #### 7 | 8 | ## MakeFile 9 | ## Generated by tinyrpc framework tinyrpc_generator.py 10 | ## Create Time: ${CREATE_TIME} 11 | ## File Name: makefile 12 | ## How to use: 13 | ## make clean && make -j4 14 | 15 | ## This file will not be overwrite althrough protobuf file changed !!! 16 | ## Just write this file while not exist 17 | ## 18 | ##################################################################### 19 | 20 | 21 | 22 | 23 | 24 | PATH_BIN = ../bin 25 | PATH_SERVICE = service 26 | PATH_INTERFACE = interface 27 | PATH_PB = pb 28 | PATH_COMM = comm 29 | PATH_OBJ = ../obj 30 | PATH_TEST_CLIENT = ../test_client 31 | PATH_TEST_CLIENT_TOOL = $(PATH_TEST_CLIENT)/test_tool 32 | 33 | 34 | # libtinypc 35 | # if you have installed libtinyrpc.a in another path, please modify it 36 | TINYRPC_LIB = /usr/lib/libtinyrpc.a 37 | 38 | # protobuf 39 | # if you have installed libprotobuf.a in another path, please modify it 40 | PROTOBUF_LIB = /usr/lib/libprotobuf.a 41 | 42 | # tinyxml 43 | # if you have installed libtinyxml.a in another path, please modify it 44 | TINYXML_LIB = /usr/lib/libtinyxml.a 45 | 46 | # out bin file 47 | TARGET = $(PATH_BIN)/${PROJECT_NAME} 48 | 49 | CXX := g++ 50 | 51 | CXX_FLAGS := -g -O3 -std=c++11 -Wall -Wno-deprecated -Wno-unused-but-set-variable 52 | 53 | CXX_FLAGS += -I../ -I ./$(PATH_PB) -I ./$(PATH_SERVICE) -I ./$(PATH_INTERFACE) -I ./$(PATH_COMM) 54 | 55 | LIBS += $(TINYRPC_LIB) 56 | 57 | LIBS += $(PROTOBUF_LIB) $(TINYXML_LIB) 58 | 59 | PB_OBJS := $(patsubst $(PATH_PB)/%.cc, $(PATH_OBJ)/%.o, $(wildcard $(PATH_PB)/*.cc)) 60 | SERVICE_OBJS := $(patsubst $(PATH_SERVICE)/%.cc, $(PATH_OBJ)/%.o, $(wildcard $(PATH_SERVICE)/*.cc)) 61 | INTERFACE_OBJS := $(patsubst $(PATH_INTERFACE)/%.cc, $(PATH_OBJ)/%.o, $(wildcard $(PATH_INTERFACE)/*.cc)) 62 | COMM_OBJS := $(patsubst $(PATH_COMM)/%.cc, $(PATH_OBJ)/%.o, $(wildcard $(PATH_COMM)/*.cc)) 63 | TEST_BINS := $(patsubst $(PATH_TEST_CLIENT)/%.cc, $(PATH_TEST_CLIENT_TOOL)/%, $(wildcard $(PATH_TEST_CLIENT)/*.cc)) 64 | 65 | OUT : $(TARGET) $(TEST_BINS) 66 | 67 | $(TARGET) : $(PB_OBJS) $(SERVICE_OBJS) $(INTERFACE_OBJS) 68 | $(CXX) $(CXX_FLAGS) main.cc -o $@ $^ $(LIBS) -ldl -lpthread 69 | 70 | $(PATH_TEST_CLIENT_TOOL)/%: $(PATH_TEST_CLIENT)/%.cc $(PB_OBJS) 71 | $(CXX) $(CXX_FLAGS) $< -o $@ $(LIBS) $(PB_OBJS) -ldl -lpthread 72 | 73 | $(PATH_OBJ)/%.o : $(PATH_PB)/%.cc 74 | $(CXX) $(CXX_FLAGS) -c $< -o $@ 75 | 76 | $(PATH_OBJ)/%.o : $(PATH_SERVICE)/%.cc 77 | $(CXX) $(CXX_FLAGS) -c $< -o $@ 78 | 79 | $(PATH_OBJ)/%.o : $(PATH_INTERFACE)/%.cc 80 | $(CXX) $(CXX_FLAGS) -c $< -o $@ 81 | 82 | $(PATH_OBJ)/%.o : $(PATH_COMM)/%.cc 83 | $(CXX) $(CXX_FLAGS) -c $< -o $@ 84 | 85 | 86 | 87 | PRINT-% : ; @echo $* = $($*) 88 | 89 | clean : 90 | rm -f $(PB_OBJS) $(SERVICE_OBJS) $(INTERFACE_OBJS) $(COMM_OBJS) $(TARGET) $(TEST_BINS) -------------------------------------------------------------------------------- /generator/template/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | FILE_NAME=$1 3 | PROJECT_NAME=$(basename ${FILE_NAME}) 4 | CURRENT_PATH=$(cd $(dirname $0); pwd) 5 | PROJECT_ROOT_PATH=$(cd $(dirname $0); cd ..; pwd) 6 | PROJECT_BIN_FILE="${CURRENT_PATH}"/"${PROJECT_NAME}" 7 | PROJECT_CONF_FILE="../conf/${PROJECT_NAME}.xml" 8 | 9 | 10 | echo "Run tinyrpc project, name: ${PROJECT_NAME}, path: ${PROJECT_BIN_FILE}" 11 | 12 | if [ -z "$1" ] 13 | then 14 | echo "Please input execuable binary file!" 15 | fi 16 | 17 | # check bin file exist 18 | if [ ! -e ${PROJECT_BIN_FILE} ] 19 | then 20 | echo "Run tinyrpc eror, file: ${PROJECT_BIN_FILE} not exist, please check file" 21 | exit -1 22 | fi 23 | 24 | # check config xml file exist 25 | if [ ! -e ${PROJECT_CONF_FILE} ] 26 | then 27 | echo "Run tinyrpc eror, file: ${PROJECT_CONF_FILE} not exist, please check config file" 28 | exit -1 29 | fi 30 | 31 | # check bin file execute privilege 32 | if [ ! -x ${PROJECT_BIN_FILE} ] 33 | then 34 | echo "chmod +x : ${PROJECT_BIN_FILE}" 35 | chmod +x ${PROJECT_BIN_FILE} 36 | fi 37 | 38 | sh shutdown.sh ${PROJECT_NAME} 39 | nohup ./${PROJECT_NAME} ${PROJECT_CONF_FILE} & > ${PROJECT_ROOT_PATH}/log/${PROJECT_NAME}.nohup_log 40 | echo "Start tinyrpc server ${PROJECT_CONF_FILE} succ" 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /generator/template/server.cc.template: -------------------------------------------------------------------------------- 1 | /************************************************************* 2 | * 3 | * ##### ### # # # # ##### ##### #### 4 | * # # # # # # # # # # # # 5 | * # # # # # # ### ##### # 6 | * # ### # # # # # # #### 7 | * 8 | * Generated by tinyrpc framework tinyrpc_generator.py 9 | * This file will be overwrite every time 10 | * File Name: ${FILE_NAME} 11 | * Create Time: ${CREATE_TIME} 12 | * Allow Edit: False 13 | *************************************************************/ 14 | 15 | 16 | #include 17 | #include 18 | #include 19 | ${INCLUDE_PB_HEADER} 20 | ${INCLUDE_SERVER_HEADER} 21 | ${INCLUDE_BUSINESS_EXCEPTION_HEADER} 22 | ${INCLUDE_SERVICE_HEADER} 23 | ${INCLUDE_INTERFACEBASE_HEADER} 24 | 25 | #define CALL_RPC_INTERFACE(type) \ 26 | tinyrpc::TinyPbRpcController* con = dynamic_cast(controller); \ 27 | std::shared_ptr impl = std::make_shared(*request, *response, *con); \ 28 | try { \ 29 | AppInfoLog("In|request:{%s}", request->ShortDebugString().c_str()); \ 30 | impl->run(); \ 31 | response->set_ret_code(0); \ 32 | response->set_res_info("OK"); \ 33 | AppInfoLog("Out|response:{%s}", response->ShortDebugString().c_str()); \ 34 | } catch (${PROJECT_NAME}::BusinessException& e) { \ 35 | AppErrorLog("[%s:%d] occur BusinessException, error code=%d, error info = %s", \ 36 | e.file_name().c_str(), e.line(), e.code(), e.error().c_str()); \ 37 | response->set_ret_code(e.code()); \ 38 | response->set_res_info(e.error()); \ 39 | AppErrorLog("Out|response:{%s}", response->ShortDebugString().c_str()); \ 40 | } catch (std::exception&) { \ 41 | AppErrorLog("occur std::exception, error code = -1, errorinfo = UnKnown error"); \ 42 | response->set_ret_code(-1); \ 43 | response->set_res_info("UnKnown error"); \ 44 | AppErrorLog("Out|response:{%s}", response->ShortDebugString().c_str()); \ 45 | } catch (...) { \ 46 | AppErrorLog("occur UnKnown exception, error code = -1, errorinfo = UnKnown error"); \ 47 | response->set_ret_code(-1); \ 48 | response->set_res_info("UnKnown error"); \ 49 | AppErrorLog("Out|response:{%s}", response->ShortDebugString().c_str()); \ 50 | } \ 51 | if (done) { \ 52 | done->Run(); \ 53 | } \ 54 | 55 | namespace ${PROJECT_NAME} { 56 | 57 | ${METHOD} 58 | 59 | } -------------------------------------------------------------------------------- /generator/template/server.h.template: -------------------------------------------------------------------------------- 1 | /************************************************************* 2 | * 3 | * ##### ### # # # # ##### ##### #### 4 | * # # # # # # # # # # # # 5 | * # # # # # # ### ##### # 6 | * # ### # # # # # # #### 7 | * 8 | * Generated by tinyrpc framework tinyrpc_generator.py 9 | * This file will be overwrite every time 10 | * File Name: ${FILE_NAME} 11 | * Create Time: ${CREATE_TIME} 12 | * Allow Edit: False 13 | *************************************************************/ 14 | 15 | 16 | #ifndef ${HEADER_DEFINE} 17 | #define ${HEADER_DEFINE} 18 | 19 | #include 20 | ${INCLUDE_PB_HEADER} 21 | 22 | namespace ${PROJECT_NAME} { 23 | 24 | class ${CLASS_NAME} : public ${SERVICE_NAME} { 25 | 26 | public: 27 | 28 | ${CLASS_NAME}() = default; 29 | 30 | ~${CLASS_NAME}() = default; 31 | 32 | ${METHOD} 33 | 34 | }; 35 | 36 | } 37 | 38 | 39 | #endif -------------------------------------------------------------------------------- /generator/template/shutdown.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$1" ] 4 | then 5 | echo "Please input tinyrpc server name!" 6 | exit -1 7 | fi 8 | 9 | FILE_NAME=$1 10 | PROJECT_NAME=$(basename ${FILE_NAME}) 11 | CURRENT_PATH=$(cd $(dirname $0); pwd) 12 | PROJECT_BIN_FILE="${CURRENT_PATH}"/"${PROJECT_NAME}" 13 | PROJECT_CONF_FILE="../conf/${PROJECT_NAME}.xml" 14 | 15 | echo "Shutdown tinyrpc project, name: ${PROJECT_NAME}, path: ${PROJECT_BIN_FILE}" 16 | 17 | # check bin file exist 18 | if [ ! -e ${PROJECT_BIN_FILE} ] 19 | then 20 | echo "Shtdown tinyrpc eror, file: ${PROJECT_BIN_FILE} not exist, please check file" 21 | exit -1 22 | fi 23 | 24 | 25 | proc_list=`ps -elf | grep "${PROJECT_NAME}" | grep -v 'grep' | grep -v 'shutdown.sh' | awk '{print $4}'` 26 | echo ${proc_list[0]} 27 | 28 | for i in ${proc_list[@]} 29 | do 30 | bin_path=`ls -l /proc/${i}/exe | awk '{print $11}'` 31 | echo ${bin_path} 32 | if [ "$bin_path" = "$PROJECT_BIN_FILE" ] 33 | then 34 | echo "kill this proc: ${i}" 35 | kill -9 ${i} 36 | fi 37 | done 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /generator/template/test_tinyrpc_client.cc.template: -------------------------------------------------------------------------------- 1 | /************************************************************* 2 | * 3 | * ##### ### # # # # ##### ##### #### 4 | * # # # # # # # # # # # # 5 | * # # # # # # ### ##### # 6 | * # ### # # # # # # #### 7 | * 8 | * Generated by tinyrpc framework tinyrpc_generator.py 9 | * This file will not be overwrite althrough protobuf file changed !!! 10 | * Just write this file while not exist 11 | * File Name: ${FILE_NAME} 12 | * Create Time: ${CREATE_TIME} 13 | * Allow Edit: True 14 | *************************************************************/ 15 | 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | ${INCLUDE_PB_HEADER} 24 | 25 | 26 | void test_client() { 27 | 28 | tinyrpc::IPAddress::ptr addr = std::make_shared("127.0.0.1", 12345); 29 | 30 | tinyrpc::TinyPbRpcChannel channel(addr); 31 | ${STUBCLASS} stub(&channel); 32 | 33 | tinyrpc::TinyPbRpcController rpc_controller; 34 | rpc_controller.SetTimeout(5000); 35 | 36 | ${REQUEST_TYPE} rpc_req; 37 | ${RESPONSE_TYPE} rpc_res; 38 | 39 | std::cout << "Send to tinyrpc server " << addr->toString() << ", requeset body: " << rpc_req.ShortDebugString() << std::endl; 40 | stub.${METHOD_NAME}(&rpc_controller, &rpc_req, &rpc_res, NULL); 41 | 42 | if (rpc_controller.ErrorCode() != 0) { 43 | std::cout << "Failed to call tinyrpc server, error code: " << rpc_controller.ErrorCode() << ", error info: " << rpc_controller.ErrorText() << std::endl; 44 | return; 45 | } 46 | 47 | std::cout << "Success get response from tinyrpc server " << addr->toString() << ", response body: " << rpc_res.ShortDebugString() << std::endl; 48 | 49 | } 50 | 51 | int main(int argc, char* argv[]) { 52 | 53 | test_client(); 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /imgs/block_async_call.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gooddbird/tinyrpc/3db2785f7c46d64b70999894154aa4096f1a13ef/imgs/block_async_call.drawio.png -------------------------------------------------------------------------------- /imgs/execute.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gooddbird/tinyrpc/3db2785f7c46d64b70999894154aa4096f1a13ef/imgs/execute.drawio.png -------------------------------------------------------------------------------- /imgs/input.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gooddbird/tinyrpc/3db2785f7c46d64b70999894154aa4096f1a13ef/imgs/input.drawio.png -------------------------------------------------------------------------------- /imgs/mine/alipay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gooddbird/tinyrpc/3db2785f7c46d64b70999894154aa4096f1a13ef/imgs/mine/alipay.png -------------------------------------------------------------------------------- /imgs/mine/wechatpay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gooddbird/tinyrpc/3db2785f7c46d64b70999894154aa4096f1a13ef/imgs/mine/wechatpay.png -------------------------------------------------------------------------------- /imgs/nonblock_async_call.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gooddbird/tinyrpc/3db2785f7c46d64b70999894154aa4096f1a13ef/imgs/nonblock_async_call.drawio.png -------------------------------------------------------------------------------- /imgs/tcp_server.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gooddbird/tinyrpc/3db2785f7c46d64b70999894154aa4096f1a13ef/imgs/tcp_server.drawio.png -------------------------------------------------------------------------------- /imgs/test_succ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gooddbird/tinyrpc/3db2785f7c46d64b70999894154aa4096f1a13ef/imgs/test_succ.png -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | ################################## 2 | # makefile 3 | # ikerli 4 | # 2022-05-23 5 | ################################## 6 | 7 | PATH_BIN = bin 8 | PATH_LIB = lib 9 | PATH_OBJ = obj 10 | 11 | PATH_TINYRPC = tinyrpc 12 | PATH_COMM = $(PATH_TINYRPC)/comm 13 | PATH_COROUTINE = $(PATH_TINYRPC)/coroutine 14 | PATH_NET = $(PATH_TINYRPC)/net 15 | PATH_HTTP = $(PATH_TINYRPC)/net/http 16 | PATH_TCP = $(PATH_TINYRPC)/net/tcp 17 | PATH_TINYPB = $(PATH_TINYRPC)/net/tinypb 18 | 19 | PATH_TESTCASES = testcases 20 | 21 | # will install lib to /usr/lib/libtinyrpc.a 22 | PATH_INSTALL_LIB_ROOT = /usr/lib 23 | 24 | # will install all header file to /usr/include/tinyrpc 25 | PATH_INSTALL_INC_ROOT = /usr/include 26 | 27 | PATH_INSTALL_INC_COMM = $(PATH_INSTALL_INC_ROOT)/$(PATH_COMM) 28 | PATH_INSTALL_INC_COROUTINE = $(PATH_INSTALL_INC_ROOT)/$(PATH_COROUTINE) 29 | PATH_INSTALL_INC_NET = $(PATH_INSTALL_INC_ROOT)/$(PATH_NET) 30 | PATH_INSTALL_INC_HTTP = $(PATH_INSTALL_INC_ROOT)/$(PATH_HTTP) 31 | PATH_INSTALL_INC_TCP = $(PATH_INSTALL_INC_ROOT)/$(PATH_TCP) 32 | PATH_INSTALL_INC_TINYPB = $(PATH_INSTALL_INC_ROOT)/$(PATH_TINYPB) 33 | 34 | 35 | 36 | # PATH_PROTOBUF = /usr/include/google 37 | # PATH_TINYXML = /usr/include/tinyxml 38 | 39 | CXX := g++ 40 | 41 | CXXFLAGS += -g -O0 -std=c++11 -Wall -Wno-deprecated -Wno-unused-but-set-variable 42 | # add lib plugin 43 | # CXXFLAGS += -g -O0 -std=c++11 -Wall -Wno-deprecated -Wno-unused-but-set-variable -D DECLARE_MYSQL_PLUGIN 44 | CXXFLAGS += -I./ -I$(PATH_TINYRPC) -I$(PATH_COMM) -I$(PATH_COROUTINE) -I$(PATH_NET) -I$(PATH_HTTP) -I$(PATH_TCP) -I$(PATH_TINYPB) 45 | # CXXFLAGS += -I./ -I$(PATH_TINYRPC) -I$(PATH_COMM) -I$(PATH_COROUTINE) -I$(PATH_NET) -I$(PATH_HTTP) -I$(PATH_TCP) -I$(PATH_TINYPB) 46 | 47 | LIBS += /usr/lib/libprotobuf.a /usr/lib/libtinyxml.a 48 | 49 | MYSQL_LIB = /usr/lib/libmysqlclient.a 50 | 51 | PLUGIN_LIB = 52 | # PLUGIN_LIB = $(MYSQL_LIB) 53 | 54 | COMM_OBJ := $(patsubst $(PATH_COMM)/%.cc, $(PATH_OBJ)/%.o, $(wildcard $(PATH_COMM)/*.cc)) 55 | COROUTINE_OBJ := $(patsubst $(PATH_COROUTINE)/%.cc, $(PATH_OBJ)/%.o, $(wildcard $(PATH_COROUTINE)/*.cc)) 56 | NET_OBJ := $(patsubst $(PATH_NET)/%.cc, $(PATH_OBJ)/%.o, $(wildcard $(PATH_NET)/*.cc)) 57 | HTTP_OBJ := $(patsubst $(PATH_HTTP)/%.cc, $(PATH_OBJ)/%.o, $(wildcard $(PATH_HTTP)/*.cc)) 58 | TCP_OBJ := $(patsubst $(PATH_TCP)/%.cc, $(PATH_OBJ)/%.o, $(wildcard $(PATH_TCP)/*.cc)) 59 | TINYPB_OBJ := $(patsubst $(PATH_TINYPB)/%.cc, $(PATH_OBJ)/%.o, $(wildcard $(PATH_TINYPB)/*.cc)) 60 | 61 | COR_CTX_SWAP := coctx_swap.o 62 | 63 | ALL_TESTS : $(PATH_BIN)/test_tinypb_server $(PATH_BIN)/test_http_server $(PATH_BIN)/test_coroutine $(PATH_BIN)/test_tinypb_server_client\ 64 | 65 | TEST_CASE_OUT := $(PATH_BIN)/test_tinypb_server $(PATH_BIN)/test_http_server $(PATH_BIN)/test_tinypb_server_client\ 66 | 67 | LIB_OUT := $(PATH_LIB)/libtinyrpc.a 68 | 69 | $(PATH_BIN)/test_tinypb_server: $(LIB_OUT) 70 | $(CXX) $(CXXFLAGS) $(PATH_TESTCASES)/test_tinypb_server.cc $(PATH_TESTCASES)/test_tinypb_server.pb.cc -o $@ $(LIB_OUT) $(LIBS) -ldl -pthread $(PLUGIN_LIB) 71 | 72 | $(PATH_BIN)/test_tinypb_server_client: $(LIB_OUT) 73 | $(CXX) $(CXXFLAGS) $(PATH_TESTCASES)/test_tinypb_server_client.cc $(PATH_TESTCASES)/test_tinypb_server.pb.cc -o $@ $(LIB_OUT) $(LIBS) -ldl -pthread $(PLUGIN_LIB) 74 | 75 | $(PATH_BIN)/test_http_server: $(LIB_OUT) 76 | $(CXX) $(CXXFLAGS) $(PATH_TESTCASES)/test_http_server.cc $(PATH_TESTCASES)/test_tinypb_server.pb.cc -o $@ $(LIB_OUT) $(LIBS) -ldl -pthread $(PLUGIN_LIB) 77 | 78 | $(PATH_BIN)/test_coroutine: $(LIB_OUT) 79 | $(CXX) $(CXXFLAGS) $(PATH_TESTCASES)/test_coroutine.cc -o $@ $(LIB_OUT) $(LIBS) -ldl -pthread $(PLUGIN_LIB) 80 | 81 | $(LIB_OUT): $(COMM_OBJ) $(COROUTINE_OBJ) $(PATH_OBJ)/coctx_swap.o $(NET_OBJ) $(HTTP_OBJ) $(TCP_OBJ) $(TINYPB_OBJ) 82 | cd $(PATH_OBJ) && ar rcv libtinyrpc.a *.o && cp libtinyrpc.a ../lib/ 83 | 84 | $(PATH_OBJ)/%.o : $(PATH_COMM)/%.cc 85 | $(CXX) $(CXXFLAGS) -c $< -o $@ 86 | 87 | $(PATH_OBJ)/%.o : $(PATH_COROUTINE)/%.cc 88 | $(CXX) $(CXXFLAGS) -c $< -o $@ 89 | 90 | $(PATH_OBJ)/coctx_swap.o : $(PATH_COROUTINE)/coctx_swap.S 91 | $(CXX) $(CXXFLAGS) -c $< -o $@ 92 | 93 | $(PATH_OBJ)/%.o : $(PATH_NET)/%.cc 94 | $(CXX) $(CXXFLAGS) -c $< -o $@ 95 | 96 | $(PATH_OBJ)/%.o : $(PATH_HTTP)/%.cc 97 | $(CXX) $(CXXFLAGS) -c $< -o $@ 98 | 99 | $(PATH_OBJ)/%.o : $(PATH_TCP)/%.cc 100 | $(CXX) $(CXXFLAGS) -c $< -o $@ 101 | 102 | $(PATH_OBJ)/%.o : $(PATH_TINYPB)/%.cc 103 | $(CXX) $(CXXFLAGS) -c $< -o $@ 104 | 105 | 106 | # print something test 107 | # like this: make PRINT-PATH_BIN, and then will print variable PATH_BIN 108 | PRINT-% : ; @echo $* = $($*) 109 | 110 | 111 | # to clean 112 | clean : 113 | rm -f $(COMM_OBJ) $(COROUTINE_OBJ) $(NET_OBJ) $(HTTP_OBJ) $(TCP_OBJ) $(TINYPB_OBJ) $(TESTCASES) $(PATH_COROUTINE)/coctx_swap.o $(TEST_CASE_OUT) $(PATH_LIB)/libtinyrpc.a $(PATH_OBJ)/libtinyrpc.a 114 | 115 | # install 116 | install: 117 | mkdir -p $(PATH_INSTALL_INC_COMM) $(PATH_INSTALL_INC_COROUTINE) $(PATH_INSTALL_INC_NET) \ 118 | && mkdir -p $(PATH_INSTALL_INC_TCP) $(PATH_INSTALL_INC_HTTP) $(PATH_INSTALL_INC_TINYPB) \ 119 | && cp $(PATH_COMM)/*.h $(PATH_INSTALL_INC_COMM) \ 120 | && cp $(PATH_COROUTINE)/*.h $(PATH_INSTALL_INC_COROUTINE) \ 121 | && cp $(PATH_NET)/*.h $(PATH_INSTALL_INC_NET) \ 122 | && cp $(PATH_HTTP)/*.h $(PATH_INSTALL_INC_HTTP) \ 123 | && cp $(PATH_TCP)/*.h $(PATH_INSTALL_INC_TCP) \ 124 | && cp $(PATH_TINYPB)/*.h $(PATH_INSTALL_INC_TINYPB) \ 125 | && cp $(LIB_OUT) $(PATH_INSTALL_LIB_ROOT)/ 126 | 127 | 128 | # uninstall 129 | uninstall: 130 | rm -rf $(PATH_INSTALL_INC_ROOT)/tinyrpc && rm -f $(PATH_INSTALL_LIB_ROOT)/libtinyrpc.a -------------------------------------------------------------------------------- /testcases/test_coroutine.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "tinyrpc/comm/log.h" 6 | #include "tinyrpc/coroutine/coroutine_pool.h" 7 | #include "tinyrpc/coroutine/coroutine_hook.h" 8 | #include "tinyrpc/coroutine/coroutine.h" 9 | #include "tinyrpc/net/mutex.h" 10 | 11 | 12 | tinyrpc::Coroutine::ptr cor; 13 | tinyrpc::Coroutine::ptr cor2; 14 | 15 | class Test { 16 | 17 | public: 18 | tinyrpc::CoroutineMutex m_coroutine_mutex; 19 | int a = 1; 20 | }; 21 | Test test_; 22 | 23 | void fun1() { 24 | std::cout << "cor1 ---- now fitst resume fun1 coroutine by thread 1" << std::endl; 25 | std::cout << "cor1 ---- now begin to yield fun1 coroutine" << std::endl; 26 | 27 | test_.m_coroutine_mutex.lock(); 28 | 29 | std::cout << "cor1 ---- coroutine lock on test_, sleep 5s begin" << std::endl; 30 | 31 | sleep(5); 32 | std::cout << "cor1 ---- sleep 5s end, now back coroutine lock" << std::endl; 33 | 34 | test_.m_coroutine_mutex.unlock(); 35 | 36 | tinyrpc::Coroutine::Yield(); 37 | std::cout << "cor1 ---- fun1 coroutine back, now end" << std::endl; 38 | 39 | } 40 | 41 | void fun2() { 42 | std::cout << "cor222 ---- now fitst resume fun1 coroutine by thread 1" << std::endl; 43 | std::cout << "cor222 ---- now begin to yield fun1 coroutine" << std::endl; 44 | 45 | sleep(2); 46 | std::cout << "cor222 ---- coroutine2 want to get coroutine lock of test_" << std::endl; 47 | test_.m_coroutine_mutex.lock(); 48 | 49 | std::cout << "cor222 ---- coroutine2 get coroutine lock of test_ succ" << std::endl; 50 | 51 | } 52 | 53 | 54 | void* thread1_func(void*) { 55 | std::cout << "thread 1 begin" << std::endl; 56 | std::cout << "now begin to resume fun1 coroutine in thread 1" << std::endl; 57 | tinyrpc::Coroutine::Resume(cor.get()); 58 | std::cout << "now fun1 coroutine back in thread 1"<< std::endl; 59 | std::cout << "thread 1 end" << std::endl; 60 | return NULL; 61 | } 62 | 63 | void* thread2_func(void*) { 64 | tinyrpc::Coroutine::GetCurrentCoroutine(); 65 | std::cout << "thread 2 begin" << std::endl; 66 | std::cout << "now begin to resume fun1 coroutine in thread 2" << std::endl; 67 | tinyrpc::Coroutine::Resume(cor2.get()); 68 | std::cout << "now fun1 coroutine back in thread 2" << std::endl; 69 | std::cout << "thread 2 end" << std::endl; 70 | return NULL; 71 | } 72 | 73 | int main(int argc, char* argv[]) { 74 | tinyrpc::SetHook(false); 75 | std::cout << "main begin" << std::endl; 76 | int stack_size = 128 * 1024; 77 | char* sp = reinterpret_cast(malloc(stack_size)); 78 | cor = std::make_shared(stack_size, sp, fun1); 79 | 80 | char* sp2 = reinterpret_cast(malloc(stack_size)); 81 | cor2 = std::make_shared(stack_size, sp2, fun2); 82 | 83 | 84 | pthread_t thread2; 85 | pthread_create(&thread2, NULL, &thread2_func, NULL); 86 | 87 | thread1_func(NULL); 88 | 89 | pthread_join(thread2, NULL); 90 | 91 | std::cout << "main end" << std::endl; 92 | } 93 | -------------------------------------------------------------------------------- /testcases/test_http_server.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "tinyrpc/comm/start.h" 5 | #include "tinyrpc/net/http/http_request.h" 6 | #include "tinyrpc/net/http/http_response.h" 7 | #include "tinyrpc/net/http/http_servlet.h" 8 | #include "tinyrpc/net/http/http_define.h" 9 | #include "tinyrpc/net/tinypb/tinypb_rpc_channel.h" 10 | #include "tinyrpc/net/tinypb/tinypb_rpc_async_channel.h" 11 | #include "tinyrpc/net/tinypb/tinypb_rpc_controller.h" 12 | #include "tinyrpc/net/tinypb/tinypb_rpc_closure.h" 13 | #include "tinyrpc/net/net_address.h" 14 | #include "test_tinypb_server.pb.h" 15 | 16 | 17 | const char* html = "

Welcome to TinyRPC, just enjoy it!

%s

"; 18 | 19 | tinyrpc::IPAddress::ptr addr = std::make_shared("127.0.0.1", 20000); 20 | 21 | class BlockCallHttpServlet : public tinyrpc::HttpServlet { 22 | public: 23 | BlockCallHttpServlet() = default; 24 | ~BlockCallHttpServlet() = default; 25 | 26 | void handle(tinyrpc::HttpRequest* req, tinyrpc::HttpResponse* res) { 27 | AppDebugLog("BlockCallHttpServlet get request"); 28 | AppDebugLog("BlockCallHttpServlet success recive http request, now to get http response"); 29 | setHttpCode(res, tinyrpc::HTTP_OK); 30 | setHttpContentType(res, "text/html;charset=utf-8"); 31 | 32 | queryAgeReq rpc_req; 33 | queryAgeRes rpc_res; 34 | AppDebugLog ("now to call QueryServer TinyRPC server to query who's id is %s", req->m_query_maps["id"].c_str()); 35 | rpc_req.set_id(std::atoi(req->m_query_maps["id"].c_str())); 36 | 37 | tinyrpc::TinyPbRpcChannel channel(addr); 38 | QueryService_Stub stub(&channel); 39 | 40 | tinyrpc::TinyPbRpcController rpc_controller; 41 | rpc_controller.SetTimeout(5000); 42 | 43 | AppDebugLog("BlockCallHttpServlet end to call RPC"); 44 | stub.query_age(&rpc_controller, &rpc_req, &rpc_res, NULL); 45 | AppDebugLog("BlockCallHttpServlet end to call RPC"); 46 | 47 | if (rpc_controller.ErrorCode() != 0) { 48 | char buf[512]; 49 | sprintf(buf, html, "failed to call QueryServer rpc server"); 50 | setHttpBody(res, std::string(buf)); 51 | return; 52 | } 53 | 54 | if (rpc_res.ret_code() != 0) { 55 | std::stringstream ss; 56 | ss << "QueryServer rpc server return bad result, ret = " << rpc_res.ret_code() << ", and res_info = " << rpc_res.res_info(); 57 | AppDebugLog(ss.str().c_str()); 58 | char buf[512]; 59 | sprintf(buf, html, ss.str().c_str()); 60 | setHttpBody(res, std::string(buf)); 61 | return; 62 | } 63 | 64 | std::stringstream ss; 65 | ss << "Success!! Your age is," << rpc_res.age() << " and Your id is " << rpc_res.id(); 66 | 67 | char buf[512]; 68 | sprintf(buf, html, ss.str().c_str()); 69 | setHttpBody(res, std::string(buf)); 70 | 71 | } 72 | 73 | std::string getServletName() { 74 | return "BlockCallHttpServlet"; 75 | } 76 | 77 | }; 78 | 79 | class NonBlockCallHttpServlet: public tinyrpc::HttpServlet { 80 | public: 81 | NonBlockCallHttpServlet() = default; 82 | ~NonBlockCallHttpServlet() = default; 83 | 84 | void handle(tinyrpc::HttpRequest* req, tinyrpc::HttpResponse* res) { 85 | AppInfoLog("NonBlockCallHttpServlet get request"); 86 | AppDebugLog("NonBlockCallHttpServlet success recive http request, now to get http response"); 87 | setHttpCode(res, tinyrpc::HTTP_OK); 88 | setHttpContentType(res, "text/html;charset=utf-8"); 89 | 90 | std::shared_ptr rpc_req = std::make_shared(); 91 | std::shared_ptr rpc_res = std::make_shared(); 92 | AppDebugLog("now to call QueryServer TinyRPC server to query who's id is %s", req->m_query_maps["id"].c_str()); 93 | rpc_req->set_id(std::atoi(req->m_query_maps["id"].c_str())); 94 | 95 | std::shared_ptr rpc_controller = std::make_shared(); 96 | rpc_controller->SetTimeout(10000); 97 | 98 | AppDebugLog("NonBlockCallHttpServlet begin to call RPC async"); 99 | 100 | 101 | tinyrpc::TinyPbRpcAsyncChannel::ptr async_channel = 102 | std::make_shared(addr); 103 | 104 | auto cb = [rpc_res]() { 105 | printf("call succ, res = %s\n", rpc_res->ShortDebugString().c_str()); 106 | AppDebugLog("NonBlockCallHttpServlet async call end, res=%s", rpc_res->ShortDebugString().c_str()); 107 | }; 108 | 109 | std::shared_ptr closure = std::make_shared(cb); 110 | async_channel->saveCallee(rpc_controller, rpc_req, rpc_res, closure); 111 | 112 | QueryService_Stub stub(async_channel.get()); 113 | 114 | stub.query_age(rpc_controller.get(), rpc_req.get(), rpc_res.get(), NULL); 115 | AppDebugLog("NonBlockCallHttpServlet async end, now you can to some another thing"); 116 | 117 | async_channel->wait(); 118 | AppDebugLog("wait() back, now to check is rpc call succ"); 119 | 120 | if (rpc_controller->ErrorCode() != 0) { 121 | AppDebugLog("failed to call QueryServer rpc server"); 122 | char buf[512]; 123 | sprintf(buf, html, "failed to call QueryServer rpc server"); 124 | setHttpBody(res, std::string(buf)); 125 | return; 126 | } 127 | 128 | if (rpc_res->ret_code() != 0) { 129 | std::stringstream ss; 130 | ss << "QueryServer rpc server return bad result, ret = " << rpc_res->ret_code() << ", and res_info = " << rpc_res->res_info(); 131 | char buf[512]; 132 | sprintf(buf, html, ss.str().c_str()); 133 | setHttpBody(res, std::string(buf)); 134 | return; 135 | } 136 | 137 | std::stringstream ss; 138 | ss << "Success!! Your age is," << rpc_res->age() << " and Your id is " << rpc_res->id(); 139 | 140 | char buf[512]; 141 | sprintf(buf, html, ss.str().c_str()); 142 | setHttpBody(res, std::string(buf)); 143 | } 144 | 145 | std::string getServletName() { 146 | return "NonBlockCallHttpServlet"; 147 | } 148 | 149 | }; 150 | 151 | class QPSHttpServlet : public tinyrpc::HttpServlet { 152 | public: 153 | QPSHttpServlet() = default; 154 | ~QPSHttpServlet() = default; 155 | 156 | void handle(tinyrpc::HttpRequest* req, tinyrpc::HttpResponse* res) { 157 | AppDebugLog("QPSHttpServlet get request"); 158 | setHttpCode(res, tinyrpc::HTTP_OK); 159 | setHttpContentType(res, "text/html;charset=utf-8"); 160 | 161 | std::stringstream ss; 162 | ss << "QPSHttpServlet Echo Success!! Your id is," << req->m_query_maps["id"]; 163 | char buf[512]; 164 | sprintf(buf, html, ss.str().c_str()); 165 | setHttpBody(res, std::string(buf)); 166 | AppDebugLog(ss.str().c_str()); 167 | } 168 | 169 | std::string getServletName() { 170 | return "QPSHttpServlet"; 171 | } 172 | 173 | }; 174 | 175 | 176 | int main(int argc, char* argv[]) { 177 | if (argc != 2) { 178 | printf("Start TinyRPC server error, input argc is not 2!"); 179 | printf("Start TinyRPC server like this: \n"); 180 | printf("./server a.xml\n"); 181 | return 0; 182 | } 183 | 184 | tinyrpc::InitConfig(argv[1]); 185 | 186 | REGISTER_HTTP_SERVLET("/qps", QPSHttpServlet); 187 | 188 | REGISTER_HTTP_SERVLET("/block", BlockCallHttpServlet); 189 | REGISTER_HTTP_SERVLET("/nonblock", NonBlockCallHttpServlet); 190 | 191 | tinyrpc::StartRpcServer(); 192 | return 0; 193 | } 194 | -------------------------------------------------------------------------------- /testcases/test_tinypb_server.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "tinyrpc/net/tcp/tcp_server.h" 6 | #include "tinyrpc/net/net_address.h" 7 | #include "tinyrpc/net/mutex.h" 8 | #include "tinyrpc/net/tinypb/tinypb_rpc_dispatcher.h" 9 | #include "tinyrpc/comm/log.h" 10 | #include "tinyrpc/comm/start.h" 11 | #include "test_tinypb_server.pb.h" 12 | 13 | 14 | static int i = 0; 15 | tinyrpc::CoroutineMutex g_cor_mutex; 16 | 17 | class QueryServiceImpl : public QueryService { 18 | public: 19 | QueryServiceImpl() {} 20 | ~QueryServiceImpl() {} 21 | 22 | void query_name(google::protobuf::RpcController* controller, 23 | const ::queryNameReq* request, 24 | ::queryNameRes* response, 25 | ::google::protobuf::Closure* done) { 26 | 27 | AppInfoLog("QueryServiceImpl.query_name, req={%s}", request->ShortDebugString().c_str()); 28 | response->set_id(request->id()); 29 | response->set_name("ikerli"); 30 | 31 | AppInfoLog("QueryServiceImpl.query_name, res={%s}", response->ShortDebugString().c_str()); 32 | 33 | if (done) { 34 | done->Run(); 35 | } 36 | 37 | } 38 | 39 | void query_age(google::protobuf::RpcController* controller, 40 | const ::queryAgeReq* request, 41 | ::queryAgeRes* response, 42 | ::google::protobuf::Closure* done) { 43 | 44 | AppInfoLog("QueryServiceImpl.query_age, req={%s}", request->ShortDebugString().c_str()); 45 | // AppInfoLog << "QueryServiceImpl.query_age, sleep 6 s begin"; 46 | // sleep(6); 47 | // AppInfoLog << "QueryServiceImpl.query_age, sleep 6 s end"; 48 | 49 | response->set_ret_code(0); 50 | response->set_res_info("OK"); 51 | response->set_req_no(request->req_no()); 52 | response->set_id(request->id()); 53 | response->set_age(100100111); 54 | 55 | g_cor_mutex.lock(); 56 | AppDebugLog("begin i = %d", i); 57 | sleep(1); 58 | i++; 59 | AppDebugLog("end i = %d", i); 60 | g_cor_mutex.unlock(); 61 | 62 | if (done) { 63 | done->Run(); 64 | } 65 | // printf("response = %s\n", response->ShortDebugString().c_str()); 66 | 67 | AppInfoLog("QueryServiceImpl.query_age, res={%s}", response->ShortDebugString().c_str()); 68 | 69 | } 70 | 71 | }; 72 | 73 | 74 | int main(int argc, char* argv[]) { 75 | if (argc != 2) { 76 | printf("Start TinyRPC server error, input argc is not 2!"); 77 | printf("Start TinyRPC server like this: \n"); 78 | printf("./server a.xml\n"); 79 | return 0; 80 | } 81 | 82 | tinyrpc::InitConfig(argv[1]); 83 | 84 | REGISTER_SERVICE(QueryServiceImpl); 85 | 86 | tinyrpc::StartRpcServer(); 87 | 88 | return 0; 89 | } 90 | -------------------------------------------------------------------------------- /testcases/test_tinypb_server.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option cc_generic_services = true; 3 | 4 | message queryAgeReq { 5 | int32 req_no = 1; 6 | int32 id = 2; 7 | } 8 | 9 | message queryAgeRes { 10 | int32 ret_code = 1; 11 | string res_info = 2; 12 | int32 req_no = 3; 13 | int32 id = 4; 14 | int32 age = 5; 15 | } 16 | 17 | message queryNameReq { 18 | int32 req_no = 1; 19 | int32 id = 2; 20 | int32 type = 3; 21 | } 22 | 23 | message queryNameRes { 24 | int32 ret_code = 1; 25 | string res_info = 2; 26 | int32 req_no = 3; 27 | int32 id = 4; 28 | string name = 5; 29 | } 30 | 31 | 32 | service QueryService { 33 | // rpc method name 34 | rpc query_name(queryNameReq) returns (queryNameRes); 35 | 36 | // rpc method name 37 | rpc query_age(queryAgeReq) returns (queryAgeRes); 38 | } -------------------------------------------------------------------------------- /testcases/test_tinypb_server_client.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "tinyrpc/net/tinypb/tinypb_rpc_channel.h" 4 | #include "tinyrpc/net/tinypb/tinypb_rpc_async_channel.h" 5 | #include "tinyrpc/net/tinypb/tinypb_rpc_controller.h" 6 | #include "tinyrpc/net/tinypb/tinypb_rpc_closure.h" 7 | #include "tinyrpc/net/net_address.h" 8 | #include "test_tinypb_server.pb.h" 9 | 10 | void test_client() { 11 | 12 | tinyrpc::IPAddress::ptr addr = std::make_shared("127.0.0.1", 39999); 13 | 14 | tinyrpc::TinyPbRpcChannel channel(addr); 15 | QueryService_Stub stub(&channel); 16 | 17 | tinyrpc::TinyPbRpcController rpc_controller; 18 | rpc_controller.SetTimeout(5000); 19 | 20 | queryAgeReq rpc_req; 21 | queryAgeRes rpc_res; 22 | 23 | std::cout << "Send to tinyrpc server " << addr->toString() << ", requeset body: " << rpc_req.ShortDebugString() << std::endl; 24 | stub.query_age(&rpc_controller, &rpc_req, &rpc_res, NULL); 25 | 26 | if (rpc_controller.ErrorCode() != 0) { 27 | std::cout << "Failed to call tinyrpc server, error code: " << rpc_controller.ErrorCode() << ", error info: " << rpc_controller.ErrorText() << std::endl; 28 | return; 29 | } 30 | 31 | std::cout << "Success get response frrom tinyrpc server " << addr->toString() << ", response body: " << rpc_res.ShortDebugString() << std::endl; 32 | 33 | } 34 | 35 | int main(int argc, char* argv[]) { 36 | 37 | test_client(); 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /tinyrpc/comm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(HEADERS 2 | config.h 3 | error_code.h 4 | log.h 5 | msg_req.h 6 | mysql_instase.h 7 | run_time.h 8 | start.h 9 | string_util.h 10 | thread_pool.h 11 | ) 12 | 13 | install(FILES ${HEADERS} DESTINATION include/tinyrpc/comm) -------------------------------------------------------------------------------- /tinyrpc/comm/config.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_COMM_CONFIG_H 2 | #define TINYRPC_COMM_CONFIG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifdef DECLARE_MYSQL_PLUGIN 10 | #include "tinyrpc/comm/mysql_instase.h" 11 | #endif 12 | 13 | namespace tinyrpc { 14 | 15 | enum LogLevel { 16 | DEBUG = 1, 17 | INFO = 2, 18 | WARN = 3, 19 | ERROR = 4, 20 | NONE = 5 // don't print log 21 | }; 22 | 23 | class Config { 24 | 25 | public: 26 | typedef std::shared_ptr ptr; 27 | 28 | Config(const char* file_path); 29 | 30 | ~Config(); 31 | 32 | void readConf(); 33 | 34 | void readDBConfig(TiXmlElement* node); 35 | 36 | void readLogConfig(TiXmlElement* node); 37 | 38 | TiXmlElement* getXmlNode(const std::string& name); 39 | 40 | 41 | public: 42 | 43 | // log params 44 | std::string m_log_path; 45 | std::string m_log_prefix; 46 | int m_log_max_size {0}; 47 | LogLevel m_log_level {LogLevel::DEBUG}; 48 | LogLevel m_app_log_level {LogLevel::DEBUG}; 49 | int m_log_sync_inteval {500}; 50 | 51 | // coroutine params 52 | int m_cor_stack_size {0}; 53 | int m_cor_pool_size {0}; 54 | 55 | int m_msg_req_len {0}; 56 | 57 | int m_max_connect_timeout {0}; // ms 58 | int m_iothread_num {0}; 59 | 60 | int m_timewheel_bucket_num {0}; 61 | int m_timewheel_inteval {0}; 62 | 63 | #ifdef DECLARE_MYSQL_PLUGIN 64 | std::map m_mysql_options; 65 | #endif 66 | 67 | private: 68 | std::string m_file_path; 69 | 70 | TiXmlDocument* m_xml_file; 71 | 72 | 73 | }; 74 | 75 | 76 | } 77 | 78 | #endif // TINYRPC_COMM_CONFIG_H -------------------------------------------------------------------------------- /tinyrpc/comm/error_code.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_COMM_ERRORCODE_H 2 | #define TINYRPC_COMM_ERRORCODE_H 3 | 4 | 5 | namespace tinyrpc { 6 | 7 | #ifndef SYS_ERROR_PREFIX 8 | #define SYS_ERROR_PREFIX(xx) 1000##xx 9 | #endif // SYS_ERROR_PREFIX(xx) 10 | 11 | // 12 | // error 13 | // 14 | const int ERROR_PEER_CLOSED = SYS_ERROR_PREFIX(0000); // connect when peer close 15 | const int ERROR_FAILED_CONNECT = SYS_ERROR_PREFIX(0001); // failed to connection peer host 16 | const int ERROR_FAILED_GET_REPLY = SYS_ERROR_PREFIX(0002); // failed to get server reply 17 | const int ERROR_FAILED_DESERIALIZE = SYS_ERROR_PREFIX(0003); // deserialize failed 18 | const int ERROR_FAILED_SERIALIZE = SYS_ERROR_PREFIX(0004); // serialize failed 19 | 20 | const int ERROR_FAILED_ENCODE = SYS_ERROR_PREFIX(0005); // encode failed 21 | const int ERROR_FAILED_DECODE = SYS_ERROR_PREFIX(0006); // decode failed 22 | 23 | const int ERROR_RPC_CALL_TIMEOUT = SYS_ERROR_PREFIX(0007); // call rpc timeout 24 | 25 | const int ERROR_SERVICE_NOT_FOUND = SYS_ERROR_PREFIX(0008); // not found service name 26 | 27 | const int ERROR_METHOD_NOT_FOUND = SYS_ERROR_PREFIX(0009); // not found method 28 | 29 | const int ERROR_PARSE_SERVICE_NAME = SYS_ERROR_PREFIX(0010); // not found service name 30 | const int ERROR_NOT_SET_ASYNC_PRE_CALL = SYS_ERROR_PREFIX(0011); // you didn't set some nessary param before call async rpc 31 | const int ERROR_CONNECT_SYS_ERR = SYS_ERROR_PREFIX(0012); // connect sys error 32 | 33 | } // namespace tinyrpc 34 | 35 | 36 | #endif // TINYRPC_COMM_ERRORCODE_H -------------------------------------------------------------------------------- /tinyrpc/comm/log.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_COMM_LOG_H 2 | #define TINYRPC_COMM_LOG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "tinyrpc/net/mutex.h" 17 | #include "tinyrpc/comm/config.h" 18 | 19 | 20 | namespace tinyrpc { 21 | 22 | extern tinyrpc::Config::ptr gRpcConfig; 23 | 24 | template 25 | std::string formatString(const char* str, Args&&... args) { 26 | 27 | int size = snprintf(nullptr, 0, str, args...); 28 | 29 | std::string result; 30 | if (size > 0) { 31 | result.resize(size); 32 | snprintf(&result[0], size + 1, str, args...); 33 | } 34 | 35 | return result; 36 | } 37 | 38 | 39 | #define DebugLog \ 40 | if (tinyrpc::OpenLog() && tinyrpc::LogLevel::DEBUG >= tinyrpc::gRpcConfig->m_log_level) \ 41 | tinyrpc::LogTmp(tinyrpc::LogEvent::ptr(new tinyrpc::LogEvent(tinyrpc::LogLevel::DEBUG, __FILE__, __LINE__, __func__, tinyrpc::LogType::RPC_LOG))).getStringStream() 42 | 43 | #define InfoLog \ 44 | if (tinyrpc::OpenLog() && tinyrpc::LogLevel::INFO >= tinyrpc::gRpcConfig->m_log_level) \ 45 | tinyrpc::LogTmp(tinyrpc::LogEvent::ptr(new tinyrpc::LogEvent(tinyrpc::LogLevel::INFO, __FILE__, __LINE__, __func__, tinyrpc::LogType::RPC_LOG))).getStringStream() 46 | 47 | #define WarnLog \ 48 | if (tinyrpc::OpenLog() && tinyrpc::LogLevel::WARN >= tinyrpc::gRpcConfig->m_log_level) \ 49 | tinyrpc::LogTmp(tinyrpc::LogEvent::ptr(new tinyrpc::LogEvent(tinyrpc::LogLevel::WARN, __FILE__, __LINE__, __func__, tinyrpc::LogType::RPC_LOG))).getStringStream() 50 | 51 | #define ErrorLog \ 52 | if (tinyrpc::OpenLog() && tinyrpc::LogLevel::ERROR >= tinyrpc::gRpcConfig->m_log_level) \ 53 | tinyrpc::LogTmp(tinyrpc::LogEvent::ptr(new tinyrpc::LogEvent(tinyrpc::LogLevel::ERROR, __FILE__, __LINE__, __func__, tinyrpc::LogType::RPC_LOG))).getStringStream() 54 | 55 | 56 | #define AppDebugLog(str, ...) \ 57 | if (tinyrpc::OpenLog() && tinyrpc::LogLevel::DEBUG >= tinyrpc::gRpcConfig->m_app_log_level) \ 58 | { \ 59 | tinyrpc::Logger::GetLogger()->pushAppLog(tinyrpc::LogEvent(tinyrpc::LogLevel::DEBUG, __FILE__, __LINE__, __func__, tinyrpc::LogType::APP_LOG).toString() \ 60 | + "[" + std::string(__FILE__) + ":" + std::to_string(__LINE__) + "]\t" + tinyrpc::formatString(str, ##__VA_ARGS__) + "\n");\ 61 | } \ 62 | 63 | #define AppInfoLog(str, ...) \ 64 | if (tinyrpc::OpenLog() && tinyrpc::LogLevel::INFO>= tinyrpc::gRpcConfig->m_app_log_level) \ 65 | { \ 66 | tinyrpc::Logger::GetLogger()->pushAppLog(tinyrpc::LogEvent(tinyrpc::LogLevel::INFO, __FILE__, __LINE__, __func__, tinyrpc::LogType::APP_LOG).toString() \ 67 | + "[" + std::string(__FILE__) + ":" + std::to_string(__LINE__) + "]\t" + tinyrpc::formatString(str, ##__VA_ARGS__) + "\n");\ 68 | } \ 69 | 70 | #define AppWarnLog(str, ...) \ 71 | if (tinyrpc::OpenLog() && tinyrpc::LogLevel::WARN>= tinyrpc::gRpcConfig->m_app_log_level) \ 72 | { \ 73 | tinyrpc::Logger::GetLogger()->pushAppLog(tinyrpc::LogEvent(tinyrpc::LogLevel::WARN, __FILE__, __LINE__, __func__, tinyrpc::LogType::APP_LOG).toString() \ 74 | + "[" + std::string(__FILE__) + ":" + std::to_string(__LINE__) + "]\t" + tinyrpc::formatString(str, ##__VA_ARGS__) + "\n");\ 75 | } \ 76 | 77 | #define AppErrorLog(str, ...) \ 78 | if (tinyrpc::OpenLog() && tinyrpc::LogLevel::ERROR>= tinyrpc::gRpcConfig->m_app_log_level) \ 79 | { \ 80 | tinyrpc::Logger::GetLogger()->pushAppLog(tinyrpc::LogEvent(tinyrpc::LogLevel::ERROR, __FILE__, __LINE__, __func__, tinyrpc::LogType::APP_LOG).toString() \ 81 | + "[" + std::string(__FILE__) + ":" + std::to_string(__LINE__) + "]\t" + tinyrpc::formatString(str, ##__VA_ARGS__) + "\n");\ 82 | } \ 83 | 84 | 85 | 86 | enum LogType { 87 | RPC_LOG = 1, 88 | APP_LOG = 2, 89 | }; 90 | 91 | pid_t gettid(); 92 | 93 | LogLevel stringToLevel(const std::string& str); 94 | std::string levelToString(LogLevel level); 95 | 96 | bool OpenLog(); 97 | 98 | class LogEvent { 99 | 100 | public: 101 | 102 | typedef std::shared_ptr ptr; 103 | LogEvent(LogLevel level, const char* file_name, int line, const char* func_name, LogType type); 104 | 105 | ~LogEvent(); 106 | 107 | std::stringstream& getStringStream(); 108 | 109 | std::string toString(); 110 | 111 | void log(); 112 | 113 | 114 | private: 115 | 116 | // uint64_t m_timestamp; 117 | timeval m_timeval; 118 | LogLevel m_level; 119 | pid_t m_pid {0}; 120 | pid_t m_tid {0}; 121 | int m_cor_id {0}; 122 | 123 | const char* m_file_name; 124 | int m_line {0}; 125 | const char* m_func_name; 126 | LogType m_type; 127 | std::string m_msg_no; 128 | 129 | std::stringstream m_ss; 130 | }; 131 | 132 | 133 | class LogTmp { 134 | 135 | public: 136 | explicit LogTmp(LogEvent::ptr event); 137 | 138 | ~LogTmp(); 139 | 140 | std::stringstream& getStringStream(); 141 | 142 | private: 143 | LogEvent::ptr m_event; 144 | 145 | }; 146 | 147 | class AsyncLogger { 148 | public: 149 | typedef std::shared_ptr ptr; 150 | 151 | AsyncLogger(const char* file_name, const char* file_path, int max_size, LogType logtype); 152 | ~AsyncLogger(); 153 | 154 | void push(std::vector& buffer); 155 | 156 | void flush(); 157 | 158 | static void* excute(void*); 159 | 160 | void stop(); 161 | 162 | public: 163 | std::queue> m_tasks; 164 | 165 | private: 166 | const char* m_file_name; 167 | const char* m_file_path; 168 | int m_max_size {0}; 169 | LogType m_log_type; 170 | int m_no {0}; 171 | bool m_need_reopen {false}; 172 | FILE* m_file_handle {nullptr}; 173 | std::string m_date; 174 | 175 | Mutex m_mutex; 176 | pthread_cond_t m_condition; 177 | bool m_stop {false}; 178 | 179 | public: 180 | pthread_t m_thread; 181 | sem_t m_semaphore; 182 | 183 | }; 184 | 185 | class Logger { 186 | 187 | public: 188 | static Logger* GetLogger(); 189 | public: 190 | typedef std::shared_ptr ptr; 191 | 192 | Logger(); 193 | ~Logger(); 194 | 195 | void init(const char* file_name, const char* file_path, int max_size, int sync_inteval); 196 | 197 | void pushRpcLog(const std::string& log_msg); 198 | void pushAppLog(const std::string& log_msg); 199 | void loopFunc(); 200 | 201 | void flush(); 202 | 203 | void start(); 204 | 205 | AsyncLogger::ptr getAsyncLogger() { 206 | return m_async_rpc_logger; 207 | } 208 | 209 | AsyncLogger::ptr getAsyncAppLogger() { 210 | return m_async_app_logger; 211 | } 212 | 213 | public: 214 | std::vector m_buffer; 215 | std::vector m_app_buffer; 216 | 217 | private: 218 | Mutex m_app_buff_mutex; 219 | Mutex m_buff_mutex; 220 | bool m_is_init {false}; 221 | AsyncLogger::ptr m_async_rpc_logger; 222 | AsyncLogger::ptr m_async_app_logger; 223 | 224 | int m_sync_inteval {0}; 225 | 226 | }; 227 | 228 | void Exit(int code); 229 | 230 | } 231 | 232 | #endif 233 | -------------------------------------------------------------------------------- /tinyrpc/comm/msg_req.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "tinyrpc/comm/log.h" 8 | #include "tinyrpc/comm/config.h" 9 | #include "tinyrpc/comm/msg_req.h" 10 | 11 | 12 | namespace tinyrpc { 13 | 14 | extern tinyrpc::Config::ptr gRpcConfig; 15 | 16 | static thread_local std::string t_msg_req_nu; 17 | static thread_local std::string t_max_msg_req_nu; 18 | // static thread_local int t_msg_req_len = 20; 19 | 20 | static int g_random_fd = -1; 21 | 22 | std::string MsgReqUtil::genMsgNumber() { 23 | 24 | int t_msg_req_len = 20; 25 | if (gRpcConfig) { 26 | t_msg_req_len = gRpcConfig->m_msg_req_len; 27 | } 28 | 29 | if (t_msg_req_nu.empty() || t_msg_req_nu == t_max_msg_req_nu) { 30 | if (g_random_fd == -1) { 31 | g_random_fd = open("/dev/urandom", O_RDONLY); 32 | } 33 | std::string res(t_msg_req_len, 0); 34 | if ((read(g_random_fd, &res[0], t_msg_req_len)) != t_msg_req_len) { 35 | ErrorLog << "read /dev/urandom data less " << t_msg_req_len << " bytes"; 36 | return ""; 37 | } 38 | t_max_msg_req_nu = ""; 39 | for (int i = 0; i < t_msg_req_len; ++i) { 40 | uint8_t x = ((uint8_t)(res[i])) % 10; 41 | res[i] = x + '0'; 42 | t_max_msg_req_nu += "9"; 43 | } 44 | t_msg_req_nu = res; 45 | 46 | } else { 47 | int i = t_msg_req_nu.length() - 1; 48 | while(t_msg_req_nu[i] == '9' && i >= 0) { 49 | i--; 50 | } 51 | if (i >= 0) { 52 | t_msg_req_nu[i] += 1; 53 | for (size_t j = i + 1; j < t_msg_req_nu.length(); ++j) { 54 | t_msg_req_nu[j] = '0'; 55 | } 56 | } 57 | 58 | } 59 | // DebugLog << "get msg_req_nu is " << t_msg_req_nu; 60 | return t_msg_req_nu; 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /tinyrpc/comm/msg_req.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_COMM_MSG_REQ_H 2 | #define TINYRPC_COMM_MSG_REQ_H 3 | 4 | #include 5 | 6 | namespace tinyrpc { 7 | 8 | class MsgReqUtil { 9 | public: 10 | static std::string genMsgNumber(); 11 | 12 | }; 13 | 14 | 15 | } 16 | 17 | 18 | #endif -------------------------------------------------------------------------------- /tinyrpc/comm/mysql_instase.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_COMM_MYSQL_INSTASE_H 2 | #define TINYRPC_COMM_MYSQL_INSTASE_H 3 | 4 | #ifdef DECLARE_MYSQL_PLUGIN 5 | #include 6 | #endif 7 | 8 | #include 9 | #include 10 | #include "tinyrpc/net/mutex.h" 11 | #include "tinyrpc/net/net_address.h" 12 | 13 | namespace tinyrpc { 14 | 15 | 16 | struct MySQLOption { 17 | public: 18 | explicit MySQLOption(const IPAddress& addr) : m_addr(addr) {}; 19 | ~MySQLOption() {}; 20 | 21 | public: 22 | IPAddress m_addr; 23 | std::string m_user; 24 | std::string m_passwd; 25 | std::string m_select_db; 26 | std::string m_char_set; 27 | }; 28 | 29 | #ifdef DECLARE_MYSQL_PLUGIN 30 | class MySQLThreadInit { 31 | public: 32 | 33 | MySQLThreadInit(); 34 | 35 | ~MySQLThreadInit(); 36 | 37 | }; 38 | 39 | class MySQLInstase { 40 | public: 41 | 42 | typedef std::shared_ptr ptr; 43 | 44 | MySQLInstase(const MySQLOption& option); 45 | 46 | ~MySQLInstase(); 47 | 48 | bool isInitSuccess(); 49 | 50 | int query(const std::string& sql); 51 | 52 | int commit(); 53 | 54 | int begin(); 55 | 56 | int rollBack(); 57 | 58 | MYSQL_RES* storeResult(); 59 | 60 | MYSQL_ROW fetchRow(MYSQL_RES* res); 61 | 62 | void freeResult(MYSQL_RES* res); 63 | 64 | long long numFields(MYSQL_RES* res); 65 | 66 | long long affectedRows(); 67 | 68 | std::string getMySQLErrorInfo(); 69 | 70 | int getMySQLErrno(); 71 | 72 | private: 73 | int reconnect(); 74 | 75 | private: 76 | MySQLOption m_option; 77 | bool m_init_succ {false}; 78 | bool m_in_trans {false}; 79 | Mutex m_mutex; 80 | MYSQL* m_sql_handler {NULL}; 81 | 82 | }; 83 | 84 | 85 | class MySQLInstaseFactroy { 86 | public: 87 | MySQLInstaseFactroy() = default; 88 | 89 | ~MySQLInstaseFactroy() = default; 90 | 91 | MySQLInstase::ptr GetMySQLInstase(const std::string& key); 92 | public: 93 | static MySQLInstaseFactroy* GetThreadMySQLFactory(); 94 | 95 | }; 96 | 97 | #endif 98 | 99 | 100 | 101 | } 102 | 103 | 104 | #endif -------------------------------------------------------------------------------- /tinyrpc/comm/run_time.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_COMM_RUN_TIME_H 2 | #define TINYRPC_COMM_RUN_TIME_H 3 | 4 | #include 5 | 6 | namespace tinyrpc { 7 | 8 | class RunTime { 9 | public: 10 | std::string m_msg_no; 11 | std::string m_interface_name; 12 | }; 13 | 14 | } 15 | 16 | 17 | #endif -------------------------------------------------------------------------------- /tinyrpc/comm/start.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tinyrpc/comm/start.h" 3 | #include "tinyrpc/comm/log.h" 4 | #include "tinyrpc/comm/config.h" 5 | #include "tinyrpc/net/tcp/tcp_server.h" 6 | #include "tinyrpc/coroutine/coroutine_hook.h" 7 | 8 | namespace tinyrpc { 9 | 10 | tinyrpc::Config::ptr gRpcConfig; 11 | tinyrpc::Logger::ptr gRpcLogger; 12 | tinyrpc::TcpServer::ptr gRpcServer; 13 | 14 | static int g_init_config = 0; 15 | 16 | void InitConfig(const char* file) { 17 | tinyrpc::SetHook(false); 18 | 19 | #ifdef DECLARE_MYSQL_PULGIN 20 | int rt = mysql_library_init(0, NULL, NULL); 21 | if (rt != 0) { 22 | printf("Start TinyRPC server error, call mysql_library_init error\n"); 23 | mysql_library_end(); 24 | exit(0); 25 | } 26 | #endif 27 | 28 | tinyrpc::SetHook(true); 29 | 30 | if (g_init_config == 0) { 31 | gRpcConfig = std::make_shared(file); 32 | gRpcConfig->readConf(); 33 | g_init_config = 1; 34 | } 35 | } 36 | 37 | // void RegisterService(google::protobuf::Service* service) { 38 | // gRpcServer->registerService(service); 39 | // } 40 | 41 | TcpServer::ptr GetServer() { 42 | return gRpcServer; 43 | } 44 | 45 | void StartRpcServer() { 46 | gRpcLogger->start(); 47 | gRpcServer->start(); 48 | } 49 | 50 | int GetIOThreadPoolSize() { 51 | return gRpcServer->getIOThreadPool()->getIOThreadPoolSize(); 52 | } 53 | 54 | Config::ptr GetConfig() { 55 | return gRpcConfig; 56 | } 57 | 58 | void AddTimerEvent(TimerEvent::ptr event) { 59 | 60 | } 61 | 62 | } -------------------------------------------------------------------------------- /tinyrpc/comm/start.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_COMM_START_H 2 | #define TINYRPC_COMM_START_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "tinyrpc/comm/log.h" 9 | #include "tinyrpc/net/tcp/tcp_server.h" 10 | #include "tinyrpc/net/timer.h" 11 | 12 | namespace tinyrpc { 13 | 14 | 15 | #define REGISTER_HTTP_SERVLET(path, servlet) \ 16 | do { \ 17 | if(!tinyrpc::GetServer()->registerHttpServlet(path, std::make_shared())) { \ 18 | printf("Start TinyRPC server error, because register http servelt error, please look up rpc log get more details!\n"); \ 19 | tinyrpc::Exit(0); \ 20 | } \ 21 | } while(0)\ 22 | 23 | #define REGISTER_SERVICE(service) \ 24 | do { \ 25 | if (!tinyrpc::GetServer()->registerService(std::make_shared())) { \ 26 | printf("Start TinyRPC server error, because register protobuf service error, please look up rpc log get more details!\n"); \ 27 | tinyrpc::Exit(0); \ 28 | } \ 29 | } while(0)\ 30 | 31 | 32 | void InitConfig(const char* file); 33 | 34 | // void RegisterService(google::protobuf::Service* service); 35 | 36 | void StartRpcServer(); 37 | 38 | TcpServer::ptr GetServer(); 39 | 40 | int GetIOThreadPoolSize(); 41 | 42 | Config::ptr GetConfig(); 43 | 44 | void AddTimerEvent(TimerEvent::ptr event); 45 | 46 | } 47 | 48 | #endif -------------------------------------------------------------------------------- /tinyrpc/comm/string_util.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "tinyrpc/comm/string_util.h" 4 | #include "tinyrpc/comm/log.h" 5 | 6 | 7 | namespace tinyrpc { 8 | 9 | void StringUtil::SplitStrToMap(const std::string& str, const std::string& split_str, 10 | const std::string& joiner, std::map& res) { 11 | 12 | if (str.empty() || split_str.empty() || joiner.empty()) { 13 | DebugLog << "str or split_str or joiner_str is empty"; 14 | return; 15 | } 16 | std::string tmp = str; 17 | 18 | std::vector vec; 19 | SplitStrToVector(tmp, split_str, vec); 20 | for (auto i : vec) { 21 | if (!i.empty()) { 22 | size_t j = i.find_first_of(joiner); 23 | if (j != i.npos && j != 0) { 24 | std::string key = i.substr(0, j); 25 | std::string value = i.substr(j + joiner.length(), i.length() - j - joiner.length()); 26 | DebugLog << "insert key = " << key << ", value=" << value; 27 | res[key.c_str()] = value; 28 | } 29 | } 30 | } 31 | 32 | } 33 | 34 | void StringUtil::SplitStrToVector(const std::string& str, const std::string& split_str, 35 | std::vector& res) { 36 | 37 | if (str.empty() || split_str.empty()) { 38 | // DebugLog << "str or split_str is empty"; 39 | return; 40 | } 41 | std::string tmp = str; 42 | if (tmp.substr(tmp.length() - split_str.length(), split_str.length()) != split_str) { 43 | tmp += split_str; 44 | } 45 | 46 | while (1) { 47 | size_t i = tmp.find_first_of(split_str); 48 | if (i == tmp.npos) { 49 | return; 50 | } 51 | int l = tmp.length(); 52 | std::string x = tmp.substr(0, i); 53 | tmp = tmp.substr(i + split_str.length(), l - i - split_str.length()); 54 | if (!x.empty()) { 55 | res.push_back(std::move(x)); 56 | } 57 | } 58 | 59 | } 60 | 61 | 62 | } -------------------------------------------------------------------------------- /tinyrpc/comm/string_util.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_COMM_STRING_UTIL_H 2 | #define TINYRPC_COMM_STRING_UTIL_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace tinyrpc { 9 | 10 | class StringUtil { 11 | 12 | public: 13 | // split a string to map 14 | // for example: str is a=1&tt=2&cc=3 split_str = '&' joiner='=' 15 | // get res is {"a":"1", "tt":"2", "cc", "3"} 16 | static void SplitStrToMap(const std::string& str, const std::string& split_str, 17 | const std::string& joiner, std::map& res); 18 | 19 | // split a string to vector 20 | // for example: str is a=1&tt=2&cc=3 split_str = '&' 21 | // get res is {"a=1", "tt=2", "cc=3"} 22 | static void SplitStrToVector(const std::string& str, const std::string& split_str, 23 | std::vector& res); 24 | 25 | }; 26 | 27 | 28 | } 29 | 30 | 31 | #endif -------------------------------------------------------------------------------- /tinyrpc/comm/thread_pool.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "tinyrpc/comm/thread_pool.h" 5 | 6 | namespace tinyrpc { 7 | 8 | void* ThreadPool::MainFunction(void* ptr) { 9 | ThreadPool* pool = reinterpret_cast(ptr); 10 | pthread_cond_init(&pool->m_condition, NULL); 11 | 12 | while (!pool->m_is_stop) { 13 | Mutex::Lock lock(pool->m_mutex); 14 | 15 | while (pool->m_tasks.empty()) { 16 | pthread_cond_wait(&(pool->m_condition), pool->m_mutex.getMutex()); 17 | } 18 | std::function cb = pool->m_tasks.front(); 19 | pool->m_tasks.pop(); 20 | lock.unlock(); 21 | 22 | cb(); 23 | } 24 | return nullptr; 25 | 26 | } 27 | 28 | 29 | ThreadPool::ThreadPool(int size) : m_size(size) { 30 | for (int i = 0; i < m_size; ++i) { 31 | pthread_t thread; 32 | m_threads.emplace_back(thread); 33 | } 34 | pthread_cond_init(&m_condition, nullptr); 35 | 36 | } 37 | 38 | void ThreadPool::start() { 39 | for (int i = 0; i < m_size; ++i) { 40 | pthread_create(&m_threads[i], nullptr, &ThreadPool::MainFunction, this); 41 | } 42 | 43 | } 44 | 45 | void ThreadPool::stop() { 46 | m_is_stop = true; 47 | } 48 | 49 | 50 | void ThreadPool::addTask(std::function cb) { 51 | Mutex::Lock lock(m_mutex); 52 | m_tasks.push(cb); 53 | lock.unlock(); 54 | pthread_cond_signal(&m_condition); 55 | } 56 | 57 | ThreadPool::~ThreadPool() { 58 | // for (int i = 0; i < m_size; ++i) { 59 | // pthread_join(m_threads[i], nullptr); 60 | // } 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /tinyrpc/comm/thread_pool.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_THREAD_THRFEADPOOL_H 2 | #define TINYRPC_THREAD_THRFEADPOOL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "tinyrpc/net/mutex.h" 8 | 9 | namespace tinyrpc { 10 | 11 | class ThreadPool { 12 | public: 13 | ThreadPool(int size); 14 | 15 | ~ThreadPool(); 16 | 17 | void start(); 18 | 19 | void stop(); 20 | 21 | void addTask(std::function cb); 22 | 23 | private: 24 | static void* MainFunction(void* ptr); 25 | 26 | 27 | public: 28 | int m_size {0}; 29 | std::vector m_threads; 30 | std::queue> m_tasks; 31 | 32 | Mutex m_mutex; 33 | pthread_cond_t m_condition; 34 | bool m_is_stop {false}; 35 | }; 36 | 37 | } 38 | 39 | 40 | 41 | #endif -------------------------------------------------------------------------------- /tinyrpc/coroutine/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(HEADERS 2 | coctx.h 3 | coroutine.h 4 | coroutine_hook.h 5 | coroutine_pool.h 6 | memory.h 7 | ) 8 | 9 | install(FILES ${HEADERS} DESTINATION include/tinyrpc/coroutine) -------------------------------------------------------------------------------- /tinyrpc/coroutine/coctx.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_COROUTINE_COCTX_H 2 | #define TINYRPC_COROUTINE_COCTX_H 3 | 4 | namespace tinyrpc{ 5 | 6 | enum { 7 | kRBP = 6, // rbp, bottom of stack 8 | kRDI = 7, // rdi, first para when call function 9 | kRSI = 8, // rsi, second para when call function 10 | kRETAddr = 9, // the next excute cmd address, it will be assigned to rip 11 | kRSP = 13, // rsp, top of stack 12 | }; 13 | 14 | 15 | struct coctx { 16 | void* regs[14]; 17 | }; 18 | 19 | extern "C" { 20 | // save current register's state to fitst coctx, and from second coctx take out register's state to assign register 21 | extern void coctx_swap(coctx *, coctx *) asm("coctx_swap"); 22 | 23 | }; 24 | 25 | } 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /tinyrpc/coroutine/coctx_swap.S: -------------------------------------------------------------------------------- 1 | # copy from https://github.com/Tencent/libco/blob/master/coctx_swap.S 2 | 3 | .globl coctx_swap 4 | coctx_swap: 5 | leaq (%rsp),%rax 6 | movq %rax, 104(%rdi) 7 | movq %rbx, 96(%rdi) 8 | movq %rcx, 88(%rdi) 9 | movq %rdx, 80(%rdi) 10 | movq 0(%rax), %rax 11 | movq %rax, 72(%rdi) 12 | movq %rsi, 64(%rdi) 13 | movq %rdi, 56(%rdi) 14 | movq %rbp, 48(%rdi) 15 | movq %r8, 40(%rdi) 16 | movq %r9, 32(%rdi) 17 | movq %r12, 24(%rdi) 18 | movq %r13, 16(%rdi) 19 | movq %r14, 8(%rdi) 20 | movq %r15, (%rdi) 21 | xorq %rax, %rax 22 | 23 | movq 48(%rsi), %rbp 24 | movq 104(%rsi), %rsp 25 | movq (%rsi), %r15 26 | movq 8(%rsi), %r14 27 | movq 16(%rsi), %r13 28 | movq 24(%rsi), %r12 29 | movq 32(%rsi), %r9 30 | movq 40(%rsi), %r8 31 | movq 56(%rsi), %rdi 32 | movq 80(%rsi), %rdx 33 | movq 88(%rsi), %rcx 34 | movq 96(%rsi), %rbx 35 | leaq 8(%rsp), %rsp 36 | pushq 72(%rsi) 37 | movq 64(%rsi), %rsi 38 | ret 39 | -------------------------------------------------------------------------------- /tinyrpc/coroutine/coroutine.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "tinyrpc/coroutine/coroutine.h" 6 | #include "tinyrpc/comm/log.h" 7 | #include "tinyrpc/comm/run_time.h" 8 | 9 | namespace tinyrpc { 10 | 11 | // main coroutine, every io thread have a main_coroutine 12 | static thread_local Coroutine* t_main_coroutine = NULL; 13 | 14 | // current thread is runing which coroutine 15 | static thread_local Coroutine* t_cur_coroutine = NULL; 16 | 17 | static thread_local RunTime* t_cur_run_time = NULL; 18 | 19 | // static thread_local bool t_enable_coroutine_swap = true; 20 | 21 | static std::atomic_int t_coroutine_count {0}; 22 | 23 | static std::atomic_int t_cur_coroutine_id {1}; 24 | 25 | int getCoroutineIndex() { 26 | return t_cur_coroutine_id; 27 | } 28 | 29 | RunTime* getCurrentRunTime() { 30 | return t_cur_run_time; 31 | } 32 | 33 | void setCurrentRunTime(RunTime* v) { 34 | t_cur_run_time = v; 35 | } 36 | 37 | void CoFunction(Coroutine* co) { 38 | 39 | if (co!= nullptr) { 40 | co->setIsInCoFunc(true); 41 | 42 | // 去执行协程回调函数 43 | co->m_call_back(); 44 | 45 | co->setIsInCoFunc(false); 46 | } 47 | 48 | // here coroutine's callback function finished, that means coroutine's life is over. we should yiled main couroutine 49 | Coroutine::Yield(); 50 | } 51 | 52 | // void Coroutine::SetCoroutineSwapFlag(bool value) { 53 | // t_enable_coroutine_swap = value; 54 | // } 55 | 56 | // bool Coroutine::GetCoroutineSwapFlag() { 57 | // return t_enable_coroutine_swap; 58 | // } 59 | 60 | Coroutine::Coroutine() { 61 | // main coroutine'id is 0 62 | m_cor_id = 0; 63 | t_coroutine_count++; 64 | memset(&m_coctx, 0, sizeof(m_coctx)); 65 | t_cur_coroutine = this; 66 | // DebugLog << "coroutine[" << m_cor_id << "] create"; 67 | } 68 | 69 | Coroutine::Coroutine(int size, char* stack_ptr) : m_stack_size(size), m_stack_sp(stack_ptr) { 70 | assert(stack_ptr); 71 | 72 | if (!t_main_coroutine) { 73 | t_main_coroutine = new Coroutine(); 74 | } 75 | 76 | m_cor_id = t_cur_coroutine_id++; 77 | t_coroutine_count++; 78 | // DebugLog << "coroutine[" << m_cor_id << "] create"; 79 | } 80 | 81 | Coroutine::Coroutine(int size, char* stack_ptr, std::function cb) 82 | : m_stack_size(size), m_stack_sp(stack_ptr) { 83 | 84 | assert(m_stack_sp); 85 | 86 | if (!t_main_coroutine) { 87 | t_main_coroutine = new Coroutine(); 88 | } 89 | 90 | setCallBack(cb); 91 | m_cor_id = t_cur_coroutine_id++; 92 | t_coroutine_count++; 93 | // DebugLog << "coroutine[" << m_cor_id << "] create"; 94 | } 95 | 96 | bool Coroutine::setCallBack(std::function cb) { 97 | 98 | if (this == t_main_coroutine) { 99 | ErrorLog << "main coroutine can't set callback"; 100 | return false; 101 | } 102 | if (m_is_in_cofunc) { 103 | ErrorLog << "this coroutine is in CoFunction"; 104 | return false; 105 | } 106 | 107 | m_call_back = cb; 108 | 109 | // assert(m_stack_sp != nullptr); 110 | 111 | char* top = m_stack_sp + m_stack_size; 112 | // first set 0 to stack 113 | // memset(&top, 0, m_stack_size); 114 | 115 | top = reinterpret_cast((reinterpret_cast(top)) & -16LL); 116 | 117 | memset(&m_coctx, 0, sizeof(m_coctx)); 118 | 119 | m_coctx.regs[kRSP] = top; 120 | m_coctx.regs[kRBP] = top; 121 | m_coctx.regs[kRETAddr] = reinterpret_cast(CoFunction); 122 | m_coctx.regs[kRDI] = reinterpret_cast(this); 123 | 124 | m_can_resume = true; 125 | 126 | return true; 127 | 128 | } 129 | 130 | Coroutine::~Coroutine() { 131 | t_coroutine_count--; 132 | // DebugLog << "coroutine[" << m_cor_id << "] die"; 133 | } 134 | 135 | Coroutine* Coroutine::GetCurrentCoroutine() { 136 | if (t_cur_coroutine == nullptr) { 137 | t_main_coroutine = new Coroutine(); 138 | t_cur_coroutine = t_main_coroutine; 139 | } 140 | return t_cur_coroutine; 141 | } 142 | 143 | Coroutine* Coroutine::GetMainCoroutine() { 144 | if (t_main_coroutine) { 145 | return t_main_coroutine; 146 | } 147 | t_main_coroutine = new Coroutine(); 148 | return t_main_coroutine; 149 | } 150 | 151 | bool Coroutine::IsMainCoroutine() { 152 | if (t_main_coroutine == nullptr || t_cur_coroutine == t_main_coroutine) { 153 | return true; 154 | } 155 | return false; 156 | } 157 | 158 | /******** 159 | form target coroutine back to main coroutine 160 | ********/ 161 | void Coroutine::Yield() { 162 | // if (!t_enable_coroutine_swap) { 163 | // ErrorLog << "can't yield, because disable coroutine swap"; 164 | // return; 165 | // } 166 | if (t_main_coroutine == nullptr) { 167 | ErrorLog << "main coroutine is nullptr"; 168 | return; 169 | } 170 | 171 | if (t_cur_coroutine == t_main_coroutine) { 172 | ErrorLog << "current coroutine is main coroutine"; 173 | return; 174 | } 175 | Coroutine* co = t_cur_coroutine; 176 | t_cur_coroutine = t_main_coroutine; 177 | t_cur_run_time = NULL; 178 | coctx_swap(&(co->m_coctx), &(t_main_coroutine->m_coctx)); 179 | // DebugLog << "swap back"; 180 | } 181 | 182 | /******** 183 | form main coroutine switch to target coroutine 184 | ********/ 185 | void Coroutine::Resume(Coroutine* co) { 186 | if (t_cur_coroutine != t_main_coroutine) { 187 | ErrorLog << "swap error, current coroutine must be main coroutine"; 188 | return; 189 | } 190 | 191 | if (!t_main_coroutine) { 192 | ErrorLog << "main coroutine is nullptr"; 193 | return; 194 | } 195 | if (!co || !co->m_can_resume) { 196 | ErrorLog << "pending coroutine is nullptr or can_resume is false"; 197 | return; 198 | } 199 | 200 | if (t_cur_coroutine == co) { 201 | DebugLog << "current coroutine is pending cor, need't swap"; 202 | return; 203 | } 204 | 205 | t_cur_coroutine = co; 206 | t_cur_run_time = co->getRunTime(); 207 | 208 | coctx_swap(&(t_main_coroutine->m_coctx), &(co->m_coctx)); 209 | // DebugLog << "swap back"; 210 | 211 | } 212 | 213 | } 214 | -------------------------------------------------------------------------------- /tinyrpc/coroutine/coroutine.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_COROUTINE_COROUTINE_H 2 | #define TINYRPC_COROUTINE_COROUTINE_H 3 | 4 | #include 5 | #include 6 | #include "tinyrpc/coroutine/coctx.h" 7 | #include "tinyrpc/comm/run_time.h" 8 | 9 | namespace tinyrpc { 10 | 11 | int getCoroutineIndex(); 12 | 13 | RunTime* getCurrentRunTime(); 14 | 15 | void setCurrentRunTime(RunTime* v); 16 | 17 | class Coroutine { 18 | 19 | public: 20 | typedef std::shared_ptr ptr; 21 | 22 | private: 23 | 24 | Coroutine(); 25 | 26 | public: 27 | 28 | Coroutine(int size, char* stack_ptr); 29 | 30 | Coroutine(int size, char* stack_ptr, std::function cb); 31 | 32 | ~Coroutine(); 33 | 34 | bool setCallBack(std::function cb); 35 | 36 | int getCorId() const { 37 | return m_cor_id; 38 | } 39 | 40 | void setIsInCoFunc(const bool v) { 41 | m_is_in_cofunc = v; 42 | } 43 | 44 | bool getIsInCoFunc() const { 45 | return m_is_in_cofunc; 46 | } 47 | 48 | std::string getMsgNo() { 49 | return m_msg_no; 50 | } 51 | 52 | RunTime* getRunTime() { 53 | return &m_run_time; 54 | } 55 | 56 | void setMsgNo(const std::string& msg_no) { 57 | m_msg_no = msg_no; 58 | } 59 | 60 | void setIndex(int index) { 61 | m_index = index; 62 | } 63 | 64 | int getIndex() { 65 | return m_index; 66 | } 67 | 68 | char* getStackPtr() { 69 | return m_stack_sp; 70 | } 71 | 72 | int getStackSize() { 73 | return m_stack_size; 74 | } 75 | 76 | void setCanResume(bool v) { 77 | m_can_resume = v; 78 | } 79 | 80 | public: 81 | static void Yield(); 82 | 83 | static void Resume(Coroutine* cor); 84 | 85 | static Coroutine* GetCurrentCoroutine(); 86 | 87 | static Coroutine* GetMainCoroutine(); 88 | 89 | static bool IsMainCoroutine(); 90 | 91 | // static void SetCoroutineSwapFlag(bool value); 92 | 93 | // static bool GetCoroutineSwapFlag(); 94 | 95 | private: 96 | int m_cor_id {0}; // coroutine' id 97 | coctx m_coctx; // coroutine regs 98 | int m_stack_size {0}; // size of stack memory space 99 | char* m_stack_sp {NULL}; // coroutine's stack memory space, you can malloc or mmap get some mermory to init this value 100 | bool m_is_in_cofunc {false}; // true when call CoFunction, false when CoFunction finished 101 | std::string m_msg_no; 102 | RunTime m_run_time; 103 | 104 | bool m_can_resume {true}; 105 | 106 | int m_index {-1}; // index in coroutine pool 107 | 108 | 109 | public: 110 | 111 | std::function m_call_back; 112 | 113 | }; 114 | 115 | } 116 | 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /tinyrpc/coroutine/coroutine_hook.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_COROUTINE_COUROUTINE_HOOK_H 2 | #define TINYRPC_COROUTINE_COUROUTINE_HOOK_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | typedef ssize_t (*read_fun_ptr_t)(int fd, void *buf, size_t count); 9 | 10 | typedef ssize_t (*write_fun_ptr_t)(int fd, const void *buf, size_t count); 11 | 12 | typedef int (*connect_fun_ptr_t)(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 13 | 14 | typedef int (*accept_fun_ptr_t)(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 15 | 16 | typedef int (*socket_fun_ptr_t)(int domain, int type, int protocol); 17 | 18 | typedef int (*sleep_fun_ptr_t)(unsigned int seconds); 19 | 20 | 21 | namespace tinyrpc { 22 | 23 | int accept_hook(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 24 | 25 | ssize_t read_hook(int fd, void *buf, size_t count); 26 | 27 | ssize_t write_hook(int fd, const void *buf, size_t count); 28 | 29 | int connect_hook(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 30 | 31 | unsigned int sleep_hook(unsigned int seconds); 32 | 33 | void SetHook(bool); 34 | 35 | } 36 | 37 | extern "C" { 38 | 39 | int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 40 | 41 | ssize_t read(int fd, void *buf, size_t count); 42 | 43 | ssize_t write(int fd, const void *buf, size_t count); 44 | 45 | int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 46 | 47 | unsigned int sleep(unsigned int seconds); 48 | 49 | } 50 | 51 | #endif -------------------------------------------------------------------------------- /tinyrpc/coroutine/coroutine_pool.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "tinyrpc/comm/config.h" 4 | #include "tinyrpc/comm/log.h" 5 | #include "tinyrpc/coroutine/coroutine_pool.h" 6 | #include "tinyrpc/coroutine/coroutine.h" 7 | #include "tinyrpc/net/mutex.h" 8 | 9 | 10 | namespace tinyrpc { 11 | 12 | extern tinyrpc::Config::ptr gRpcConfig; 13 | 14 | static CoroutinePool* t_coroutine_container_ptr = nullptr; 15 | 16 | CoroutinePool* GetCoroutinePool() { 17 | if (!t_coroutine_container_ptr) { 18 | t_coroutine_container_ptr = new CoroutinePool(gRpcConfig->m_cor_pool_size, gRpcConfig->m_cor_stack_size); 19 | } 20 | return t_coroutine_container_ptr; 21 | } 22 | 23 | 24 | CoroutinePool::CoroutinePool(int pool_size, int stack_size /*= 1024 * 128 B*/) : m_pool_size(pool_size), m_stack_size(stack_size) { 25 | // set main coroutine first 26 | Coroutine::GetCurrentCoroutine(); 27 | 28 | m_memory_pool.push_back(std::make_shared(stack_size, pool_size)); 29 | 30 | Memory::ptr tmp = m_memory_pool[0]; 31 | 32 | for (int i = 0; i < pool_size; ++i) { 33 | Coroutine::ptr cor = std::make_shared(stack_size, tmp->getBlock()); 34 | cor->setIndex(i); 35 | m_free_cors.push_back(std::make_pair(cor, false)); 36 | } 37 | 38 | } 39 | 40 | CoroutinePool::~CoroutinePool() { 41 | 42 | } 43 | 44 | Coroutine::ptr CoroutinePool::getCoroutineInstanse() { 45 | 46 | // from 0 to find first free coroutine which: 1. it.second = false, 2. getIsInCoFunc() is false 47 | // try our best to reuse used corroutine, and try our best not to choose unused coroutine 48 | // beacuse used couroutine which used has already write bytes into physical memory, 49 | // but unused coroutine no physical memory yet. we just call mmap get virtual address, but not write yet. 50 | // so linux will alloc physical when we realy write, that casuse page fault interrupt 51 | 52 | Mutex::Lock lock(m_mutex); 53 | for (int i = 0; i < m_pool_size; ++i) { 54 | if (!m_free_cors[i].first->getIsInCoFunc() && !m_free_cors[i].second) { 55 | m_free_cors[i].second = true; 56 | Coroutine::ptr cor = m_free_cors[i].first; 57 | lock.unlock(); 58 | return cor; 59 | } 60 | } 61 | 62 | for (size_t i = 1; i < m_memory_pool.size(); ++i) { 63 | char* tmp = m_memory_pool[i]->getBlock(); 64 | if(tmp) { 65 | Coroutine::ptr cor = std::make_shared(m_stack_size, tmp); 66 | return cor; 67 | } 68 | } 69 | m_memory_pool.push_back(std::make_shared(m_stack_size, m_pool_size)); 70 | return std::make_shared(m_stack_size, m_memory_pool[m_memory_pool.size() - 1]->getBlock()); 71 | } 72 | 73 | void CoroutinePool::returnCoroutine(Coroutine::ptr cor) { 74 | int i = cor->getIndex(); 75 | if (i >= 0 && i < m_pool_size) { 76 | m_free_cors[i].second = false; 77 | } else { 78 | for (size_t i = 1; i < m_memory_pool.size(); ++i) { 79 | if (m_memory_pool[i]->hasBlock(cor->getStackPtr())) { 80 | m_memory_pool[i]->backBlock(cor->getStackPtr()); 81 | } 82 | } 83 | } 84 | } 85 | 86 | 87 | 88 | } -------------------------------------------------------------------------------- /tinyrpc/coroutine/coroutine_pool.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_COROUTINE_COUROUTINE_POOL_H 2 | #define TINYRPC_COROUTINE_COUROUTINE_POOL_H 3 | 4 | #include 5 | #include "tinyrpc/coroutine/coroutine.h" 6 | #include "tinyrpc/net/mutex.h" 7 | #include "tinyrpc/coroutine/memory.h" 8 | 9 | namespace tinyrpc { 10 | 11 | class CoroutinePool { 12 | 13 | public: 14 | CoroutinePool(int pool_size, int stack_size = 1024 * 128); 15 | ~CoroutinePool(); 16 | 17 | Coroutine::ptr getCoroutineInstanse(); 18 | 19 | void returnCoroutine(Coroutine::ptr cor); 20 | 21 | private: 22 | int m_pool_size {0}; 23 | int m_stack_size {0}; 24 | 25 | // first--ptr of cor 26 | // second 27 | // false -- can be dispatched 28 | // true -- can't be dispatched 29 | std::vector> m_free_cors; 30 | 31 | Mutex m_mutex; 32 | 33 | std::vector m_memory_pool; 34 | }; 35 | 36 | 37 | CoroutinePool* GetCoroutinePool(); 38 | 39 | } 40 | 41 | 42 | #endif -------------------------------------------------------------------------------- /tinyrpc/coroutine/memory.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "tinyrpc/comm/log.h" 6 | #include "tinyrpc/coroutine/memory.h" 7 | 8 | namespace tinyrpc { 9 | 10 | Memory::Memory(int block_size, int block_count) : m_block_size(block_size), m_block_count(block_count) { 11 | m_size = m_block_count * m_block_size; 12 | m_start = (char*)malloc(m_size); 13 | assert(m_start != (void*)-1); 14 | InfoLog << "succ mmap " << m_size << " bytes memory"; 15 | m_end = m_start + m_size - 1; 16 | m_blocks.resize(m_block_count); 17 | for (size_t i = 0; i < m_blocks.size(); ++i) { 18 | m_blocks[i] = false; 19 | } 20 | m_ref_counts = 0; 21 | } 22 | 23 | // void Memory::free() { 24 | // if (!m_start || m_start == (void*)-1) { 25 | // return; 26 | // } 27 | // int rt = free(m_start); 28 | // if (rt != 0) { 29 | // ErrorLog << "munmap error, error=" << strerror(errno); 30 | // } 31 | // InfoLog << "~succ free munmap " << m_size << " bytes memory"; 32 | // m_start = NULL; 33 | // m_ref_counts = 0; 34 | // } 35 | 36 | Memory::~Memory() { 37 | if (!m_start || m_start == (void*)-1) { 38 | return; 39 | } 40 | free(m_start); 41 | InfoLog << "~succ free munmap " << m_size << " bytes memory"; 42 | m_start = NULL; 43 | m_ref_counts = 0; 44 | } 45 | 46 | char* Memory::getStart() { 47 | return m_start; 48 | } 49 | 50 | char* Memory::getEnd() { 51 | return m_end; 52 | } 53 | 54 | int Memory::getRefCount() { 55 | return m_ref_counts; 56 | } 57 | 58 | char* Memory::getBlock() { 59 | int t = -1; 60 | Mutex::Lock lock(m_mutex); 61 | for (size_t i = 0; i < m_blocks.size(); ++i) { 62 | if (m_blocks[i] == false) { 63 | m_blocks[i] = true; 64 | t = i; 65 | break; 66 | } 67 | } 68 | lock.unlock(); 69 | if (t == -1) { 70 | return NULL; 71 | } 72 | m_ref_counts++; 73 | return m_start + (t * m_block_size); 74 | } 75 | 76 | void Memory::backBlock(char* s) { 77 | if (s > m_end || s < m_start) { 78 | ErrorLog << "error, this block is not belong to this Memory"; 79 | return; 80 | } 81 | int i = (s - m_start) / m_block_size; 82 | Mutex::Lock lock(m_mutex); 83 | m_blocks[i] = false; 84 | lock.unlock(); 85 | m_ref_counts--; 86 | } 87 | 88 | bool Memory::hasBlock(char* s) { 89 | return ((s >= m_start) && (s <= m_end)); 90 | } 91 | 92 | 93 | } 94 | -------------------------------------------------------------------------------- /tinyrpc/coroutine/memory.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_COROUTINE_MEMORY_H 2 | #define TINYRPC_COROUTINE_MEMORY_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "tinyrpc/net/mutex.h" 8 | 9 | namespace tinyrpc { 10 | 11 | class Memory { 12 | public: 13 | typedef std::shared_ptr ptr; 14 | 15 | Memory(int block_size, int block_count); 16 | 17 | // void free(); 18 | 19 | ~Memory(); 20 | 21 | int getRefCount(); 22 | 23 | char* getStart(); 24 | 25 | char* getEnd(); 26 | 27 | char* getBlock(); 28 | 29 | void backBlock(char* s); 30 | 31 | bool hasBlock(char* s); 32 | 33 | private: 34 | int m_block_size {0}; 35 | int m_block_count {0}; 36 | 37 | int m_size {0}; 38 | char* m_start {NULL}; 39 | char* m_end {NULL}; 40 | 41 | std::atomic m_ref_counts {0}; 42 | std::vector m_blocks; 43 | Mutex m_mutex; 44 | 45 | }; 46 | 47 | } 48 | 49 | #endif -------------------------------------------------------------------------------- /tinyrpc/net/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(HEADERS 2 | abstract_codec.h 3 | byte.h 4 | mutex.h 5 | abstract_data.h 6 | fd_event.h 7 | net_address.h 8 | timer.h 9 | abstract_dispatcher.h 10 | reactor.h 11 | ) 12 | 13 | install(FILES ${HEADERS} DESTINATION include/tinyrpc/net) -------------------------------------------------------------------------------- /tinyrpc/net/abstract_codec.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_CODEC_H 2 | #define TINYRPC_NET_CODEC_H 3 | 4 | #include 5 | #include 6 | #include "tcp/tcp_buffer.h" 7 | #include "abstract_data.h" 8 | 9 | 10 | namespace tinyrpc { 11 | 12 | enum ProtocalType { 13 | TinyPb_Protocal = 1, 14 | Http_Protocal = 2 15 | }; 16 | 17 | class AbstractCodeC { 18 | 19 | public: 20 | typedef std::shared_ptr ptr; 21 | 22 | AbstractCodeC() {} 23 | 24 | virtual ~AbstractCodeC() {} 25 | 26 | virtual void encode(TcpBuffer* buf, AbstractData* data) = 0; 27 | 28 | virtual void decode(TcpBuffer* buf, AbstractData* data) = 0; 29 | 30 | virtual ProtocalType getProtocalType() = 0; 31 | 32 | }; 33 | 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /tinyrpc/net/abstract_data.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_ABSTRACT_DATA_H 2 | #define TINYRPC_NET_ABSTRACT_DATA_H 3 | 4 | namespace tinyrpc { 5 | 6 | class AbstractData { 7 | public: 8 | AbstractData() = default; 9 | virtual ~AbstractData() {}; 10 | 11 | bool decode_succ {false}; 12 | bool encode_succ {false}; 13 | }; 14 | 15 | 16 | } 17 | 18 | #endif -------------------------------------------------------------------------------- /tinyrpc/net/abstract_dispatcher.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_ABSTRACT_DISPATCHER_H 2 | #define TINYRPC_NET_ABSTRACT_DISPATCHER_H 3 | 4 | #include 5 | #include 6 | #include "tinyrpc/net/abstract_data.h" 7 | #include "tinyrpc/net/tcp/tcp_connection.h" 8 | 9 | namespace tinyrpc { 10 | 11 | class TcpConnection; 12 | 13 | class AbstractDispatcher { 14 | public: 15 | typedef std::shared_ptr ptr; 16 | 17 | AbstractDispatcher() {} 18 | 19 | virtual ~AbstractDispatcher() {} 20 | 21 | virtual void dispatch(AbstractData* data, TcpConnection* conn) = 0; 22 | 23 | }; 24 | 25 | } 26 | 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /tinyrpc/net/byte.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_BYTE_H 2 | #define TINYRPC_NET_BYTE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace tinyrpc { 9 | 10 | int32_t getInt32FromNetByte(const char* buf) { 11 | int32_t tmp; 12 | memcpy(&tmp, buf, sizeof(tmp)); 13 | return ntohl(tmp); 14 | } 15 | 16 | 17 | 18 | } 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /tinyrpc/net/fd_event.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "fd_event.h" 4 | 5 | namespace tinyrpc { 6 | 7 | static FdEventContainer* g_FdContainer = nullptr; 8 | 9 | FdEvent::FdEvent(tinyrpc::Reactor* reactor, int fd/*=-1*/) : m_fd(fd), m_reactor(reactor) { 10 | if (reactor == nullptr) { 11 | ErrorLog << "create reactor first"; 12 | } 13 | // assert(reactor != nullptr); 14 | } 15 | 16 | FdEvent::FdEvent(int fd) : m_fd(fd) { 17 | 18 | } 19 | 20 | FdEvent::~FdEvent() {} 21 | 22 | void FdEvent::handleEvent(int flag) { 23 | 24 | if (flag == READ) { 25 | m_read_callback(); 26 | } else if (flag == WRITE) { 27 | m_write_callback(); 28 | } else { 29 | ErrorLog << "error flag"; 30 | } 31 | 32 | } 33 | 34 | void FdEvent::setCallBack(IOEvent flag, std::function cb) { 35 | if (flag == READ) { 36 | m_read_callback = cb; 37 | } else if (flag == WRITE) { 38 | m_write_callback = cb; 39 | } else { 40 | ErrorLog << "error flag"; 41 | } 42 | } 43 | 44 | std::function FdEvent::getCallBack(IOEvent flag) const { 45 | if (flag == READ) { 46 | return m_read_callback; 47 | } else if (flag == WRITE) { 48 | return m_write_callback; 49 | } 50 | return nullptr; 51 | } 52 | 53 | void FdEvent::addListenEvents(IOEvent event) { 54 | if (m_listen_events & event) { 55 | DebugLog << "already has this event, skip"; 56 | return; 57 | } 58 | m_listen_events |= event; 59 | updateToReactor(); 60 | // DebugLog << "add succ"; 61 | } 62 | 63 | void FdEvent::delListenEvents(IOEvent event) { 64 | if (m_listen_events & event) { 65 | 66 | DebugLog << "delete succ"; 67 | m_listen_events &= ~event; 68 | updateToReactor(); 69 | return; 70 | } 71 | DebugLog << "this event not exist, skip"; 72 | 73 | } 74 | 75 | void FdEvent::updateToReactor() { 76 | 77 | epoll_event event; 78 | event.events = m_listen_events; 79 | event.data.ptr = this; 80 | // DebugLog << "reactor = " << m_reactor << "log m_tid =" << m_reactor->getTid(); 81 | if (!m_reactor) { 82 | m_reactor = tinyrpc::Reactor::GetReactor(); 83 | } 84 | 85 | m_reactor->addEvent(m_fd, event); 86 | } 87 | 88 | void FdEvent::unregisterFromReactor () { 89 | if (!m_reactor) { 90 | m_reactor = tinyrpc::Reactor::GetReactor(); 91 | } 92 | m_reactor->delEvent(m_fd); 93 | m_listen_events = 0; 94 | m_read_callback = nullptr; 95 | m_write_callback = nullptr; 96 | } 97 | 98 | int FdEvent::getFd() const { 99 | return m_fd; 100 | } 101 | 102 | void FdEvent::setFd(const int fd) { 103 | m_fd = fd; 104 | } 105 | 106 | int FdEvent::getListenEvents() const { 107 | return m_listen_events; 108 | } 109 | 110 | Reactor* FdEvent::getReactor() const { 111 | return m_reactor; 112 | } 113 | 114 | void FdEvent::setReactor(Reactor* r) { 115 | m_reactor = r; 116 | } 117 | 118 | void FdEvent::setNonBlock() { 119 | if (m_fd == -1) { 120 | ErrorLog << "error, fd=-1"; 121 | return; 122 | } 123 | 124 | int flag = fcntl(m_fd, F_GETFL, 0); 125 | if (flag & O_NONBLOCK) { 126 | DebugLog << "fd already set o_nonblock"; 127 | return; 128 | } 129 | 130 | fcntl(m_fd, F_SETFL, flag | O_NONBLOCK); 131 | flag = fcntl(m_fd, F_GETFL, 0); 132 | if (flag & O_NONBLOCK) { 133 | DebugLog << "succ set o_nonblock"; 134 | } else { 135 | ErrorLog << "set o_nonblock error"; 136 | } 137 | 138 | } 139 | 140 | bool FdEvent::isNonBlock() { 141 | if (m_fd == -1) { 142 | ErrorLog << "error, fd=-1"; 143 | return false; 144 | } 145 | int flag = fcntl(m_fd, F_GETFL, 0); 146 | return (flag & O_NONBLOCK); 147 | 148 | } 149 | 150 | void FdEvent::setCoroutine(Coroutine* cor) { 151 | m_coroutine = cor; 152 | } 153 | 154 | void FdEvent::clearCoroutine() { 155 | m_coroutine = nullptr; 156 | } 157 | 158 | Coroutine* FdEvent::getCoroutine() { 159 | return m_coroutine; 160 | } 161 | 162 | 163 | 164 | FdEvent::ptr FdEventContainer::getFdEvent(int fd) { 165 | 166 | RWMutex::ReadLock rlock(m_mutex); 167 | if (fd < static_cast(m_fds.size())) { 168 | tinyrpc::FdEvent::ptr re = m_fds[fd]; 169 | rlock.unlock(); 170 | return re; 171 | } 172 | rlock.unlock(); 173 | 174 | RWMutex::WriteLock wlock(m_mutex); 175 | int n = (int)(fd * 1.5); 176 | for (int i = m_fds.size(); i < n; ++i) { 177 | m_fds.push_back(std::make_shared(i)); 178 | } 179 | tinyrpc::FdEvent::ptr re = m_fds[fd]; 180 | wlock.unlock(); 181 | return re; 182 | 183 | } 184 | 185 | FdEventContainer::FdEventContainer(int size) { 186 | for(int i = 0; i < size; ++i) { 187 | m_fds.push_back(std::make_shared(i)); 188 | } 189 | 190 | } 191 | 192 | FdEventContainer* FdEventContainer::GetFdContainer() { 193 | if (g_FdContainer == nullptr) { 194 | g_FdContainer = new FdEventContainer(1000); 195 | } 196 | return g_FdContainer; 197 | } 198 | 199 | 200 | } 201 | -------------------------------------------------------------------------------- /tinyrpc/net/fd_event.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_FD_EVNET_H 2 | #define TINYRPC_NET_FD_EVNET_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "reactor.h" 10 | #include "tinyrpc/comm/log.h" 11 | #include "tinyrpc/coroutine/coroutine.h" 12 | #include "mutex.h" 13 | 14 | namespace tinyrpc { 15 | 16 | class Reactor; 17 | 18 | enum IOEvent { 19 | READ = EPOLLIN, 20 | WRITE = EPOLLOUT, 21 | ETModel = EPOLLET, 22 | }; 23 | 24 | class FdEvent : public std::enable_shared_from_this { 25 | public: 26 | 27 | typedef std::shared_ptr ptr; 28 | 29 | FdEvent(tinyrpc::Reactor* reactor, int fd = -1); 30 | 31 | FdEvent(int fd); 32 | 33 | virtual ~FdEvent(); 34 | 35 | void handleEvent(int flag); 36 | 37 | void setCallBack(IOEvent flag, std::function cb); 38 | 39 | std::function getCallBack(IOEvent flag) const; 40 | 41 | void addListenEvents(IOEvent event); 42 | 43 | void delListenEvents(IOEvent event); 44 | 45 | void updateToReactor(); 46 | 47 | void unregisterFromReactor (); 48 | 49 | int getFd() const; 50 | 51 | void setFd(const int fd); 52 | 53 | int getListenEvents() const; 54 | 55 | Reactor* getReactor() const; 56 | 57 | void setReactor(Reactor* r); 58 | 59 | void setNonBlock(); 60 | 61 | bool isNonBlock(); 62 | 63 | void setCoroutine(Coroutine* cor); 64 | 65 | Coroutine* getCoroutine(); 66 | 67 | void clearCoroutine(); 68 | 69 | public: 70 | Mutex m_mutex; 71 | 72 | protected: 73 | int m_fd {-1}; 74 | std::function m_read_callback; 75 | std::function m_write_callback; 76 | 77 | int m_listen_events {0}; 78 | 79 | Reactor* m_reactor {nullptr}; 80 | 81 | Coroutine* m_coroutine {nullptr}; 82 | 83 | }; 84 | 85 | 86 | class FdEventContainer { 87 | 88 | public: 89 | FdEventContainer(int size); 90 | 91 | FdEvent::ptr getFdEvent(int fd); 92 | 93 | public: 94 | static FdEventContainer* GetFdContainer(); 95 | 96 | private: 97 | RWMutex m_mutex; 98 | std::vector m_fds; 99 | 100 | }; 101 | 102 | } 103 | 104 | #endif 105 | -------------------------------------------------------------------------------- /tinyrpc/net/http/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(HEADERS 2 | http_codec.h 3 | http_dispatcher.h 4 | http_response.h 5 | http_define.h 6 | http_request.h 7 | http_servlet.h 8 | ) 9 | 10 | install(FILES ${HEADERS} DESTINATION include/tinyrpc/net/http) -------------------------------------------------------------------------------- /tinyrpc/net/http/http_codec.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "http_codec.h" 4 | #include "tinyrpc/comm/log.h" 5 | #include "tinyrpc/comm/string_util.h" 6 | #include "tinyrpc/net/abstract_data.h" 7 | #include "tinyrpc/net/abstract_codec.h" 8 | #include "tinyrpc/net/http/http_request.h" 9 | #include "tinyrpc/net/http/http_response.h" 10 | 11 | namespace tinyrpc { 12 | 13 | 14 | HttpCodeC::HttpCodeC() { 15 | 16 | } 17 | 18 | HttpCodeC::~HttpCodeC() { 19 | 20 | } 21 | 22 | 23 | 24 | void HttpCodeC::encode(TcpBuffer* buf, AbstractData* data) { 25 | DebugLog << "test encode"; 26 | HttpResponse* response = dynamic_cast(data); 27 | response->encode_succ = false; 28 | 29 | std::stringstream ss; 30 | ss << response->m_response_version << " " << response->m_response_code << " " 31 | << response->m_response_info << "\r\n" << response->m_response_header.toHttpString() 32 | << "\r\n" << response->m_response_body; 33 | std::string http_res = ss.str(); 34 | DebugLog << "encode http response is: " << http_res; 35 | 36 | buf->writeToBuffer(http_res.c_str(), http_res.length()); 37 | DebugLog << "succ encode and write to buffer, writeindex=" << buf->writeIndex(); 38 | response->encode_succ = true; 39 | DebugLog << "test encode end"; 40 | } 41 | 42 | void HttpCodeC::decode(TcpBuffer* buf, AbstractData* data) { 43 | DebugLog << "test http decode start"; 44 | std::string strs = ""; 45 | if (!buf || !data) { 46 | ErrorLog << "decode error! buf or data nullptr"; 47 | return; 48 | } 49 | HttpRequest* request = dynamic_cast(data); 50 | if (!request) { 51 | ErrorLog << "not httprequest type"; 52 | return; 53 | } 54 | 55 | strs = buf->getBufferString(); 56 | 57 | bool is_parse_request_line = false; 58 | bool is_parse_request_header = false; 59 | bool is_parse_request_content = false; 60 | // bool is_parse_succ = false; 61 | int read_size = 0; 62 | std::string tmp(strs); 63 | DebugLog << "pending to parse str:" << tmp << ", total size =" << tmp.size(); 64 | int len = tmp.length(); 65 | while (1) { 66 | if (!is_parse_request_line) { 67 | size_t i = tmp.find(g_CRLF); 68 | if (i == tmp.npos) { 69 | DebugLog << "not found CRLF in buffer"; 70 | return; 71 | } 72 | if (i == tmp.length() - 2) { 73 | DebugLog << "need to read more data"; 74 | break; 75 | } 76 | is_parse_request_line = parseHttpRequestLine(request, tmp.substr(0, i)); 77 | if (!is_parse_request_line) { 78 | return; 79 | } 80 | tmp = tmp.substr(i + 2, len - 2 - i); 81 | len = tmp.length(); 82 | read_size = read_size + i + 2; 83 | } 84 | 85 | if (!is_parse_request_header) { 86 | size_t j = tmp.find(g_CRLF_DOUBLE); 87 | if (j == tmp.npos) { 88 | DebugLog << "not found CRLF CRLF in buffer"; 89 | return; 90 | } 91 | // if (j == tmp.length() - 4) { 92 | // DebugLog << "need to read more data"; 93 | // goto parse_error; 94 | // } 95 | is_parse_request_header = parseHttpRequestHeader(request, tmp.substr(0, j)); 96 | if (!is_parse_request_header) { 97 | return; 98 | } 99 | tmp = tmp.substr(j + 4, len - 4 - j); 100 | len = tmp.length(); 101 | read_size = read_size + j + 4; 102 | } 103 | if (!is_parse_request_content) { 104 | int content_len = std::atoi(request->m_requeset_header.m_maps["Content-Length"].c_str()); 105 | if ((int)strs.length() - read_size < content_len) { 106 | DebugLog << "need to read more data"; 107 | return; 108 | } 109 | if (request->m_request_method == POST && content_len != 0) { 110 | is_parse_request_content = parseHttpRequestContent(request, tmp.substr(0, content_len)); 111 | if (!is_parse_request_content) { 112 | return; 113 | } 114 | read_size = read_size + content_len; 115 | } else { 116 | is_parse_request_content = true; 117 | } 118 | 119 | } 120 | if (is_parse_request_line && is_parse_request_header && is_parse_request_header) { 121 | DebugLog << "parse http request success, read size is " << read_size << " bytes"; 122 | buf->recycleRead(read_size); 123 | break; 124 | } 125 | } 126 | 127 | request->decode_succ = true; 128 | data = request; 129 | 130 | DebugLog << "test http decode end"; 131 | } 132 | 133 | 134 | bool HttpCodeC::parseHttpRequestLine(HttpRequest* requset, const std::string& tmp) { 135 | size_t s1 = tmp.find_first_of(" "); 136 | size_t s2 = tmp.find_last_of(" "); 137 | 138 | if (s1 == tmp.npos || s2 == tmp.npos || s1 == s2) { 139 | ErrorLog << "error read Http Requser Line, space is not 2"; 140 | return false; 141 | } 142 | std::string method = tmp.substr(0, s1); 143 | std::transform(method.begin(), method.end(), method.begin(), toupper); 144 | if (method == "GET") { 145 | requset->m_request_method = HttpMethod::GET; 146 | } else if (method == "POST") { 147 | requset->m_request_method = HttpMethod::POST; 148 | } else { 149 | ErrorLog << "parse http request request line error, not support http method:" << method; 150 | return false; 151 | } 152 | 153 | std::string version = tmp.substr(s2 + 1, tmp.length() - s2 - 1); 154 | std::transform(version.begin(), version.end(), version.begin(), toupper); 155 | if (version != "HTTP/1.1" && version != "HTTP/1.0") { 156 | ErrorLog << "parse http request request line error, not support http version:" << version; 157 | return false; 158 | } 159 | requset->m_request_version = version; 160 | 161 | 162 | std::string url = tmp.substr(s1 + 1, s2 - s1 - 1); 163 | size_t j = url.find("://"); 164 | 165 | if (j != url.npos && j + 3 >= url.length()) { 166 | ErrorLog << "parse http request request line error, bad url:" << url; 167 | return false; 168 | } 169 | int l = 0; 170 | if (j == url.npos) { 171 | DebugLog << "url only have path, url is" << url; 172 | } else { 173 | url = url.substr(j + 3, s2 - s1 - j - 4); 174 | DebugLog << "delete http prefix, url = " << url; 175 | j = url.find_first_of("/"); 176 | l = url.length(); 177 | if (j == url.npos || j == url.length() - 1) { 178 | DebugLog << "http request root path, and query is empty"; 179 | return true; 180 | } 181 | url = url.substr(j + 1, l - j - 1); 182 | } 183 | 184 | l = url.length(); 185 | j = url.find_first_of("?"); 186 | if (j == url.npos) { 187 | requset->m_request_path = url; 188 | DebugLog << "http request path:" << requset->m_request_path << "and query is empty"; 189 | return true; 190 | } 191 | requset->m_request_path = url.substr(0, j); 192 | requset->m_request_query = url.substr(j + 1, l - j - 1); 193 | DebugLog << "http request path:" << requset->m_request_path << ", and query:" << requset->m_request_query; 194 | StringUtil::SplitStrToMap(requset->m_request_query, "&", "=", requset->m_query_maps); 195 | return true; 196 | 197 | } 198 | 199 | bool HttpCodeC::parseHttpRequestHeader(HttpRequest* requset, const std::string& str) { 200 | if (str.empty() || str.length() < 4 || str == "\r\n\r\n") { 201 | return true; 202 | } 203 | std::string tmp = str; 204 | StringUtil::SplitStrToMap(tmp, "\r\n", ":", requset->m_requeset_header.m_maps); 205 | return true; 206 | } 207 | bool HttpCodeC::parseHttpRequestContent(HttpRequest* requset, const std::string& str) { 208 | if (str.empty()) { 209 | return true; 210 | } 211 | requset->m_request_body = str; 212 | return true; 213 | } 214 | 215 | 216 | ProtocalType HttpCodeC::getProtocalType() { 217 | return Http_Protocal; 218 | } 219 | 220 | } 221 | -------------------------------------------------------------------------------- /tinyrpc/net/http/http_codec.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_HTTP_HTTP_CODEC_H 2 | #define TINYRPC_NET_HTTP_HTTP_CODEC_H 3 | 4 | #include 5 | #include 6 | #include "tinyrpc/net/abstract_data.h" 7 | #include "tinyrpc/net/abstract_codec.h" 8 | #include "tinyrpc/net/http/http_request.h" 9 | 10 | namespace tinyrpc { 11 | 12 | class HttpCodeC : public AbstractCodeC { 13 | public: 14 | HttpCodeC(); 15 | 16 | ~HttpCodeC(); 17 | 18 | void encode(TcpBuffer* buf, AbstractData* data); 19 | 20 | void decode(TcpBuffer* buf, AbstractData* data); 21 | 22 | ProtocalType getProtocalType(); 23 | 24 | private: 25 | bool parseHttpRequestLine(HttpRequest* requset, const std::string& tmp); 26 | bool parseHttpRequestHeader(HttpRequest* requset, const std::string& tmp); 27 | bool parseHttpRequestContent(HttpRequest* requset, const std::string& tmp); 28 | }; 29 | 30 | } 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /tinyrpc/net/http/http_define.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "tinyrpc/net/http/http_define.h" 4 | 5 | namespace tinyrpc { 6 | 7 | std::string g_CRLF = "\r\n"; 8 | std::string g_CRLF_DOUBLE = "\r\n\r\n"; 9 | 10 | std::string content_type_text = "text/html;charset=utf-8"; 11 | const char* default_html_template = "

%s

%s

"; 12 | 13 | 14 | const char* httpCodeToString(const int code) { 15 | switch (code) 16 | { 17 | case HTTP_OK: 18 | return "OK"; 19 | 20 | case HTTP_BADREQUEST: 21 | return "Bad Request"; 22 | 23 | case HTTP_FORBIDDEN: 24 | return "Forbidden"; 25 | 26 | case HTTP_NOTFOUND: 27 | return "Not Found"; 28 | 29 | case HTTP_INTERNALSERVERERROR: 30 | return "Internal Server Error"; 31 | 32 | default: 33 | return "UnKnown code"; 34 | } 35 | 36 | } 37 | 38 | std::string HttpHeaderComm::getValue(const std::string& key) { 39 | return m_maps[key.c_str()]; 40 | } 41 | 42 | int HttpHeaderComm::getHeaderTotalLength() { 43 | int len = 0; 44 | for (auto it : m_maps) { 45 | len += it.first.length() + 1 + it.second.length() + 2; 46 | } 47 | return len; 48 | } 49 | 50 | void HttpHeaderComm::setKeyValue(const std::string& key, const std::string& value) { 51 | m_maps[key.c_str()] = value; 52 | } 53 | 54 | std::string HttpHeaderComm::toHttpString() { 55 | std::stringstream ss; 56 | for (auto it : m_maps) { 57 | ss << it.first << ":" << it.second << "\r\n"; 58 | } 59 | return ss.str(); 60 | } 61 | 62 | // void HttpRequestHeader::storeToMap() { 63 | // m_maps["Accept"] = m_accept; 64 | // m_maps["Referer"] = m_referer; 65 | // m_maps["Accept-Language"] = m_accept_language; 66 | // m_maps["Accept-Charset"] = m_accept_charset; 67 | // m_maps["User-Agent"] = m_user_agent; 68 | // m_maps["Host"] = m_host; 69 | // m_maps["Content-Type"] = m_content_type; 70 | // m_maps["Content-Length"] = m_content_length; 71 | // m_maps["Connection"] = m_connection; 72 | // m_maps["Cookie"] = m_cookie; 73 | // } 74 | 75 | 76 | // void HttpResponseHeader::storeToMap() { 77 | // m_maps["Server"] = m_server; 78 | // m_maps["Content-Type"] = m_content_type; 79 | // m_maps["Content-Length"] = m_content_length; 80 | // m_maps["Connection"] = m_connection; 81 | // m_maps["Set-Cookie"] = m_set_cookie; 82 | // } 83 | 84 | 85 | } -------------------------------------------------------------------------------- /tinyrpc/net/http/http_define.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_HTTP_HTTP_DEFINE_H 2 | #define TINYRPC_HTTP_HTTP_DEFINE_H 3 | 4 | #include 5 | #include 6 | 7 | namespace tinyrpc { 8 | 9 | extern std::string g_CRLF; 10 | extern std::string g_CRLF_DOUBLE; 11 | 12 | extern std::string content_type_text; 13 | extern const char* default_html_template; 14 | 15 | enum HttpMethod { 16 | GET = 1, 17 | POST = 2, 18 | }; 19 | 20 | enum HttpCode { 21 | HTTP_OK = 200, 22 | HTTP_BADREQUEST = 400, 23 | HTTP_FORBIDDEN = 403, 24 | HTTP_NOTFOUND = 404, 25 | HTTP_INTERNALSERVERERROR = 500, 26 | }; 27 | 28 | const char* httpCodeToString(const int code); 29 | 30 | class HttpHeaderComm { 31 | public: 32 | HttpHeaderComm() = default; 33 | 34 | virtual ~HttpHeaderComm() = default; 35 | 36 | int getHeaderTotalLength(); 37 | 38 | // virtual void storeToMap() = 0; 39 | 40 | std::string getValue(const std::string& key); 41 | 42 | void setKeyValue(const std::string& key, const std::string& value); 43 | 44 | std::string toHttpString(); 45 | 46 | 47 | public: 48 | std::map m_maps; 49 | 50 | }; 51 | 52 | class HttpRequestHeader : public HttpHeaderComm { 53 | public: 54 | // std::string m_accept; 55 | // std::string m_referer; 56 | // std::string m_accept_language; 57 | // std::string m_accept_charset; 58 | // std::string m_user_agent; 59 | // std::string m_host; 60 | // std::string m_content_type; 61 | // std::string m_content_length; 62 | // std::string m_connection; 63 | // std::string m_cookie; 64 | 65 | // public: 66 | // void storeToMap(); 67 | }; 68 | 69 | class HttpResponseHeader : public HttpHeaderComm { 70 | // public: 71 | // std::string m_server; 72 | // std::string m_content_type; 73 | // std::string m_content_length; 74 | // std::string m_set_cookie; 75 | // std::string m_connection; 76 | 77 | // public: 78 | // void storeToMap(); 79 | }; 80 | 81 | 82 | } 83 | 84 | #endif -------------------------------------------------------------------------------- /tinyrpc/net/http/http_dispatcher.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "tinyrpc/net/http/http_dispatcher.h" 4 | #include "tinyrpc/net/http/http_request.h" 5 | #include "tinyrpc/net/http/http_servlet.h" 6 | #include "tinyrpc/comm/log.h" 7 | #include "tinyrpc/comm/msg_req.h" 8 | 9 | 10 | namespace tinyrpc { 11 | 12 | void HttpDispacther::dispatch(AbstractData* data, TcpConnection* conn) { 13 | HttpRequest* resquest = dynamic_cast(data); 14 | HttpResponse response; 15 | Coroutine::GetCurrentCoroutine()->getRunTime()->m_msg_no = MsgReqUtil::genMsgNumber(); 16 | setCurrentRunTime(Coroutine::GetCurrentCoroutine()->getRunTime()); 17 | 18 | InfoLog << "begin to dispatch client http request, msgno=" << Coroutine::GetCurrentCoroutine()->getRunTime()->m_msg_no; 19 | 20 | std::string url_path = resquest->m_request_path; 21 | if (!url_path.empty()) { 22 | auto it = m_servlets.find(url_path); 23 | if (it == m_servlets.end()) { 24 | ErrorLog << "404, url path{ " << url_path << "}, msgno=" << Coroutine::GetCurrentCoroutine()->getRunTime()->m_msg_no; 25 | NotFoundHttpServlet servlet; 26 | Coroutine::GetCurrentCoroutine()->getRunTime()->m_interface_name = servlet.getServletName(); 27 | servlet.setCommParam(resquest, &response); 28 | servlet.handle(resquest, &response); 29 | } else { 30 | 31 | Coroutine::GetCurrentCoroutine()->getRunTime()->m_interface_name = it->second->getServletName(); 32 | it->second->setCommParam(resquest, &response); 33 | it->second->handle(resquest, &response); 34 | } 35 | } 36 | 37 | conn->getCodec()->encode(conn->getOutBuffer(), &response); 38 | 39 | InfoLog << "end dispatch client http request, msgno=" << Coroutine::GetCurrentCoroutine()->getRunTime()->m_msg_no; 40 | 41 | } 42 | 43 | void HttpDispacther::registerServlet(const std::string& path, HttpServlet::ptr servlet) { 44 | auto it = m_servlets.find(path); 45 | if (it == m_servlets.end()) { 46 | DebugLog << "register servlet success to path {" << path << "}"; 47 | m_servlets[path] = servlet; 48 | } else { 49 | ErrorLog << "failed to register, beacuse path {" << path << "} has already register sertlet"; 50 | } 51 | } 52 | 53 | 54 | 55 | 56 | } -------------------------------------------------------------------------------- /tinyrpc/net/http/http_dispatcher.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_HTTP_HTTP_DISPATCHER_H 2 | #define TINYRPC_NET_HTTP_HTTP_DISPATCHER_H 3 | 4 | #include 5 | #include 6 | #include "tinyrpc/net/abstract_dispatcher.h" 7 | #include "tinyrpc/net/http/http_servlet.h" 8 | 9 | 10 | namespace tinyrpc { 11 | 12 | class HttpDispacther : public AbstractDispatcher { 13 | public: 14 | HttpDispacther() = default; 15 | 16 | ~HttpDispacther() = default; 17 | 18 | void dispatch(AbstractData* data, TcpConnection* conn); 19 | 20 | void registerServlet(const std::string& path, HttpServlet::ptr servlet); 21 | 22 | public: 23 | std::map m_servlets; 24 | }; 25 | 26 | 27 | } 28 | 29 | 30 | 31 | #endif -------------------------------------------------------------------------------- /tinyrpc/net/http/http_request.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_HTTP_HTTP_REQUEST_H 2 | #define TINYRPC_NET_HTTP_HTTP_REQUEST_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "tinyrpc/net/abstract_data.h" 9 | #include "tinyrpc/net/http/http_define.h" 10 | 11 | 12 | namespace tinyrpc { 13 | 14 | class HttpRequest : public AbstractData { 15 | public: 16 | typedef std::shared_ptr ptr; 17 | 18 | public: 19 | HttpMethod m_request_method; 20 | std::string m_request_path; 21 | std::string m_request_query; 22 | std::string m_request_version; 23 | HttpRequestHeader m_requeset_header; 24 | std::string m_request_body; 25 | 26 | std::map m_query_maps; 27 | 28 | 29 | }; 30 | 31 | } 32 | 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /tinyrpc/net/http/http_response.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_HTTP_HTTP_RESPONSE_H 2 | #define TINYRPC_NET_HTTP_HTTP_RESPONSE_H 3 | 4 | #include 5 | #include 6 | 7 | #include "tinyrpc/net/abstract_data.h" 8 | #include "tinyrpc/net/http/http_define.h" 9 | 10 | namespace tinyrpc { 11 | 12 | class HttpResponse : public AbstractData { 13 | public: 14 | typedef std::shared_ptr ptr; 15 | 16 | public: 17 | std::string m_response_version; 18 | int m_response_code; 19 | std::string m_response_info; 20 | HttpResponseHeader m_response_header; 21 | std::string m_response_body; 22 | }; 23 | 24 | } 25 | 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /tinyrpc/net/http/http_servlet.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tinyrpc/net/http/http_servlet.h" 3 | #include "tinyrpc/net/http/http_request.h" 4 | #include "tinyrpc/net/http/http_response.h" 5 | #include "tinyrpc/net/http/http_define.h" 6 | #include "tinyrpc/comm/log.h" 7 | 8 | namespace tinyrpc { 9 | 10 | extern const char* default_html_template; 11 | extern std::string content_type_text; 12 | 13 | 14 | HttpServlet::HttpServlet() { 15 | } 16 | 17 | HttpServlet::~HttpServlet() { 18 | 19 | } 20 | 21 | void HttpServlet::handle(HttpRequest* req, HttpResponse* res) { 22 | // handleNotFound(); 23 | } 24 | 25 | void HttpServlet::handleNotFound(HttpRequest* req, HttpResponse* res) { 26 | DebugLog << "return 404 html"; 27 | setHttpCode(res, HTTP_NOTFOUND); 28 | char buf[512]; 29 | sprintf(buf, default_html_template, std::to_string(HTTP_NOTFOUND).c_str(), httpCodeToString(HTTP_NOTFOUND)); 30 | res->m_response_body = std::string(buf); 31 | res->m_response_header.m_maps["Content-Type"] = content_type_text; 32 | res->m_response_header.m_maps["Content-Length"]= std::to_string(res->m_response_body.length()); 33 | } 34 | 35 | void HttpServlet::setHttpCode(HttpResponse* res, const int code) { 36 | res->m_response_code = code; 37 | res->m_response_info = std::string(httpCodeToString(code)); 38 | } 39 | 40 | void HttpServlet::setHttpContentType(HttpResponse* res, const std::string& content_type) { 41 | res->m_response_header.m_maps["Content-Type"] = content_type; 42 | } 43 | 44 | void HttpServlet::setHttpBody(HttpResponse* res, const std::string& body) { 45 | res->m_response_body = body; 46 | res->m_response_header.m_maps["Content-Length"]= std::to_string(res->m_response_body.length()); 47 | } 48 | 49 | void HttpServlet::setCommParam(HttpRequest* req, HttpResponse* res) { 50 | DebugLog << "set response version=" << req->m_request_version; 51 | res->m_response_version = req->m_request_version; 52 | res->m_response_header.m_maps["Connection"]= req->m_requeset_header.m_maps["Connection"]; 53 | } 54 | 55 | 56 | NotFoundHttpServlet::NotFoundHttpServlet() { 57 | 58 | } 59 | 60 | NotFoundHttpServlet::~NotFoundHttpServlet() { 61 | 62 | } 63 | 64 | void NotFoundHttpServlet::handle(HttpRequest* req, HttpResponse* res) { 65 | handleNotFound(req, res); 66 | } 67 | 68 | 69 | std::string NotFoundHttpServlet::getServletName() { 70 | return "NotFoundHttpServlet"; 71 | } 72 | 73 | 74 | } -------------------------------------------------------------------------------- /tinyrpc/net/http/http_servlet.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_HTTP_HTTP_SERVLET_H 2 | #define TINYRPC_NET_HTTP_HTTP_SERVLET_H 3 | 4 | #include 5 | #include "tinyrpc/net/http/http_request.h" 6 | #include "tinyrpc/net/http/http_response.h" 7 | 8 | namespace tinyrpc { 9 | 10 | class HttpServlet : public std::enable_shared_from_this { 11 | public: 12 | typedef std::shared_ptr ptr; 13 | 14 | HttpServlet(); 15 | 16 | virtual ~HttpServlet(); 17 | 18 | virtual void handle(HttpRequest* req, HttpResponse* res) = 0; 19 | 20 | virtual std::string getServletName() = 0; 21 | 22 | void handleNotFound(HttpRequest* req, HttpResponse* res); 23 | 24 | void setHttpCode(HttpResponse* res, const int code); 25 | 26 | void setHttpContentType(HttpResponse* res, const std::string& content_type); 27 | 28 | void setHttpBody(HttpResponse* res, const std::string& body); 29 | 30 | void setCommParam(HttpRequest* req, HttpResponse* res); 31 | 32 | }; 33 | 34 | 35 | class NotFoundHttpServlet: public HttpServlet { 36 | public: 37 | 38 | NotFoundHttpServlet(); 39 | 40 | ~NotFoundHttpServlet(); 41 | 42 | void handle(HttpRequest* req, HttpResponse* res); 43 | 44 | std::string getServletName(); 45 | 46 | }; 47 | 48 | } 49 | 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /tinyrpc/net/mutex.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "tinyrpc/net/mutex.h" 4 | #include "tinyrpc/net/reactor.h" 5 | #include "tinyrpc/comm/log.h" 6 | #include "tinyrpc/coroutine/coroutine.h" 7 | #include "tinyrpc/coroutine/coroutine_hook.h" 8 | 9 | // this file copy form sylar 10 | 11 | namespace tinyrpc { 12 | 13 | 14 | CoroutineMutex::CoroutineMutex() {} 15 | 16 | CoroutineMutex::~CoroutineMutex() { 17 | if (m_lock) { 18 | unlock(); 19 | } 20 | } 21 | 22 | void CoroutineMutex::lock() { 23 | 24 | if (Coroutine::IsMainCoroutine()) { 25 | ErrorLog << "main coroutine can't use coroutine mutex"; 26 | return; 27 | } 28 | 29 | Coroutine* cor = Coroutine::GetCurrentCoroutine(); 30 | 31 | Mutex::Lock lock(m_mutex); 32 | if (!m_lock) { 33 | m_lock = true; 34 | DebugLog << "coroutine succ get coroutine mutex"; 35 | lock.unlock(); 36 | } else { 37 | m_sleep_cors.push(cor); 38 | auto tmp = m_sleep_cors; 39 | lock.unlock(); 40 | 41 | DebugLog << "coroutine yield, pending coroutine mutex, current sleep queue exist [" 42 | << tmp.size() << "] coroutines"; 43 | 44 | Coroutine::Yield(); 45 | } 46 | } 47 | 48 | void CoroutineMutex::unlock() { 49 | if (Coroutine::IsMainCoroutine()) { 50 | ErrorLog << "main coroutine can't use coroutine mutex"; 51 | return; 52 | } 53 | 54 | Mutex::Lock lock(m_mutex); 55 | if (m_lock) { 56 | m_lock = false; 57 | if (m_sleep_cors.empty()) { 58 | return; 59 | } 60 | 61 | Coroutine* cor = m_sleep_cors.front(); 62 | m_sleep_cors.pop(); 63 | lock.unlock(); 64 | 65 | if (cor) { 66 | // wakeup the first cor in sleep queue 67 | DebugLog << "coroutine unlock, now to resume coroutine[" << cor->getCorId() << "]"; 68 | 69 | tinyrpc::Reactor::GetReactor()->addTask([cor]() { 70 | tinyrpc::Coroutine::Resume(cor); 71 | }, true); 72 | } 73 | } 74 | } 75 | 76 | 77 | } -------------------------------------------------------------------------------- /tinyrpc/net/mutex.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_MUTEX_H 2 | #define TINYRPC_MUTEX_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "tinyrpc/coroutine/coroutine.h" 8 | 9 | // this file copy form sylar 10 | 11 | namespace tinyrpc { 12 | 13 | template 14 | struct ScopedLockImpl 15 | { 16 | public: 17 | ScopedLockImpl(T &mutex) 18 | : m_mutex(mutex) 19 | { 20 | m_mutex.lock(); 21 | m_locked = true; 22 | } 23 | 24 | ~ScopedLockImpl() 25 | { 26 | unlock(); 27 | } 28 | 29 | void lock() 30 | { 31 | if (!m_locked) 32 | { 33 | m_mutex.lock(); 34 | m_locked = true; 35 | } 36 | } 37 | 38 | void unlock() 39 | { 40 | if (m_locked) 41 | { 42 | m_mutex.unlock(); 43 | m_locked = false; 44 | } 45 | } 46 | 47 | private: 48 | /// mutex 49 | T &m_mutex; 50 | /// 是否已上锁 51 | bool m_locked; 52 | }; 53 | 54 | template 55 | struct ReadScopedLockImpl 56 | { 57 | public: 58 | ReadScopedLockImpl(T &mutex) 59 | : m_mutex(mutex) 60 | { 61 | m_mutex.rdlock(); 62 | m_locked = true; 63 | } 64 | 65 | ~ReadScopedLockImpl() 66 | { 67 | unlock(); 68 | } 69 | 70 | void lock() 71 | { 72 | if (!m_locked) 73 | { 74 | m_mutex.rdlock(); 75 | m_locked = true; 76 | } 77 | } 78 | 79 | void unlock() 80 | { 81 | if (m_locked) 82 | { 83 | m_mutex.unlock(); 84 | m_locked = false; 85 | } 86 | } 87 | 88 | private: 89 | /// mutex 90 | T &m_mutex; 91 | /// 是否已上锁 92 | bool m_locked; 93 | }; 94 | 95 | /** 96 | * @brief 局部写锁模板实现 97 | */ 98 | template 99 | struct WriteScopedLockImpl 100 | { 101 | public: 102 | WriteScopedLockImpl(T &mutex) 103 | : m_mutex(mutex) 104 | { 105 | m_mutex.wrlock(); 106 | m_locked = true; 107 | } 108 | 109 | ~WriteScopedLockImpl() 110 | { 111 | unlock(); 112 | } 113 | 114 | void lock() 115 | { 116 | if (!m_locked) 117 | { 118 | m_mutex.wrlock(); 119 | m_locked = true; 120 | } 121 | } 122 | 123 | void unlock() 124 | { 125 | if (m_locked) 126 | { 127 | m_mutex.unlock(); 128 | m_locked = false; 129 | } 130 | } 131 | 132 | private: 133 | T &m_mutex; 134 | bool m_locked; 135 | }; 136 | 137 | class Mutex 138 | { 139 | public: 140 | /// 局部锁 141 | typedef ScopedLockImpl Lock; 142 | 143 | Mutex() 144 | { 145 | pthread_mutex_init(&m_mutex, nullptr); 146 | } 147 | 148 | ~Mutex() 149 | { 150 | pthread_mutex_destroy(&m_mutex); 151 | } 152 | 153 | void lock() 154 | { 155 | pthread_mutex_lock(&m_mutex); 156 | } 157 | 158 | void unlock() 159 | { 160 | pthread_mutex_unlock(&m_mutex); 161 | } 162 | 163 | pthread_mutex_t *getMutex() 164 | { 165 | return &m_mutex; 166 | } 167 | 168 | private: 169 | /// mutex 170 | pthread_mutex_t m_mutex; 171 | }; 172 | 173 | class RWMutex 174 | { 175 | public: 176 | /// 局部读锁 177 | typedef ReadScopedLockImpl ReadLock; 178 | 179 | typedef WriteScopedLockImpl WriteLock; 180 | 181 | RWMutex() 182 | { 183 | pthread_rwlock_init(&m_lock, nullptr); 184 | } 185 | 186 | ~RWMutex() 187 | { 188 | pthread_rwlock_destroy(&m_lock); 189 | } 190 | 191 | void rdlock() 192 | { 193 | pthread_rwlock_rdlock(&m_lock); 194 | } 195 | 196 | void wrlock() 197 | { 198 | pthread_rwlock_wrlock(&m_lock); 199 | } 200 | 201 | void unlock() 202 | { 203 | pthread_rwlock_unlock(&m_lock); 204 | } 205 | 206 | private: 207 | pthread_rwlock_t m_lock; 208 | }; 209 | 210 | 211 | class CoroutineMutex { 212 | public: 213 | typedef ScopedLockImpl Lock; 214 | 215 | CoroutineMutex(); 216 | 217 | ~CoroutineMutex(); 218 | 219 | void lock(); 220 | 221 | void unlock(); 222 | private: 223 | bool m_lock {false}; 224 | Mutex m_mutex; 225 | std::queue m_sleep_cors; 226 | }; 227 | 228 | 229 | } 230 | #endif 231 | -------------------------------------------------------------------------------- /tinyrpc/net/net_address.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "net_address.h" 10 | #include "../comm/log.h" 11 | 12 | namespace tinyrpc { 13 | 14 | bool IPAddress::CheckValidIPAddr(const std::string& addr) { 15 | size_t i = addr.find_first_of(":"); 16 | if (i == addr.npos) { 17 | return false; 18 | } 19 | int port = std::atoi(addr.substr(i + 1, addr.size() - i - 1).c_str()); 20 | if (port < 0 || port > 65536) { 21 | return false; 22 | } 23 | 24 | if(inet_addr(addr.substr(0, i).c_str()) == INADDR_NONE) { 25 | return false; 26 | } 27 | return true; 28 | } 29 | 30 | IPAddress::IPAddress(const std::string& ip, uint16_t port) 31 | : m_ip(ip), m_port(port) { 32 | 33 | memset(&m_addr, 0, sizeof(m_addr)); 34 | m_addr.sin_family = AF_INET; 35 | m_addr.sin_addr.s_addr = inet_addr(m_ip.c_str()); 36 | m_addr.sin_port = htons(m_port); 37 | 38 | DebugLog << "create ipv4 address succ [" << toString() << "]"; 39 | } 40 | 41 | IPAddress::IPAddress(sockaddr_in addr) : m_addr(addr) { 42 | // if (m_addr.sin_family != AF_INET) { 43 | // ErrorLog << "err family, this address is valid"; 44 | // } 45 | DebugLog << "ip[" << m_ip << "], port[" << addr.sin_port; 46 | m_ip = std::string(inet_ntoa(m_addr.sin_addr)); 47 | m_port = ntohs(m_addr.sin_port); 48 | } 49 | 50 | IPAddress::IPAddress(const std::string& addr) { 51 | size_t i = addr.find_first_of(":"); 52 | if (i == addr.npos) { 53 | ErrorLog << "invalid addr[" << addr << "]"; 54 | return; 55 | } 56 | m_ip = addr.substr(0, i); 57 | m_port = std::atoi(addr.substr(i + 1, addr.size() - i - 1).c_str()); 58 | 59 | memset(&m_addr, 0, sizeof(m_addr)); 60 | m_addr.sin_family = AF_INET; 61 | m_addr.sin_addr.s_addr = inet_addr(m_ip.c_str()); 62 | m_addr.sin_port = htons(m_port); 63 | DebugLog << "create ipv4 address succ [" << toString() << "]"; 64 | 65 | } 66 | 67 | IPAddress::IPAddress(uint16_t port) : m_port(port) { 68 | memset(&m_addr, 0, sizeof(m_addr)); 69 | m_addr.sin_family = AF_INET; 70 | m_addr.sin_addr.s_addr = INADDR_ANY; 71 | m_addr.sin_port = htons(m_port); 72 | 73 | DebugLog << "create ipv4 address succ [" << toString() << "]"; 74 | } 75 | 76 | int IPAddress::getFamily() const { 77 | return m_addr.sin_family; 78 | } 79 | 80 | sockaddr* IPAddress::getSockAddr() { 81 | return reinterpret_cast(&m_addr); 82 | } 83 | 84 | std::string IPAddress::toString() const { 85 | std::stringstream ss; 86 | ss << m_ip << ":" << m_port; 87 | return ss.str(); 88 | } 89 | 90 | socklen_t IPAddress::getSockLen() const { 91 | return sizeof(m_addr); 92 | } 93 | 94 | 95 | UnixDomainAddress::UnixDomainAddress(std::string& path) : m_path(path) { 96 | 97 | memset(&m_addr, 0, sizeof(m_addr)); 98 | unlink(m_path.c_str()); 99 | m_addr.sun_family = AF_UNIX; 100 | strcpy(m_addr.sun_path, m_path.c_str()); 101 | 102 | } 103 | UnixDomainAddress::UnixDomainAddress(sockaddr_un addr) : m_addr(addr) { 104 | m_path = m_addr.sun_path; 105 | } 106 | 107 | int UnixDomainAddress::getFamily() const { 108 | return m_addr.sun_family; 109 | } 110 | 111 | sockaddr* UnixDomainAddress::getSockAddr() { 112 | return reinterpret_cast(&m_addr); 113 | } 114 | 115 | socklen_t UnixDomainAddress::getSockLen() const { 116 | return sizeof(m_addr); 117 | } 118 | 119 | std::string UnixDomainAddress::toString() const { 120 | return m_path; 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /tinyrpc/net/net_address.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_NET_ADDRESS_H 2 | #define TINYRPC_NET_NET_ADDRESS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | namespace tinyrpc { 14 | 15 | 16 | class NetAddress { 17 | 18 | public: 19 | 20 | typedef std::shared_ptr ptr; 21 | 22 | virtual sockaddr* getSockAddr() = 0; 23 | 24 | virtual int getFamily() const = 0; 25 | 26 | virtual std::string toString() const = 0; 27 | 28 | virtual socklen_t getSockLen() const = 0; 29 | 30 | }; 31 | 32 | 33 | class IPAddress : public NetAddress { 34 | 35 | public: 36 | IPAddress(const std::string& ip, uint16_t port); 37 | 38 | IPAddress(const std::string& addr); 39 | 40 | IPAddress(uint16_t port); 41 | 42 | IPAddress(sockaddr_in addr); 43 | 44 | sockaddr* getSockAddr(); 45 | 46 | int getFamily() const; 47 | 48 | socklen_t getSockLen() const; 49 | 50 | std::string toString() const; 51 | 52 | std::string getIP() const { 53 | return m_ip; 54 | } 55 | 56 | int getPort() const { 57 | return m_port; 58 | } 59 | 60 | public: 61 | static bool CheckValidIPAddr(const std::string& addr); 62 | 63 | 64 | private: 65 | 66 | std::string m_ip; 67 | uint16_t m_port; 68 | sockaddr_in m_addr; 69 | 70 | }; 71 | 72 | class UnixDomainAddress : public NetAddress { 73 | 74 | public: 75 | 76 | UnixDomainAddress(std::string& path); 77 | 78 | UnixDomainAddress(sockaddr_un addr); 79 | 80 | sockaddr* getSockAddr(); 81 | 82 | int getFamily() const; 83 | 84 | socklen_t getSockLen() const; 85 | 86 | std::string getPath() const { 87 | return m_path; 88 | } 89 | 90 | std::string toString() const; 91 | 92 | 93 | private: 94 | 95 | std::string m_path; 96 | sockaddr_un m_addr; 97 | 98 | }; 99 | 100 | 101 | } 102 | 103 | 104 | #endif 105 | 106 | -------------------------------------------------------------------------------- /tinyrpc/net/reactor.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_EVENT_LOOP_H 2 | #define TINYRPC_NET_EVENT_LOOP_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "tinyrpc/coroutine/coroutine.h" 12 | #include "fd_event.h" 13 | #include "mutex.h" 14 | 15 | namespace tinyrpc { 16 | 17 | enum ReactorType { 18 | MainReactor = 1, // main rewactor, only set this by main thread. 19 | SubReactor = 2 // child reactor, every io thread is this type 20 | }; 21 | 22 | class FdEvent; 23 | class Timer; 24 | 25 | // typedef std::shared_ptr TimerPtr; 26 | 27 | class Reactor { 28 | 29 | public: 30 | 31 | typedef std::shared_ptr ptr; 32 | 33 | explicit Reactor(); 34 | 35 | ~Reactor(); 36 | 37 | void addEvent(int fd, epoll_event event, bool is_wakeup = true); 38 | 39 | void delEvent(int fd, bool is_wakeup = true); 40 | 41 | void addTask(std::function task, bool is_wakeup = true); 42 | 43 | void addTask(std::vector> task, bool is_wakeup = true); 44 | 45 | void addCoroutine(tinyrpc::Coroutine::ptr cor, bool is_wakeup = true); 46 | 47 | void wakeup(); 48 | 49 | void loop(); 50 | 51 | void stop(); 52 | 53 | Timer* getTimer(); 54 | 55 | pid_t getTid(); 56 | 57 | void setReactorType(ReactorType type); 58 | 59 | public: 60 | static Reactor* GetReactor(); 61 | 62 | 63 | private: 64 | 65 | void addWakeupFd(); 66 | 67 | bool isLoopThread() const; 68 | 69 | void addEventInLoopThread(int fd, epoll_event event); 70 | 71 | void delEventInLoopThread(int fd); 72 | 73 | private: 74 | int m_epfd {-1}; 75 | int m_wake_fd {-1}; // wakeup fd 76 | int m_timer_fd {-1}; // timer fd 77 | bool m_stop_flag {false}; 78 | bool m_is_looping {false}; 79 | bool m_is_init_timer {false}; 80 | pid_t m_tid {0}; // thread id 81 | 82 | Mutex m_mutex; // mutex 83 | 84 | std::vector m_fds; // alrady care events 85 | std::atomic m_fd_size; 86 | 87 | // fds that wait for operate 88 | // 1 -- to add to loop 89 | // 2 -- to del from loop 90 | std::map m_pending_add_fds; 91 | std::vector m_pending_del_fds; 92 | std::vector> m_pending_tasks; 93 | 94 | Timer* m_timer {nullptr}; 95 | 96 | ReactorType m_reactor_type {SubReactor}; 97 | 98 | }; 99 | 100 | 101 | class CoroutineTaskQueue { 102 | public: 103 | static CoroutineTaskQueue* GetCoroutineTaskQueue(); 104 | 105 | void push(FdEvent* fd); 106 | 107 | FdEvent* pop(); 108 | 109 | private: 110 | std::queue m_task; 111 | Mutex m_mutex; // mutex 112 | }; 113 | 114 | 115 | } 116 | 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /tinyrpc/net/tcp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(HEADERS 2 | abstract_slot.h 3 | tcp_client.h 4 | tcp_server.h 5 | io_thread.h 6 | tcp_connection.h 7 | tcp_buffer.h 8 | tcp_connection_time_wheel.h 9 | ) 10 | 11 | install(FILES ${HEADERS} DESTINATION include/tinyrpc/net/tcp) -------------------------------------------------------------------------------- /tinyrpc/net/tcp/abstract_slot.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_TCP_ABSTRACTSLOT_H 2 | #define TINYRPC_NET_TCP_ABSTRACTSLOT_H 3 | 4 | #include 5 | #include 6 | 7 | namespace tinyrpc { 8 | 9 | 10 | template 11 | class AbstractSlot { 12 | public: 13 | typedef std::shared_ptr ptr; 14 | typedef std::weak_ptr weakPtr; 15 | typedef std::shared_ptr sharedPtr; 16 | 17 | AbstractSlot(weakPtr ptr, std::function cb) : m_weak_ptr(ptr), m_cb(cb) { 18 | 19 | } 20 | ~AbstractSlot() { 21 | sharedPtr ptr = m_weak_ptr.lock(); 22 | if (ptr) { 23 | m_cb(ptr); 24 | } 25 | } 26 | 27 | private: 28 | weakPtr m_weak_ptr; 29 | std::function m_cb; 30 | 31 | }; 32 | 33 | 34 | } 35 | #endif -------------------------------------------------------------------------------- /tinyrpc/net/tcp/io_thread.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "tinyrpc/net/reactor.h" 7 | #include "tinyrpc/net/tcp/io_thread.h" 8 | #include "tinyrpc/net/tcp/tcp_connection.h" 9 | #include "tinyrpc/net/tcp/tcp_server.h" 10 | #include "tinyrpc/net/tcp/tcp_connection_time_wheel.h" 11 | #include "tinyrpc/coroutine/coroutine.h" 12 | #include "tinyrpc/coroutine/coroutine_pool.h" 13 | #include "tinyrpc/comm/config.h" 14 | 15 | 16 | namespace tinyrpc { 17 | 18 | extern tinyrpc::Config::ptr gRpcConfig; 19 | 20 | static thread_local Reactor* t_reactor_ptr = nullptr; 21 | 22 | static thread_local IOThread* t_cur_io_thread = nullptr; 23 | 24 | 25 | IOThread::IOThread() { 26 | int rt = sem_init(&m_init_semaphore, 0, 0); 27 | assert(rt==0); 28 | 29 | rt = sem_init(&m_start_semaphore, 0, 0); 30 | assert(rt==0); 31 | 32 | pthread_create(&m_thread, nullptr, &IOThread::main, this); 33 | 34 | DebugLog << "semaphore begin to wait until new thread frinish IOThread::main() to init"; 35 | // wait until new thread finish IOThread::main() func to init 36 | rt = sem_wait(&m_init_semaphore); 37 | assert(rt == 0); 38 | DebugLog << "semaphore wait end, finish create io thread"; 39 | 40 | sem_destroy(&m_init_semaphore); 41 | } 42 | 43 | IOThread::~IOThread() { 44 | m_reactor->stop(); 45 | pthread_join(m_thread, nullptr); 46 | 47 | if (m_reactor != nullptr) { 48 | 49 | delete m_reactor; 50 | m_reactor = nullptr; 51 | } 52 | } 53 | 54 | IOThread* IOThread::GetCurrentIOThread() { 55 | return t_cur_io_thread; 56 | } 57 | 58 | sem_t* IOThread::getStartSemaphore() { 59 | return &m_start_semaphore; 60 | } 61 | 62 | Reactor* IOThread::getReactor() { 63 | return m_reactor; 64 | } 65 | 66 | pthread_t IOThread::getPthreadId() { 67 | return m_thread; 68 | } 69 | 70 | void IOThread::setThreadIndex(const int index) { 71 | m_index = index; 72 | } 73 | 74 | int IOThread::getThreadIndex() { 75 | return m_index; 76 | } 77 | 78 | void* IOThread::main(void* arg) { 79 | // assert(t_reactor_ptr == nullptr); 80 | 81 | t_reactor_ptr = new Reactor(); 82 | assert(t_reactor_ptr != NULL); 83 | 84 | IOThread* thread = static_cast(arg); 85 | t_cur_io_thread = thread; 86 | thread->m_reactor = t_reactor_ptr; 87 | thread->m_reactor->setReactorType(SubReactor); 88 | thread->m_tid = gettid(); 89 | 90 | Coroutine::GetCurrentCoroutine(); 91 | 92 | DebugLog << "finish iothread init, now post semaphore"; 93 | sem_post(&thread->m_init_semaphore); 94 | 95 | // wait for main thread post m_start_semaphore to start iothread loop 96 | sem_wait(&thread->m_start_semaphore); 97 | 98 | sem_destroy(&thread->m_start_semaphore); 99 | 100 | DebugLog << "IOThread " << thread->m_tid << " begin to loop"; 101 | t_reactor_ptr->loop(); 102 | 103 | return nullptr; 104 | } 105 | 106 | void IOThread::addClient(TcpConnection* tcp_conn) { 107 | tcp_conn->registerToTimeWheel(); 108 | tcp_conn->setUpServer(); 109 | return; 110 | } 111 | 112 | IOThreadPool::IOThreadPool(int size) : m_size(size) { 113 | m_io_threads.resize(size); 114 | for (int i = 0; i < size; ++i) { 115 | m_io_threads[i] = std::make_shared(); 116 | m_io_threads[i]->setThreadIndex(i); 117 | } 118 | } 119 | 120 | void IOThreadPool::start() { 121 | for (int i = 0; i < m_size; ++i) { 122 | int rt = sem_post(m_io_threads[i]->getStartSemaphore()); 123 | assert(rt == 0); 124 | } 125 | } 126 | 127 | IOThread* IOThreadPool::getIOThread() { 128 | if (m_index == m_size || m_index == -1) { 129 | m_index = 0; 130 | } 131 | return m_io_threads[m_index++].get(); 132 | } 133 | 134 | 135 | int IOThreadPool::getIOThreadPoolSize() { 136 | return m_size; 137 | } 138 | 139 | void IOThreadPool::broadcastTask(std::function cb) { 140 | for (auto i : m_io_threads) { 141 | i->getReactor()->addTask(cb, true); 142 | } 143 | } 144 | 145 | void IOThreadPool::addTaskByIndex(int index, std::function cb) { 146 | if (index >= 0 && index < m_size) { 147 | m_io_threads[index]->getReactor()->addTask(cb, true); 148 | } 149 | } 150 | 151 | void IOThreadPool::addCoroutineToRandomThread(Coroutine::ptr cor, bool self /* = false*/) { 152 | if (m_size == 1) { 153 | m_io_threads[0]->getReactor()->addCoroutine(cor, true); 154 | return; 155 | } 156 | srand(time(0)); 157 | int i = 0; 158 | while (1) { 159 | i = rand() % (m_size); 160 | if (!self && m_io_threads[i]->getPthreadId() == t_cur_io_thread->getPthreadId()) { 161 | i++; 162 | if (i == m_size) { 163 | i -= 2; 164 | } 165 | } 166 | break; 167 | } 168 | m_io_threads[i]->getReactor()->addCoroutine(cor, true); 169 | // if (m_io_threads[m_index]->getPthreadId() == t_cur_io_thread->getPthreadId()) { 170 | // m_index++; 171 | // if (m_index == m_size || m_index == -1) { 172 | // m_index = 0; 173 | // } 174 | // } 175 | } 176 | 177 | 178 | Coroutine::ptr IOThreadPool::addCoroutineToRandomThread(std::function cb, bool self/* = false*/) { 179 | Coroutine::ptr cor = GetCoroutinePool()->getCoroutineInstanse(); 180 | cor->setCallBack(cb); 181 | addCoroutineToRandomThread(cor, self); 182 | return cor; 183 | } 184 | 185 | Coroutine::ptr IOThreadPool::addCoroutineToThreadByIndex(int index, std::function cb, bool self/* = false*/) { 186 | if (index >= (int)m_io_threads.size() || index < 0) { 187 | ErrorLog << "addCoroutineToThreadByIndex error, invalid iothread index[" << index << "]"; 188 | return nullptr; 189 | } 190 | Coroutine::ptr cor = GetCoroutinePool()->getCoroutineInstanse(); 191 | cor->setCallBack(cb); 192 | m_io_threads[index]->getReactor()->addCoroutine(cor, true); 193 | return cor; 194 | 195 | } 196 | 197 | void IOThreadPool::addCoroutineToEachThread(std::function cb) { 198 | for (auto i : m_io_threads) { 199 | Coroutine::ptr cor = GetCoroutinePool()->getCoroutineInstanse(); 200 | cor->setCallBack(cb); 201 | i->getReactor()->addCoroutine(cor, true); 202 | } 203 | } 204 | 205 | 206 | } -------------------------------------------------------------------------------- /tinyrpc/net/tcp/io_thread.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_TCP_IO_THREAD_H 2 | #define TINYRPC_NET_TCP_IO_THREAD_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "tinyrpc/net/reactor.h" 10 | #include "tinyrpc/net/tcp/tcp_connection_time_wheel.h" 11 | #include "tinyrpc/coroutine/coroutine.h" 12 | 13 | 14 | namespace tinyrpc { 15 | 16 | class TcpServer; 17 | 18 | class IOThread { 19 | 20 | public: 21 | 22 | typedef std::shared_ptr ptr; 23 | IOThread(); 24 | 25 | ~IOThread(); 26 | 27 | Reactor* getReactor(); 28 | 29 | void addClient(TcpConnection* tcp_conn); 30 | 31 | pthread_t getPthreadId(); 32 | 33 | void setThreadIndex(const int index); 34 | 35 | int getThreadIndex(); 36 | 37 | sem_t* getStartSemaphore(); 38 | 39 | 40 | public: 41 | static IOThread* GetCurrentIOThread(); 42 | 43 | private: 44 | static void* main(void* arg); 45 | 46 | private: 47 | Reactor* m_reactor {nullptr}; 48 | pthread_t m_thread {0}; 49 | pid_t m_tid {-1}; 50 | TimerEvent::ptr m_timer_event {nullptr}; 51 | int m_index {-1}; 52 | 53 | sem_t m_init_semaphore; 54 | 55 | sem_t m_start_semaphore; 56 | 57 | }; 58 | 59 | class IOThreadPool { 60 | 61 | public: 62 | typedef std::shared_ptr ptr; 63 | 64 | IOThreadPool(int size); 65 | 66 | void start(); 67 | 68 | IOThread* getIOThread(); 69 | 70 | int getIOThreadPoolSize(); 71 | 72 | void broadcastTask(std::function cb); 73 | 74 | void addTaskByIndex(int index, std::function cb); 75 | 76 | void addCoroutineToRandomThread(Coroutine::ptr cor, bool self = false); 77 | 78 | // add a coroutine to random thread in io thread pool 79 | // self = false, means random thread cann't be current thread 80 | // please free cor, or causes memory leak 81 | // call returnCoroutine(cor) to free coroutine 82 | Coroutine::ptr addCoroutineToRandomThread(std::function cb, bool self = false); 83 | 84 | Coroutine::ptr addCoroutineToThreadByIndex(int index, std::function cb, bool self = false); 85 | 86 | void addCoroutineToEachThread(std::function cb); 87 | 88 | private: 89 | int m_size {0}; 90 | 91 | std::atomic m_index {-1}; 92 | 93 | std::vector m_io_threads; 94 | 95 | }; 96 | 97 | 98 | } 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /tinyrpc/net/tcp/tcp_buffer.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "tinyrpc/net/tcp/tcp_buffer.h" 4 | #include "tinyrpc/comm/log.h" 5 | 6 | 7 | namespace tinyrpc { 8 | 9 | TcpBuffer::TcpBuffer(int size) { 10 | m_buffer.resize(size); 11 | } 12 | 13 | 14 | TcpBuffer::~TcpBuffer() { 15 | 16 | } 17 | 18 | int TcpBuffer::readAble() { 19 | 20 | return m_write_index - m_read_index; 21 | } 22 | 23 | int TcpBuffer::writeAble() { 24 | 25 | return m_buffer.size() - m_write_index; 26 | } 27 | 28 | int TcpBuffer::readIndex() const { 29 | return m_read_index; 30 | } 31 | 32 | int TcpBuffer::writeIndex() const { 33 | return m_write_index; 34 | } 35 | 36 | // int TcpBuffer::readFromSocket(int sockfd) { 37 | // if (writeAble() == 0) { 38 | // m_buffer.resize(2 * m_size); 39 | // } 40 | // int rt = read(sockfd, &m_buffer[m_write_index], writeAble()); 41 | // if (rt >= 0) { 42 | // m_write_index += rt; 43 | // } 44 | // return rt; 45 | // } 46 | 47 | void TcpBuffer::resizeBuffer(int size) { 48 | std::vector tmp(size); 49 | int c = std::min(size, readAble()); 50 | memcpy(&tmp[0], &m_buffer[m_read_index], c); 51 | 52 | m_buffer.swap(tmp); 53 | m_read_index = 0; 54 | m_write_index = m_read_index + c; 55 | 56 | } 57 | 58 | void TcpBuffer::writeToBuffer(const char* buf, int size) { 59 | if (size > writeAble()) { 60 | int new_size = (int)(1.5 * (m_write_index + size)); 61 | resizeBuffer(new_size); 62 | } 63 | memcpy(&m_buffer[m_write_index], buf, size); 64 | m_write_index += size; 65 | 66 | } 67 | 68 | 69 | void TcpBuffer::readFromBuffer(std::vector& re, int size) { 70 | if (readAble() == 0) { 71 | DebugLog << "read buffer empty!"; 72 | return; 73 | } 74 | int read_size = readAble() > size ? size : readAble(); 75 | std::vector tmp(read_size); 76 | 77 | // std::copy(m_read_index, m_read_index + read_size, tmp); 78 | memcpy(&tmp[0], &m_buffer[m_read_index], read_size); 79 | re.swap(tmp); 80 | m_read_index += read_size; 81 | adjustBuffer(); 82 | 83 | } 84 | 85 | void TcpBuffer::adjustBuffer() { 86 | if (m_read_index > static_cast(m_buffer.size() / 3)) { 87 | 88 | std::vector new_buffer(m_buffer.size()); 89 | 90 | int count = readAble(); 91 | // std::copy(&m_buffer[m_read_index], readAble(), &new_buffer); 92 | memcpy(&new_buffer[0], &m_buffer[m_read_index], count); 93 | 94 | m_buffer.swap(new_buffer); 95 | m_write_index = count; 96 | m_read_index = 0; 97 | new_buffer.clear(); 98 | 99 | } 100 | 101 | } 102 | 103 | int TcpBuffer::getSize() { 104 | return m_buffer.size(); 105 | } 106 | 107 | void TcpBuffer::clearBuffer() { 108 | m_buffer.clear(); 109 | m_read_index = 0; 110 | m_write_index = 0; 111 | } 112 | 113 | void TcpBuffer::recycleRead(int index) { 114 | int j = m_read_index + index; 115 | if (j > (int)m_buffer.size()) { 116 | ErrorLog << "recycleRead error"; 117 | return; 118 | } 119 | m_read_index = j; 120 | adjustBuffer(); 121 | } 122 | 123 | void TcpBuffer::recycleWrite(int index) { 124 | int j = m_write_index + index; 125 | if (j > (int)m_buffer.size()) { 126 | ErrorLog << "recycleWrite error"; 127 | return; 128 | } 129 | m_write_index = j; 130 | adjustBuffer(); 131 | } 132 | 133 | // const char* TcpBuffer::getBuffer() { 134 | // char* tmp; 135 | // memcpy(&tmp, &m_buffer[m_read_index], readAble()); 136 | // return tmp; 137 | // } 138 | 139 | std::string TcpBuffer::getBufferString() { 140 | std::string re(readAble(), '0'); 141 | memcpy(&re[0], &m_buffer[m_read_index], readAble()); 142 | return re; 143 | } 144 | 145 | std::vector TcpBuffer::getBufferVector() { 146 | return m_buffer; 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /tinyrpc/net/tcp/tcp_buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_TCP_TCP_BUFFER_H 2 | #define TINYRPC_NET_TCP_TCP_BUFFER_H 3 | 4 | #include 5 | #include 6 | 7 | 8 | namespace tinyrpc { 9 | 10 | 11 | class TcpBuffer { 12 | 13 | public: 14 | typedef std::shared_ptr ptr; 15 | 16 | explicit TcpBuffer(int size); 17 | 18 | ~TcpBuffer(); 19 | 20 | int readAble(); 21 | 22 | int writeAble(); 23 | 24 | int readIndex() const; 25 | 26 | int writeIndex() const; 27 | 28 | // int readFormSocket(char* buf, int size); 29 | 30 | void writeToBuffer(const char* buf, int size); 31 | 32 | void readFromBuffer(std::vector& re, int size); 33 | 34 | void resizeBuffer(int size); 35 | 36 | void clearBuffer(); 37 | 38 | int getSize(); 39 | 40 | // const char* getBuffer(); 41 | 42 | std::vector getBufferVector(); 43 | 44 | std::string getBufferString(); 45 | 46 | void recycleRead(int index); 47 | 48 | void recycleWrite(int index); 49 | 50 | void adjustBuffer(); 51 | 52 | private: 53 | 54 | int m_read_index {0}; 55 | int m_write_index {0}; 56 | int m_size {0}; 57 | 58 | public: 59 | std::vector m_buffer; 60 | 61 | }; 62 | 63 | 64 | 65 | } 66 | 67 | 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /tinyrpc/net/tcp/tcp_client.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "tinyrpc/comm/log.h" 4 | #include "tinyrpc/coroutine/coroutine.h" 5 | #include "tinyrpc/coroutine/coroutine_hook.h" 6 | #include "tinyrpc/coroutine/coroutine_pool.h" 7 | #include "tinyrpc/net/net_address.h" 8 | #include "tinyrpc/net/tcp/tcp_client.h" 9 | #include "tinyrpc/comm/error_code.h" 10 | #include "tinyrpc/net/timer.h" 11 | #include "tinyrpc/net/fd_event.h" 12 | #include "tinyrpc/net/http/http_codec.h" 13 | #include "tinyrpc/net/tinypb/tinypb_codec.h" 14 | 15 | namespace tinyrpc { 16 | 17 | TcpClient::TcpClient(NetAddress::ptr addr, ProtocalType type /*= TinyPb_Protocal*/) : m_peer_addr(addr) { 18 | 19 | m_family = m_peer_addr->getFamily(); 20 | m_fd = socket(AF_INET, SOCK_STREAM, 0); 21 | if (m_fd == -1) { 22 | ErrorLog << "call socket error, fd=-1, sys error=" << strerror(errno); 23 | } 24 | DebugLog << "TcpClient() create fd = " << m_fd; 25 | m_local_addr = std::make_shared("127.0.0.1", 0); 26 | m_reactor = Reactor::GetReactor(); 27 | 28 | if (type == Http_Protocal) { 29 | m_codec = std::make_shared(); 30 | } else { 31 | m_codec = std::make_shared(); 32 | } 33 | 34 | m_connection = std::make_shared(this, m_reactor, m_fd, 128, m_peer_addr); 35 | 36 | } 37 | 38 | TcpClient::~TcpClient() { 39 | if (m_fd > 0) { 40 | FdEventContainer::GetFdContainer()->getFdEvent(m_fd)->unregisterFromReactor(); 41 | close(m_fd); 42 | DebugLog << "~TcpClient() close fd = " << m_fd; 43 | } 44 | } 45 | 46 | TcpConnection* TcpClient::getConnection() { 47 | if (!m_connection.get()) { 48 | m_connection = std::make_shared(this, m_reactor, m_fd, 128, m_peer_addr); 49 | } 50 | return m_connection.get(); 51 | } 52 | void TcpClient::resetFd() { 53 | tinyrpc::FdEvent::ptr fd_event = tinyrpc::FdEventContainer::GetFdContainer()->getFdEvent(m_fd); 54 | fd_event->unregisterFromReactor(); 55 | close(m_fd); 56 | m_fd = socket(AF_INET, SOCK_STREAM, 0); 57 | if (m_fd == -1) { 58 | ErrorLog << "call socket error, fd=-1, sys error=" << strerror(errno); 59 | } else { 60 | 61 | } 62 | } 63 | 64 | int TcpClient::sendAndRecvTinyPb(const std::string& msg_no, TinyPbStruct::pb_ptr& res) { 65 | bool is_timeout = false; 66 | tinyrpc::Coroutine* cur_cor = tinyrpc::Coroutine::GetCurrentCoroutine(); 67 | auto timer_cb = [this, &is_timeout, cur_cor]() { 68 | InfoLog << "TcpClient timer out event occur"; 69 | is_timeout = true; 70 | this->m_connection->setOverTimeFlag(true); 71 | tinyrpc::Coroutine::Resume(cur_cor); 72 | }; 73 | TimerEvent::ptr event = std::make_shared(m_max_timeout, false, timer_cb); 74 | m_reactor->getTimer()->addTimerEvent(event); 75 | 76 | DebugLog << "add rpc timer event, timeout on " << event->m_arrive_time; 77 | 78 | while (!is_timeout) { 79 | DebugLog << "begin to connect"; 80 | if (m_connection->getState() != Connected) { 81 | int rt = connect_hook(m_fd, reinterpret_cast(m_peer_addr->getSockAddr()), m_peer_addr->getSockLen()); 82 | if (rt == 0) { 83 | DebugLog << "connect [" << m_peer_addr->toString() << "] succ!"; 84 | m_connection->setUpClient(); 85 | break; 86 | } 87 | resetFd(); 88 | if (is_timeout) { 89 | InfoLog << "connect timeout, break"; 90 | goto err_deal; 91 | } 92 | if (errno == ECONNREFUSED) { 93 | std::stringstream ss; 94 | ss << "connect error, peer[ " << m_peer_addr->toString() << " ] closed."; 95 | m_err_info = ss.str(); 96 | ErrorLog << "cancle overtime event, err info=" << m_err_info; 97 | m_reactor->getTimer()->delTimerEvent(event); 98 | return ERROR_PEER_CLOSED; 99 | } 100 | if (errno == EAFNOSUPPORT) { 101 | std::stringstream ss; 102 | ss << "connect cur sys ror, errinfo is " << std::string(strerror(errno)) << " ] closed."; 103 | m_err_info = ss.str(); 104 | ErrorLog << "cancle overtime event, err info=" << m_err_info; 105 | m_reactor->getTimer()->delTimerEvent(event); 106 | return ERROR_CONNECT_SYS_ERR; 107 | 108 | } 109 | } else { 110 | break; 111 | } 112 | } 113 | 114 | if (m_connection->getState() != Connected) { 115 | std::stringstream ss; 116 | ss << "connect peer addr[" << m_peer_addr->toString() << "] error. sys error=" << strerror(errno); 117 | m_err_info = ss.str(); 118 | m_reactor->getTimer()->delTimerEvent(event); 119 | return ERROR_FAILED_CONNECT; 120 | } 121 | 122 | m_connection->setUpClient(); 123 | m_connection->output(); 124 | if (m_connection->getOverTimerFlag()) { 125 | InfoLog << "send data over time"; 126 | is_timeout = true; 127 | goto err_deal; 128 | } 129 | 130 | while (!m_connection->getResPackageData(msg_no, res)) { 131 | DebugLog << "redo getResPackageData"; 132 | m_connection->input(); 133 | 134 | if (m_connection->getOverTimerFlag()) { 135 | InfoLog << "read data over time"; 136 | is_timeout = true; 137 | goto err_deal; 138 | } 139 | if (m_connection->getState() == Closed) { 140 | InfoLog << "peer close"; 141 | goto err_deal; 142 | } 143 | 144 | m_connection->execute(); 145 | 146 | } 147 | 148 | m_reactor->getTimer()->delTimerEvent(event); 149 | m_err_info = ""; 150 | return 0; 151 | 152 | err_deal: 153 | // connect error should close fd and reopen new one 154 | FdEventContainer::GetFdContainer()->getFdEvent(m_fd)->unregisterFromReactor(); 155 | close(m_fd); 156 | m_fd = socket(AF_INET, SOCK_STREAM, 0); 157 | std::stringstream ss; 158 | if (is_timeout) { 159 | ss << "call rpc falied, over " << m_max_timeout << " ms"; 160 | m_err_info = ss.str(); 161 | 162 | m_connection->setOverTimeFlag(false); 163 | return ERROR_RPC_CALL_TIMEOUT; 164 | } else { 165 | ss << "call rpc falied, peer closed [" << m_peer_addr->toString() << "]"; 166 | m_err_info = ss.str(); 167 | return ERROR_PEER_CLOSED; 168 | } 169 | 170 | } 171 | 172 | void TcpClient::stop() { 173 | if (!m_is_stop) { 174 | m_is_stop = true; 175 | m_reactor->stop(); 176 | } 177 | } 178 | 179 | } // namespace name 180 | -------------------------------------------------------------------------------- /tinyrpc/net/tcp/tcp_client.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_TCP_TCP_CLIENT_H 2 | #define TINYRPC_NET_TCP_TCP_CLIENT_H 3 | 4 | #include 5 | #include 6 | #include "tinyrpc/coroutine/coroutine.h" 7 | #include "tinyrpc/coroutine/coroutine_hook.h" 8 | #include "tinyrpc/net/net_address.h" 9 | #include "tinyrpc/net/reactor.h" 10 | #include "tinyrpc/net/tcp/tcp_connection.h" 11 | #include "tinyrpc/net/abstract_codec.h" 12 | 13 | namespace tinyrpc { 14 | 15 | 16 | // 17 | // You should use TcpClient in a coroutine(not main coroutine) 18 | // 19 | class TcpClient { 20 | public: 21 | typedef std::shared_ptr ptr; 22 | 23 | TcpClient(NetAddress::ptr addr, ProtocalType type = TinyPb_Protocal); 24 | 25 | ~TcpClient(); 26 | 27 | void init(); 28 | 29 | void resetFd(); 30 | 31 | int sendAndRecvTinyPb(const std::string& msg_no, TinyPbStruct::pb_ptr& res); 32 | 33 | void stop(); 34 | 35 | TcpConnection* getConnection(); 36 | 37 | void setTimeout(const int v) { 38 | m_max_timeout = v; 39 | } 40 | 41 | void setTryCounts(const int v) { 42 | m_try_counts = v; 43 | } 44 | 45 | const std::string& getErrInfo() { 46 | return m_err_info; 47 | } 48 | 49 | NetAddress::ptr getPeerAddr() const { 50 | return m_peer_addr; 51 | } 52 | 53 | NetAddress::ptr getLocalAddr() const { 54 | return m_local_addr; 55 | } 56 | 57 | AbstractCodeC::ptr getCodeC() { 58 | return m_codec; 59 | } 60 | 61 | 62 | private: 63 | 64 | int m_family {0}; 65 | int m_fd {-1}; 66 | int m_try_counts {3}; // max try reconnect times 67 | int m_max_timeout {10000}; // max connect timeout, ms 68 | bool m_is_stop {false}; 69 | std::string m_err_info; // error info of client 70 | 71 | NetAddress::ptr m_local_addr {nullptr}; 72 | NetAddress::ptr m_peer_addr {nullptr}; 73 | Reactor* m_reactor {nullptr}; 74 | TcpConnection::ptr m_connection {nullptr}; 75 | 76 | AbstractCodeC::ptr m_codec {nullptr}; 77 | 78 | bool m_connect_succ {false}; 79 | 80 | }; 81 | 82 | } 83 | 84 | 85 | 86 | #endif -------------------------------------------------------------------------------- /tinyrpc/net/tcp/tcp_connection.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_TCP_TCP_CONNECTION_H 2 | #define TINYRPC_NET_TCP_TCP_CONNECTION_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "tinyrpc/comm/log.h" 8 | #include "tinyrpc/net/fd_event.h" 9 | #include "tinyrpc/net/reactor.h" 10 | #include "tinyrpc/net/tcp/tcp_buffer.h" 11 | #include "tinyrpc/coroutine/coroutine.h" 12 | #include "tinyrpc/net/http/http_request.h" 13 | #include "tinyrpc/net/tinypb/tinypb_codec.h" 14 | #include "tinyrpc/net/tcp/io_thread.h" 15 | #include "tinyrpc/net/tcp/tcp_connection_time_wheel.h" 16 | #include "tinyrpc/net/tcp/abstract_slot.h" 17 | #include "tinyrpc/net/net_address.h" 18 | #include "tinyrpc/net/mutex.h" 19 | 20 | namespace tinyrpc { 21 | 22 | class TcpServer; 23 | class TcpClient; 24 | class IOThread; 25 | 26 | enum TcpConnectionState { 27 | NotConnected = 1, // can do io 28 | Connected = 2, // can do io 29 | HalfClosing = 3, // server call shutdown, write half close. can read,but can't write 30 | Closed = 4, // can't do io 31 | }; 32 | 33 | 34 | class TcpConnection : public std::enable_shared_from_this { 35 | 36 | public: 37 | typedef std::shared_ptr ptr; 38 | 39 | TcpConnection(tinyrpc::TcpServer* tcp_svr, tinyrpc::IOThread* io_thread, int fd, int buff_size, NetAddress::ptr peer_addr); 40 | 41 | TcpConnection(tinyrpc::TcpClient* tcp_cli, tinyrpc::Reactor* reactor, int fd, int buff_size, NetAddress::ptr peer_addr); 42 | 43 | void setUpClient(); 44 | 45 | void setUpServer(); 46 | 47 | ~TcpConnection(); 48 | 49 | void initBuffer(int size); 50 | 51 | enum ConnectionType { 52 | ServerConnection = 1, // owned by tcp_server 53 | ClientConnection = 2, // owned by tcp_client 54 | }; 55 | 56 | public: 57 | 58 | 59 | void shutdownConnection(); 60 | 61 | TcpConnectionState getState(); 62 | 63 | void setState(const TcpConnectionState& state); 64 | 65 | TcpBuffer* getInBuffer(); 66 | 67 | TcpBuffer* getOutBuffer(); 68 | 69 | AbstractCodeC::ptr getCodec() const; 70 | 71 | bool getResPackageData(const std::string& msg_req, TinyPbStruct::pb_ptr& pb_struct); 72 | 73 | void registerToTimeWheel(); 74 | 75 | Coroutine::ptr getCoroutine(); 76 | 77 | public: 78 | void MainServerLoopCorFunc(); 79 | 80 | void input(); 81 | 82 | void execute(); 83 | 84 | void output(); 85 | 86 | void setOverTimeFlag(bool value); 87 | 88 | bool getOverTimerFlag(); 89 | 90 | void initServer(); 91 | 92 | private: 93 | void clearClient(); 94 | 95 | private: 96 | TcpServer* m_tcp_svr {nullptr}; 97 | TcpClient* m_tcp_cli {nullptr}; 98 | IOThread* m_io_thread {nullptr}; 99 | Reactor* m_reactor {nullptr}; 100 | 101 | int m_fd {-1}; 102 | TcpConnectionState m_state {TcpConnectionState::Connected}; 103 | ConnectionType m_connection_type {ServerConnection}; 104 | 105 | NetAddress::ptr m_peer_addr; 106 | 107 | 108 | TcpBuffer::ptr m_read_buffer; 109 | TcpBuffer::ptr m_write_buffer; 110 | 111 | Coroutine::ptr m_loop_cor; 112 | 113 | AbstractCodeC::ptr m_codec; 114 | 115 | FdEvent::ptr m_fd_event; 116 | 117 | bool m_stop {false}; 118 | 119 | bool m_is_over_time {false}; 120 | 121 | std::map> m_reply_datas; 122 | 123 | std::weak_ptr> m_weak_slot; 124 | 125 | RWMutex m_mutex; 126 | 127 | }; 128 | 129 | } 130 | 131 | #endif 132 | -------------------------------------------------------------------------------- /tinyrpc/net/tcp/tcp_connection_time_wheel.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "tinyrpc/net/tcp/abstract_slot.h" 4 | #include "tinyrpc/net/tcp/tcp_connection.h" 5 | #include "tinyrpc/net/tcp/tcp_connection_time_wheel.h" 6 | #include "tinyrpc/net/timer.h" 7 | 8 | namespace tinyrpc { 9 | 10 | TcpTimeWheel::TcpTimeWheel(Reactor* reactor, int bucket_count, int inteval /*= 10*/) 11 | : m_reactor(reactor) 12 | , m_bucket_count(bucket_count) 13 | , m_inteval(inteval) { 14 | 15 | for (int i = 0; i < bucket_count; ++i) { 16 | std::vector tmp; 17 | m_wheel.push(tmp); 18 | } 19 | 20 | m_event = std::make_shared(m_inteval * 1000, true, std::bind(&TcpTimeWheel::loopFunc, this)); 21 | m_reactor->getTimer()->addTimerEvent(m_event); 22 | } 23 | 24 | 25 | TcpTimeWheel::~TcpTimeWheel() { 26 | m_reactor->getTimer()->delTimerEvent(m_event); 27 | } 28 | 29 | void TcpTimeWheel::loopFunc() { 30 | // DebugLog << "pop src bucket"; 31 | m_wheel.pop(); 32 | std::vector tmp; 33 | m_wheel.push(tmp); 34 | // DebugLog << "push new bucket"; 35 | } 36 | 37 | void TcpTimeWheel::fresh(TcpConnectionSlot::ptr slot) { 38 | DebugLog << "fresh connection"; 39 | m_wheel.back().emplace_back(slot); 40 | } 41 | 42 | 43 | } -------------------------------------------------------------------------------- /tinyrpc/net/tcp/tcp_connection_time_wheel.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_TCP_TCPCONNECTIONTIMEWHEEL_H 2 | #define TINYRPC_NET_TCP_TCPCONNECTIONTIMEWHEEL_H 3 | 4 | #include 5 | #include 6 | #include "tinyrpc/net/tcp/abstract_slot.h" 7 | #include "tinyrpc/net/reactor.h" 8 | #include "tinyrpc/net/timer.h" 9 | 10 | namespace tinyrpc { 11 | 12 | class TcpConnection; 13 | 14 | class TcpTimeWheel { 15 | 16 | public: 17 | typedef std::shared_ptr ptr; 18 | 19 | typedef AbstractSlot TcpConnectionSlot; 20 | 21 | TcpTimeWheel(Reactor* reactor, int bucket_count, int invetal = 10); 22 | 23 | ~TcpTimeWheel(); 24 | 25 | void fresh(TcpConnectionSlot::ptr slot); 26 | 27 | void loopFunc(); 28 | 29 | 30 | private: 31 | Reactor* m_reactor {nullptr}; 32 | int m_bucket_count {0}; 33 | int m_inteval {0}; // second 34 | 35 | TimerEvent::ptr m_event; 36 | std::queue> m_wheel; 37 | }; 38 | 39 | 40 | } 41 | 42 | 43 | 44 | 45 | 46 | #endif -------------------------------------------------------------------------------- /tinyrpc/net/tcp/tcp_server.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_TCP_TCP_SERVER_H 2 | #define TINYRPC_NET_TCP_TCP_SERVER_H 3 | 4 | #include 5 | #include 6 | #include "tinyrpc/net/reactor.h" 7 | #include "tinyrpc/net/fd_event.h" 8 | #include "tinyrpc/net/timer.h" 9 | #include "tinyrpc/net/net_address.h" 10 | #include "tinyrpc/net/tcp/tcp_connection.h" 11 | #include "tinyrpc/net/tcp/io_thread.h" 12 | #include "tinyrpc/net/tcp/tcp_connection_time_wheel.h" 13 | #include "tinyrpc/net/abstract_codec.h" 14 | #include "tinyrpc/net/abstract_dispatcher.h" 15 | #include "tinyrpc/net/http/http_dispatcher.h" 16 | #include "tinyrpc/net/http/http_servlet.h" 17 | 18 | 19 | namespace tinyrpc { 20 | 21 | class TcpAcceptor { 22 | 23 | public: 24 | 25 | typedef std::shared_ptr ptr; 26 | TcpAcceptor(NetAddress::ptr net_addr); 27 | 28 | void init(); 29 | 30 | int toAccept(); 31 | 32 | ~TcpAcceptor(); 33 | 34 | NetAddress::ptr getPeerAddr() { 35 | return m_peer_addr; 36 | } 37 | 38 | NetAddress::ptr geLocalAddr() { 39 | return m_local_addr; 40 | } 41 | 42 | private: 43 | int m_family {-1}; 44 | int m_fd {-1}; 45 | 46 | NetAddress::ptr m_local_addr {nullptr}; 47 | NetAddress::ptr m_peer_addr {nullptr}; 48 | 49 | }; 50 | 51 | 52 | class TcpServer { 53 | 54 | public: 55 | 56 | typedef std::shared_ptr ptr; 57 | 58 | TcpServer(NetAddress::ptr addr, ProtocalType type = TinyPb_Protocal); 59 | 60 | ~TcpServer(); 61 | 62 | void start(); 63 | 64 | void addCoroutine(tinyrpc::Coroutine::ptr cor); 65 | 66 | bool registerService(std::shared_ptr service); 67 | 68 | bool registerHttpServlet(const std::string& url_path, HttpServlet::ptr servlet); 69 | 70 | TcpConnection::ptr addClient(IOThread* io_thread, int fd); 71 | 72 | void freshTcpConnection(TcpTimeWheel::TcpConnectionSlot::ptr slot); 73 | 74 | 75 | public: 76 | AbstractDispatcher::ptr getDispatcher(); 77 | 78 | AbstractCodeC::ptr getCodec(); 79 | 80 | NetAddress::ptr getPeerAddr(); 81 | 82 | NetAddress::ptr getLocalAddr(); 83 | 84 | IOThreadPool::ptr getIOThreadPool(); 85 | 86 | TcpTimeWheel::ptr getTimeWheel(); 87 | 88 | 89 | private: 90 | void MainAcceptCorFunc(); 91 | 92 | void ClearClientTimerFunc(); 93 | 94 | private: 95 | 96 | NetAddress::ptr m_addr; 97 | 98 | TcpAcceptor::ptr m_acceptor; 99 | 100 | int m_tcp_counts {0}; 101 | 102 | Reactor* m_main_reactor {nullptr}; 103 | 104 | bool m_is_stop_accept {false}; 105 | 106 | Coroutine::ptr m_accept_cor; 107 | 108 | AbstractDispatcher::ptr m_dispatcher; 109 | 110 | AbstractCodeC::ptr m_codec; 111 | 112 | IOThreadPool::ptr m_io_pool; 113 | 114 | ProtocalType m_protocal_type {TinyPb_Protocal}; 115 | 116 | TcpTimeWheel::ptr m_time_wheel; 117 | 118 | std::map> m_clients; 119 | 120 | TimerEvent::ptr m_clear_clent_timer_event {nullptr}; 121 | 122 | }; 123 | 124 | } 125 | 126 | #endif 127 | -------------------------------------------------------------------------------- /tinyrpc/net/timer.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "../comm/log.h" 10 | #include "timer.h" 11 | #include "mutex.h" 12 | #include "fd_event.h" 13 | #include "../coroutine/coroutine_hook.h" 14 | 15 | 16 | extern read_fun_ptr_t g_sys_read_fun; // sys read func 17 | 18 | namespace tinyrpc { 19 | 20 | 21 | int64_t getNowMs() { 22 | timeval val; 23 | gettimeofday(&val, nullptr); 24 | int64_t re = val.tv_sec * 1000 + val.tv_usec / 1000; 25 | return re; 26 | } 27 | 28 | Timer::Timer(Reactor* reactor) : FdEvent(reactor) { 29 | 30 | m_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC); 31 | DebugLog << "m_timer fd = " << m_fd; 32 | if (m_fd == -1) { 33 | DebugLog << "timerfd_create error"; 34 | } 35 | // DebugLog << "timerfd is [" << m_fd << "]"; 36 | m_read_callback = std::bind(&Timer::onTimer, this); 37 | addListenEvents(READ); 38 | // updateToReactor(); 39 | 40 | } 41 | 42 | Timer::~Timer() { 43 | unregisterFromReactor(); 44 | close(m_fd); 45 | } 46 | 47 | 48 | void Timer::addTimerEvent(TimerEvent::ptr event, bool need_reset /*=true*/) { 49 | RWMutex::WriteLock lock(m_event_mutex); 50 | bool is_reset = false; 51 | if (m_pending_events.empty()) { 52 | is_reset = true; 53 | } else { 54 | auto it = m_pending_events.begin(); 55 | if (event->m_arrive_time < (*it).second->m_arrive_time) { 56 | is_reset = true; 57 | } 58 | } 59 | m_pending_events.emplace(event->m_arrive_time, event); 60 | lock.unlock(); 61 | 62 | if (is_reset && need_reset) { 63 | DebugLog << "need reset timer"; 64 | resetArriveTime(); 65 | } 66 | // DebugLog << "add timer event succ"; 67 | } 68 | 69 | void Timer::delTimerEvent(TimerEvent::ptr event) { 70 | event->m_is_cancled = true; 71 | 72 | RWMutex::WriteLock lock(m_event_mutex); 73 | auto begin = m_pending_events.lower_bound(event->m_arrive_time); 74 | auto end = m_pending_events.upper_bound(event->m_arrive_time); 75 | auto it = begin; 76 | for (it = begin; it != end; it++) { 77 | if (it->second == event) { 78 | DebugLog << "find timer event, now delete it. src arrive time=" << event->m_arrive_time; 79 | break; 80 | } 81 | } 82 | if (it != m_pending_events.end()) { 83 | m_pending_events.erase(it); 84 | } 85 | lock.unlock(); 86 | DebugLog << "del timer event succ, origin arrvite time=" << event->m_arrive_time; 87 | } 88 | 89 | void Timer::resetArriveTime() { 90 | RWMutex::ReadLock lock(m_event_mutex); 91 | std::multimap tmp = m_pending_events; 92 | lock.unlock(); 93 | 94 | if (tmp.size() == 0) { 95 | DebugLog << "no timerevent pending, size = 0"; 96 | return; 97 | } 98 | 99 | int64_t now = getNowMs(); 100 | auto it = tmp.rbegin(); 101 | if ((*it).first < now) { 102 | DebugLog<< "all timer events has already expire"; 103 | return; 104 | } 105 | int64_t interval = (*it).first - now; 106 | 107 | itimerspec new_value; 108 | memset(&new_value, 0, sizeof(new_value)); 109 | 110 | timespec ts; 111 | memset(&ts, 0, sizeof(ts)); 112 | ts.tv_sec = interval / 1000; 113 | ts.tv_nsec = (interval % 1000) * 1000000; 114 | new_value.it_value = ts; 115 | 116 | int rt = timerfd_settime(m_fd, 0, &new_value, nullptr); 117 | 118 | if (rt != 0) { 119 | ErrorLog << "tiemr_settime error, interval=" << interval; 120 | } else { 121 | // DebugLog << "reset timer succ, next occur time=" << (*it).first; 122 | } 123 | 124 | } 125 | 126 | void Timer::onTimer() { 127 | 128 | // DebugLog << "onTimer, first read data"; 129 | char buf[8]; 130 | while(1) { 131 | if((g_sys_read_fun(m_fd, buf, 8) == -1) && errno == EAGAIN) { 132 | break; 133 | } 134 | } 135 | 136 | int64_t now = getNowMs(); 137 | RWMutex::WriteLock lock(m_event_mutex); 138 | auto it = m_pending_events.begin(); 139 | std::vector tmps; 140 | std::vector>> tasks; 141 | for (it = m_pending_events.begin(); it != m_pending_events.end(); ++it) { 142 | if ((*it).first <= now && !((*it).second->m_is_cancled)) { 143 | tmps.push_back((*it).second); 144 | tasks.push_back(std::make_pair((*it).second->m_arrive_time, (*it).second->m_task)); 145 | } else { 146 | break; 147 | } 148 | } 149 | 150 | m_pending_events.erase(m_pending_events.begin(), it); 151 | lock.unlock(); 152 | 153 | for (auto i = tmps.begin(); i != tmps.end(); ++i) { 154 | // DebugLog << "excute timer event on " << (*i)->m_arrive_time; 155 | if ((*i)->m_is_repeated) { 156 | (*i)->resetTime(); 157 | addTimerEvent(*i, false); 158 | } 159 | } 160 | 161 | resetArriveTime(); 162 | 163 | // m_reactor->addTask(tasks); 164 | for (auto i : tasks) { 165 | // DebugLog << "excute timeevent:" << i.first; 166 | i.second(); 167 | } 168 | } 169 | 170 | } 171 | 172 | 173 | -------------------------------------------------------------------------------- /tinyrpc/net/timer.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_TIMER_H 2 | #define TINYRPC_NET_TIMER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "tinyrpc/net/mutex.h" 9 | #include "tinyrpc/net/reactor.h" 10 | #include "tinyrpc/net/fd_event.h" 11 | #include "tinyrpc/comm/log.h" 12 | 13 | 14 | namespace tinyrpc { 15 | 16 | int64_t getNowMs(); 17 | 18 | 19 | class TimerEvent { 20 | 21 | public: 22 | 23 | typedef std::shared_ptr ptr; 24 | TimerEvent(int64_t interval, bool is_repeated, std::functiontask) 25 | : m_interval(interval), m_is_repeated(is_repeated), m_task(task) { 26 | m_arrive_time = getNowMs() + m_interval; 27 | DebugLog << "timeevent will occur at " << m_arrive_time; 28 | } 29 | 30 | void resetTime() { 31 | // DebugLog << "reset tiemrevent, origin arrivetime=" << m_arrive_time; 32 | m_arrive_time = getNowMs() + m_interval; 33 | // DebugLog << "reset tiemrevent, now arrivetime=" << m_arrive_time; 34 | m_is_cancled = false; 35 | } 36 | 37 | void wake() { 38 | m_is_cancled = false; 39 | } 40 | 41 | void cancle () { 42 | m_is_cancled = true; 43 | } 44 | 45 | void cancleRepeated () { 46 | m_is_repeated = false; 47 | } 48 | 49 | public: 50 | int64_t m_arrive_time; // when to excute task, ms 51 | int64_t m_interval; // interval between two tasks, ms 52 | bool m_is_repeated {false}; 53 | bool m_is_cancled {false}; 54 | std::function m_task; 55 | 56 | }; 57 | 58 | class FdEvent; 59 | 60 | class Timer : public tinyrpc::FdEvent { 61 | 62 | public: 63 | 64 | typedef std::shared_ptr ptr; 65 | 66 | Timer(Reactor* reactor); 67 | 68 | ~Timer(); 69 | 70 | void addTimerEvent(TimerEvent::ptr event, bool need_reset = true); 71 | 72 | void delTimerEvent(TimerEvent::ptr event); 73 | 74 | void resetArriveTime(); 75 | 76 | void onTimer(); 77 | 78 | private: 79 | 80 | std::multimap m_pending_events; 81 | RWMutex m_event_mutex; 82 | 83 | 84 | }; 85 | 86 | 87 | 88 | } 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /tinyrpc/net/tinypb/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(HEADERS 2 | tinypb_codec.h 3 | tinypb_rpc_closure.h 4 | tinypb_data.h 5 | tinypb_rpc_controller.h 6 | tinypb_rpc_async_channel.h 7 | tinypb_rpc_dispatcher.h 8 | tinypb_rpc_channel.h 9 | ) 10 | 11 | install(FILES ${HEADERS} DESTINATION include/tinyrpc/net/tinypb) -------------------------------------------------------------------------------- /tinyrpc/net/tinypb/tinypb_codec.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_TINYPB_TINYPB_CODEC_H 2 | #define TINYRPC_NET_TINYPB_TINYPB_CODEC_H 3 | 4 | #include 5 | #include "tinyrpc/net/abstract_codec.h" 6 | #include "tinyrpc/net/abstract_data.h" 7 | #include "tinyrpc/net/tinypb/tinypb_data.h" 8 | 9 | namespace tinyrpc { 10 | 11 | 12 | class TinyPbCodeC: public AbstractCodeC { 13 | public: 14 | // typedef std::shared_ptr ptr; 15 | 16 | TinyPbCodeC(); 17 | 18 | ~TinyPbCodeC (); 19 | 20 | // overwrite 21 | void encode(TcpBuffer* buf, AbstractData* data); 22 | 23 | // overwrite 24 | void decode(TcpBuffer* buf, AbstractData* data); 25 | 26 | // overwrite 27 | virtual ProtocalType getProtocalType(); 28 | 29 | const char* encodePbData(TinyPbStruct* data, int& len); 30 | 31 | 32 | }; 33 | 34 | } 35 | 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /tinyrpc/net/tinypb/tinypb_data.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_TINYPB_TINYPB_DATA_H 2 | #define TINYRPC_NET_TINYPB_TINYPB_DATA_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "tinyrpc/net/abstract_data.h" 8 | #include "tinyrpc/comm/log.h" 9 | 10 | namespace tinyrpc { 11 | 12 | class TinyPbStruct : public AbstractData { 13 | public: 14 | typedef std::shared_ptr pb_ptr; 15 | TinyPbStruct() = default; 16 | ~TinyPbStruct() = default; 17 | TinyPbStruct(const TinyPbStruct& ) = default; 18 | TinyPbStruct& operator=(const TinyPbStruct& ) = default; 19 | TinyPbStruct(TinyPbStruct&&) = default; 20 | TinyPbStruct& operator=(TinyPbStruct&&) = default; 21 | 22 | /* 23 | ** min of package is: 1 + 4 + 4 + 4 + 4 + 4 + 4 + 1 = 26 bytes 24 | ** 25 | */ 26 | 27 | // char start; // indentify start of a TinyPb protocal data 28 | int32_t pk_len {0}; // len of all package(include start char and end char) 29 | int32_t msg_req_len {0}; // len of msg_req 30 | std::string msg_req; // msg_req, which identify a request 31 | int32_t service_name_len {0}; // len of service full name 32 | std::string service_full_name; // service full name, like QueryService.query_name 33 | int32_t err_code {0}; // err_code, 0 -- call rpc success, otherwise -- call rpc failed. it only be seted by RpcController 34 | int32_t err_info_len {0}; // len of err_info 35 | std::string err_info; // err_info, empty -- call rpc success, otherwise -- call rpc failed, it will display details of reason why call rpc failed. it only be seted by RpcController 36 | std::string pb_data; // business pb data 37 | int32_t check_num {-1}; // check_num of all package. to check legality of data 38 | // char end; // identify end of a TinyPb protocal data 39 | 40 | }; 41 | 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /tinyrpc/net/tinypb/tinypb_rpc_async_channel.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "tinyrpc/net/net_address.h" 7 | #include "tinyrpc/net/tcp/io_thread.h" 8 | #include "tinyrpc/comm/error_code.h" 9 | #include "tinyrpc/net/tcp/tcp_client.h" 10 | #include "tinyrpc/net/tinypb/tinypb_rpc_async_channel.h" 11 | #include "tinyrpc/net/tinypb/tinypb_rpc_channel.h" 12 | #include "tinyrpc/net/tinypb/tinypb_rpc_controller.h" 13 | #include "tinyrpc/net/tinypb/tinypb_codec.h" 14 | #include "tinyrpc/net/tinypb/tinypb_data.h" 15 | #include "tinyrpc/comm/log.h" 16 | #include "tinyrpc/comm/start.h" 17 | #include "tinyrpc/comm/run_time.h" 18 | #include "tinyrpc/comm/msg_req.h" 19 | #include "tinyrpc/coroutine/coroutine_pool.h" 20 | #include "tinyrpc/coroutine/coroutine.h" 21 | 22 | 23 | namespace tinyrpc { 24 | 25 | TinyPbRpcAsyncChannel::TinyPbRpcAsyncChannel(NetAddress::ptr addr) { 26 | m_rpc_channel = std::make_shared(addr); 27 | m_current_iothread = IOThread::GetCurrentIOThread(); 28 | m_current_cor = Coroutine::GetCurrentCoroutine(); 29 | } 30 | 31 | TinyPbRpcAsyncChannel::~TinyPbRpcAsyncChannel() { 32 | // DebugLog << "~TinyPbRpcAsyncChannel(), return coroutine"; 33 | GetCoroutinePool()->returnCoroutine(m_pending_cor); 34 | } 35 | 36 | TinyPbRpcChannel* TinyPbRpcAsyncChannel::getRpcChannel() { 37 | return m_rpc_channel.get(); 38 | } 39 | 40 | void TinyPbRpcAsyncChannel::saveCallee(con_ptr controller, msg_ptr req, msg_ptr res, clo_ptr closure) { 41 | m_controller = controller; 42 | m_req = req; 43 | m_res = res; 44 | m_closure = closure; 45 | m_is_pre_set = true; 46 | } 47 | 48 | void TinyPbRpcAsyncChannel::CallMethod(const google::protobuf::MethodDescriptor* method, 49 | google::protobuf::RpcController* controller, 50 | const google::protobuf::Message* request, 51 | google::protobuf::Message* response, 52 | google::protobuf::Closure* done) { 53 | 54 | TinyPbRpcController* rpc_controller = dynamic_cast(controller); 55 | if (!m_is_pre_set) { 56 | ErrorLog << "Error! must call [saveCallee()] function before [CallMethod()]"; 57 | TinyPbRpcController* rpc_controller = dynamic_cast(controller); 58 | rpc_controller->SetError(ERROR_NOT_SET_ASYNC_PRE_CALL, "Error! must call [saveCallee()] function before [CallMethod()];"); 59 | m_is_finished = true; 60 | return; 61 | } 62 | RunTime* run_time = getCurrentRunTime(); 63 | if (run_time) { 64 | rpc_controller->SetMsgReq(run_time->m_msg_no); 65 | DebugLog << "get from RunTime succ, msgno=" << run_time->m_msg_no; 66 | } else { 67 | rpc_controller->SetMsgReq(MsgReqUtil::genMsgNumber()); 68 | DebugLog << "get from RunTime error, generate new msgno=" << rpc_controller->MsgSeq(); 69 | } 70 | 71 | std::shared_ptr s_ptr = shared_from_this(); 72 | 73 | auto cb = [s_ptr, method]() mutable { 74 | DebugLog << "now excute rpc call method by this thread"; 75 | s_ptr->getRpcChannel()->CallMethod(method, s_ptr->getControllerPtr(), s_ptr->getRequestPtr(), s_ptr->getResponsePtr(), NULL); 76 | 77 | DebugLog << "excute rpc call method by this thread finish"; 78 | 79 | auto call_back = [s_ptr]() mutable { 80 | DebugLog << "async excute rpc call method back old thread"; 81 | // callback function excute in origin thread 82 | if (s_ptr->getClosurePtr() != nullptr) { 83 | s_ptr->getClosurePtr()->Run(); 84 | } 85 | s_ptr->setFinished(true); 86 | 87 | if (s_ptr->getNeedResume()) { 88 | DebugLog << "async excute rpc call method back old thread, need resume"; 89 | Coroutine::Resume(s_ptr->getCurrentCoroutine()); 90 | } 91 | s_ptr.reset(); 92 | }; 93 | 94 | s_ptr->getIOThread()->getReactor()->addTask(call_back, true); 95 | s_ptr.reset(); 96 | }; 97 | m_pending_cor = GetServer()->getIOThreadPool()->addCoroutineToRandomThread(cb, false); 98 | 99 | } 100 | 101 | void TinyPbRpcAsyncChannel::wait() { 102 | m_need_resume = true; 103 | if (m_is_finished) { 104 | return; 105 | } 106 | Coroutine::Yield(); 107 | } 108 | 109 | void TinyPbRpcAsyncChannel::setFinished(bool value) { 110 | m_is_finished = true; 111 | } 112 | 113 | IOThread* TinyPbRpcAsyncChannel::getIOThread() { 114 | return m_current_iothread; 115 | } 116 | 117 | Coroutine* TinyPbRpcAsyncChannel::getCurrentCoroutine() { 118 | return m_current_cor; 119 | } 120 | 121 | bool TinyPbRpcAsyncChannel::getNeedResume() { 122 | return m_need_resume; 123 | } 124 | 125 | google::protobuf::RpcController* TinyPbRpcAsyncChannel::getControllerPtr() { 126 | return m_controller.get(); 127 | } 128 | 129 | google::protobuf::Message* TinyPbRpcAsyncChannel::getRequestPtr() { 130 | return m_req.get(); 131 | } 132 | 133 | google::protobuf::Message* TinyPbRpcAsyncChannel::getResponsePtr() { 134 | return m_res.get(); 135 | } 136 | 137 | google::protobuf::Closure* TinyPbRpcAsyncChannel::getClosurePtr() { 138 | return m_closure.get(); 139 | } 140 | 141 | } -------------------------------------------------------------------------------- /tinyrpc/net/tinypb/tinypb_rpc_async_channel.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_TINYPB_TINYPB_RPC_ASYNC_CHANNEL_H 2 | #define TINYRPC_NET_TINYPB_TINYPB_RPC_ASYNC_CHANNEL_H 3 | 4 | #include 5 | #include 6 | #include "tinyrpc/net/tinypb/tinypb_data.h" 7 | #include "tinyrpc/net/tinypb/tinypb_rpc_channel.h" 8 | #include "tinyrpc/net/tinypb/tinypb_rpc_controller.h" 9 | #include "tinyrpc/net/net_address.h" 10 | #include "tinyrpc/net/tcp/tcp_client.h" 11 | #include "tinyrpc/coroutine/coroutine.h" 12 | 13 | namespace tinyrpc { 14 | 15 | class TinyPbRpcAsyncChannel : public google::protobuf::RpcChannel , public std::enable_shared_from_this { 16 | 17 | public: 18 | typedef std::shared_ptr ptr; 19 | typedef std::shared_ptr con_ptr; 20 | typedef std::shared_ptr msg_ptr; 21 | typedef std::shared_ptr clo_ptr; 22 | 23 | TinyPbRpcAsyncChannel(NetAddress::ptr addr); 24 | ~TinyPbRpcAsyncChannel(); 25 | 26 | void CallMethod(const google::protobuf::MethodDescriptor* method, 27 | google::protobuf::RpcController* controller, 28 | const google::protobuf::Message* request, 29 | google::protobuf::Message* response, 30 | google::protobuf::Closure* done); 31 | 32 | 33 | TinyPbRpcChannel* getRpcChannel(); 34 | 35 | // must call saveCallee before CallMethod 36 | // in order to save shared_ptr count of req res controller 37 | void saveCallee(con_ptr controller, msg_ptr req, msg_ptr res, clo_ptr closure); 38 | 39 | void wait(); 40 | 41 | void setFinished(bool value); 42 | 43 | bool getNeedResume(); 44 | 45 | IOThread* getIOThread(); 46 | 47 | Coroutine* getCurrentCoroutine(); 48 | 49 | google::protobuf::RpcController* getControllerPtr(); 50 | 51 | google::protobuf::Message* getRequestPtr(); 52 | 53 | google::protobuf::Message* getResponsePtr(); 54 | 55 | google::protobuf::Closure* getClosurePtr(); 56 | 57 | 58 | private: 59 | TinyPbRpcChannel::ptr m_rpc_channel; 60 | Coroutine::ptr m_pending_cor; 61 | Coroutine* m_current_cor {NULL}; 62 | IOThread* m_current_iothread {NULL}; 63 | bool m_is_finished {false}; 64 | bool m_need_resume {false}; 65 | bool m_is_pre_set {false}; 66 | 67 | private: 68 | con_ptr m_controller; 69 | msg_ptr m_req; 70 | msg_ptr m_res; 71 | clo_ptr m_closure; 72 | 73 | }; 74 | 75 | } 76 | 77 | 78 | 79 | #endif -------------------------------------------------------------------------------- /tinyrpc/net/tinypb/tinypb_rpc_channel.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "tinyrpc/net/net_address.h" 6 | #include "tinyrpc/comm/error_code.h" 7 | #include "tinyrpc/net/tcp/tcp_client.h" 8 | #include "tinyrpc/net/tinypb/tinypb_rpc_channel.h" 9 | #include "tinyrpc/net/tinypb/tinypb_rpc_controller.h" 10 | #include "tinyrpc/net/tinypb/tinypb_codec.h" 11 | #include "tinyrpc/net/tinypb/tinypb_data.h" 12 | #include "tinyrpc/comm/log.h" 13 | #include "tinyrpc/comm/msg_req.h" 14 | #include "tinyrpc/comm/run_time.h" 15 | 16 | 17 | namespace tinyrpc { 18 | 19 | TinyPbRpcChannel::TinyPbRpcChannel(NetAddress::ptr addr) : m_addr(addr) { 20 | 21 | } 22 | 23 | void TinyPbRpcChannel::CallMethod(const google::protobuf::MethodDescriptor* method, 24 | google::protobuf::RpcController* controller, 25 | const google::protobuf::Message* request, 26 | google::protobuf::Message* response, 27 | google::protobuf::Closure* done) { 28 | 29 | TinyPbStruct pb_struct; 30 | TinyPbRpcController* rpc_controller = dynamic_cast(controller); 31 | if (!rpc_controller) { 32 | ErrorLog << "call failed. falid to dynamic cast TinyPbRpcController"; 33 | return; 34 | } 35 | 36 | TcpClient::ptr m_client = std::make_shared(m_addr); 37 | rpc_controller->SetLocalAddr(m_client->getLocalAddr()); 38 | rpc_controller->SetPeerAddr(m_client->getPeerAddr()); 39 | 40 | pb_struct.service_full_name = method->full_name(); 41 | DebugLog << "call service_name = " << pb_struct.service_full_name; 42 | if (!request->SerializeToString(&(pb_struct.pb_data))) { 43 | ErrorLog << "serialize send package error"; 44 | return; 45 | } 46 | 47 | if (!rpc_controller->MsgSeq().empty()) { 48 | pb_struct.msg_req = rpc_controller->MsgSeq(); 49 | } else { 50 | // get current coroutine's msgno to set this request 51 | RunTime* run_time = getCurrentRunTime(); 52 | if(run_time != NULL && !run_time->m_msg_no.empty()) { 53 | pb_struct.msg_req = run_time->m_msg_no; 54 | DebugLog << "get from RunTime succ, msgno = " << pb_struct.msg_req; 55 | } else { 56 | pb_struct.msg_req = MsgReqUtil::genMsgNumber(); 57 | DebugLog << "get from RunTime error, generate new msgno = " << pb_struct.msg_req; 58 | } 59 | rpc_controller->SetMsgReq(pb_struct.msg_req); 60 | } 61 | 62 | AbstractCodeC::ptr m_codec = m_client->getConnection()->getCodec(); 63 | m_codec->encode(m_client->getConnection()->getOutBuffer(), &pb_struct); 64 | if (!pb_struct.encode_succ) { 65 | rpc_controller->SetError(ERROR_FAILED_ENCODE, "encode tinypb data error"); 66 | return; 67 | } 68 | 69 | InfoLog << "============================================================"; 70 | InfoLog << pb_struct.msg_req << "|" << rpc_controller->PeerAddr()->toString() 71 | << "|. Set client send request data:" << request->ShortDebugString(); 72 | InfoLog << "============================================================"; 73 | m_client->setTimeout(rpc_controller->Timeout()); 74 | 75 | TinyPbStruct::pb_ptr res_data; 76 | int rt = m_client->sendAndRecvTinyPb(pb_struct.msg_req, res_data); 77 | if (rt != 0) { 78 | rpc_controller->SetError(rt, m_client->getErrInfo()); 79 | ErrorLog << pb_struct.msg_req << "|call rpc occur client error, service_full_name=" << pb_struct.service_full_name << ", error_code=" 80 | << rt << ", error_info = " << m_client->getErrInfo(); 81 | return; 82 | } 83 | 84 | if (!response->ParseFromString(res_data->pb_data)) { 85 | rpc_controller->SetError(ERROR_FAILED_DESERIALIZE, "failed to deserialize data from server"); 86 | ErrorLog << pb_struct.msg_req << "|failed to deserialize data"; 87 | return; 88 | } 89 | if (res_data->err_code != 0) { 90 | ErrorLog << pb_struct.msg_req << "|server reply error_code=" << res_data->err_code << ", err_info=" << res_data->err_info; 91 | rpc_controller->SetError(res_data->err_code, res_data->err_info); 92 | return; 93 | } 94 | 95 | InfoLog<< "============================================================"; 96 | InfoLog<< pb_struct.msg_req << "|" << rpc_controller->PeerAddr()->toString() 97 | << "|call rpc server [" << pb_struct.service_full_name << "] succ" 98 | << ". Get server reply response data:" << response->ShortDebugString(); 99 | InfoLog<< "============================================================"; 100 | 101 | // excute callback function 102 | if (done) { 103 | done->Run(); 104 | } 105 | } 106 | 107 | 108 | } -------------------------------------------------------------------------------- /tinyrpc/net/tinypb/tinypb_rpc_channel.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_TINYPB_TINYPB_RPC_CHANNEL_H 2 | #define TINYRPC_NET_TINYPB_TINYPB_RPC_CHANNEL_H 3 | 4 | #include 5 | #include 6 | #include "tinyrpc/net/net_address.h" 7 | #include "tinyrpc/net//tcp/tcp_client.h" 8 | 9 | namespace tinyrpc { 10 | 11 | class TinyPbRpcChannel : public google::protobuf::RpcChannel { 12 | 13 | public: 14 | typedef std::shared_ptr ptr; 15 | TinyPbRpcChannel(NetAddress::ptr addr); 16 | ~TinyPbRpcChannel() = default; 17 | 18 | void CallMethod(const google::protobuf::MethodDescriptor* method, 19 | google::protobuf::RpcController* controller, 20 | const google::protobuf::Message* request, 21 | google::protobuf::Message* response, 22 | google::protobuf::Closure* done); 23 | 24 | private: 25 | NetAddress::ptr m_addr; 26 | // TcpClient::ptr m_client; 27 | 28 | }; 29 | 30 | } 31 | 32 | 33 | 34 | #endif -------------------------------------------------------------------------------- /tinyrpc/net/tinypb/tinypb_rpc_closure.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_TINYPB_TINYPB_RPC_CLOSURE_H 2 | #define TINYRPC_NET_TINYPB_TINYPB_RPC_CLOSURE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | namespace tinyrpc { 10 | 11 | class TinyPbRpcClosure : public google::protobuf::Closure { 12 | public: 13 | typedef std::shared_ptr ptr; 14 | explicit TinyPbRpcClosure(std::function cb) : m_cb(cb) { 15 | 16 | } 17 | 18 | ~TinyPbRpcClosure() = default; 19 | 20 | void Run() { 21 | if(m_cb) { 22 | m_cb(); 23 | } 24 | } 25 | 26 | private: 27 | std::function m_cb {nullptr}; 28 | 29 | }; 30 | 31 | } 32 | 33 | 34 | #endif -------------------------------------------------------------------------------- /tinyrpc/net/tinypb/tinypb_rpc_controller.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "tinypb_rpc_controller.h" 4 | 5 | namespace tinyrpc { 6 | 7 | void TinyPbRpcController::Reset() {} 8 | 9 | bool TinyPbRpcController::Failed() const { 10 | return m_is_failed; 11 | } 12 | 13 | std::string TinyPbRpcController::ErrorText() const { 14 | return m_error_info; 15 | } 16 | 17 | void TinyPbRpcController::StartCancel() {} 18 | 19 | void TinyPbRpcController::SetFailed(const std::string& reason) { 20 | m_is_failed = true; 21 | m_error_info = reason; 22 | } 23 | 24 | bool TinyPbRpcController::IsCanceled() const { 25 | return false; 26 | } 27 | 28 | void TinyPbRpcController::NotifyOnCancel(google::protobuf::Closure* callback) { 29 | 30 | } 31 | 32 | void TinyPbRpcController::SetErrorCode(const int error_code) { 33 | m_error_code = error_code; 34 | } 35 | 36 | int TinyPbRpcController::ErrorCode() const { 37 | return m_error_code; 38 | } 39 | 40 | const std::string& TinyPbRpcController::MsgSeq() const { 41 | return m_msg_req; 42 | } 43 | 44 | void TinyPbRpcController::SetMsgReq(const std::string& msg_req) { 45 | m_msg_req = msg_req; 46 | } 47 | 48 | void TinyPbRpcController::SetError(const int err_code, const std::string& err_info) { 49 | SetFailed(err_info); 50 | SetErrorCode(err_code); 51 | } 52 | 53 | void TinyPbRpcController::SetPeerAddr(NetAddress::ptr addr) { 54 | m_peer_addr = addr; 55 | } 56 | 57 | void TinyPbRpcController::SetLocalAddr(NetAddress::ptr addr) { 58 | m_local_addr = addr; 59 | } 60 | NetAddress::ptr TinyPbRpcController::PeerAddr() { 61 | return m_peer_addr; 62 | } 63 | 64 | NetAddress::ptr TinyPbRpcController::LocalAddr() { 65 | return m_local_addr; 66 | } 67 | 68 | void TinyPbRpcController::SetTimeout(const int timeout) { 69 | m_timeout = timeout; 70 | } 71 | int TinyPbRpcController::Timeout() const { 72 | return m_timeout; 73 | } 74 | 75 | void TinyPbRpcController::SetMethodName(const std::string& name) { 76 | m_method_name = name; 77 | } 78 | 79 | std::string TinyPbRpcController::GetMethodName() { 80 | return m_method_name; 81 | } 82 | 83 | void TinyPbRpcController::SetMethodFullName(const std::string& name) { 84 | m_full_name = name; 85 | } 86 | 87 | std::string TinyPbRpcController::GetMethodFullName() { 88 | return m_full_name; 89 | } 90 | 91 | 92 | } -------------------------------------------------------------------------------- /tinyrpc/net/tinypb/tinypb_rpc_controller.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_TINYPB_TINYPB_RPC_CONRTOLLER_H 2 | #define TINYRPC_NET_TINYPB_TINYPB_RPC_CONRTOLLER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "../net_address.h" 9 | 10 | namespace tinyrpc { 11 | 12 | class TinyPbRpcController : public google::protobuf::RpcController { 13 | 14 | public: 15 | typedef std::shared_ptr ptr; 16 | // Client-side methods --------------------------------------------- 17 | 18 | TinyPbRpcController() = default; 19 | 20 | ~TinyPbRpcController() = default; 21 | 22 | void Reset() override; 23 | 24 | bool Failed() const override; 25 | 26 | 27 | // Server-side methods --------------------------------------------- 28 | 29 | std::string ErrorText() const override; 30 | 31 | void StartCancel() override; 32 | 33 | void SetFailed(const std::string& reason) override; 34 | 35 | bool IsCanceled() const override; 36 | 37 | void NotifyOnCancel(google::protobuf::Closure* callback) override; 38 | 39 | 40 | // common methods 41 | 42 | int ErrorCode() const; 43 | 44 | void SetErrorCode(const int error_code); 45 | 46 | const std::string& MsgSeq() const; 47 | 48 | void SetMsgReq(const std::string& msg_req); 49 | 50 | void SetError(const int err_code, const std::string& err_info); 51 | 52 | void SetPeerAddr(NetAddress::ptr addr); 53 | 54 | void SetLocalAddr(NetAddress::ptr addr); 55 | 56 | NetAddress::ptr PeerAddr(); 57 | 58 | NetAddress::ptr LocalAddr(); 59 | 60 | void SetTimeout(const int timeout); 61 | 62 | int Timeout() const; 63 | 64 | void SetMethodName(const std::string& name); 65 | 66 | std::string GetMethodName(); 67 | 68 | void SetMethodFullName(const std::string& name); 69 | 70 | std::string GetMethodFullName(); 71 | 72 | 73 | 74 | private: 75 | int m_error_code {0}; // error_code, identify one specific error 76 | std::string m_error_info; // error_info, details description of error 77 | std::string m_msg_req; // msg_req, identify once rpc request and response 78 | bool m_is_failed {false}; 79 | bool m_is_cancled {false}; 80 | NetAddress::ptr m_peer_addr; 81 | NetAddress::ptr m_local_addr; 82 | 83 | int m_timeout {5000}; // max call rpc timeout 84 | std::string m_method_name; // method name 85 | std::string m_full_name; // full name, like server.method_name 86 | 87 | 88 | }; 89 | 90 | } 91 | 92 | 93 | #endif -------------------------------------------------------------------------------- /tinyrpc/net/tinypb/tinypb_rpc_dispatcher.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "../abstract_dispatcher.h" 6 | #include "../../comm/error_code.h" 7 | #include "tinypb_data.h" 8 | #include "tinypb_rpc_dispatcher.h" 9 | #include "tinypb_rpc_controller.h" 10 | #include "tinypb_rpc_closure.h" 11 | #include "tinypb_codec.h" 12 | #include "../../comm/msg_req.h" 13 | 14 | namespace tinyrpc { 15 | 16 | class TcpBuffer; 17 | 18 | void TinyPbRpcDispacther::dispatch(AbstractData* data, TcpConnection* conn) { 19 | TinyPbStruct* tmp = dynamic_cast(data); 20 | 21 | if (tmp == nullptr) { 22 | ErrorLog << "dynamic_cast error"; 23 | return; 24 | } 25 | Coroutine::GetCurrentCoroutine()->getRunTime()->m_msg_no = tmp->msg_req; 26 | setCurrentRunTime(Coroutine::GetCurrentCoroutine()->getRunTime()); 27 | 28 | 29 | InfoLog << "begin to dispatch client tinypb request, msgno=" << tmp->msg_req; 30 | 31 | std::string service_name; 32 | std::string method_name; 33 | 34 | TinyPbStruct reply_pk; 35 | reply_pk.service_full_name = tmp->service_full_name; 36 | reply_pk.msg_req = tmp->msg_req; 37 | if (reply_pk.msg_req.empty()) { 38 | reply_pk.msg_req = MsgReqUtil::genMsgNumber(); 39 | } 40 | 41 | if (!parseServiceFullName(tmp->service_full_name, service_name, method_name)) { 42 | ErrorLog << reply_pk.msg_req << "|parse service name " << tmp->service_full_name << "error"; 43 | 44 | reply_pk.err_code = ERROR_PARSE_SERVICE_NAME; 45 | std::stringstream ss; 46 | ss << "cannot parse service_name:[" << tmp->service_full_name << "]"; 47 | reply_pk.err_info = ss.str(); 48 | conn->getCodec()->encode(conn->getOutBuffer(), dynamic_cast(&reply_pk)); 49 | return; 50 | } 51 | 52 | Coroutine::GetCurrentCoroutine()->getRunTime()->m_interface_name = tmp->service_full_name; 53 | auto it = m_service_map.find(service_name); 54 | if (it == m_service_map.end() || !((*it).second)) { 55 | reply_pk.err_code = ERROR_SERVICE_NOT_FOUND; 56 | std::stringstream ss; 57 | ss << "not found service_name:[" << service_name << "]"; 58 | ErrorLog << reply_pk.msg_req << "|" << ss.str(); 59 | reply_pk.err_info = ss.str(); 60 | 61 | conn->getCodec()->encode(conn->getOutBuffer(), dynamic_cast(&reply_pk)); 62 | 63 | InfoLog << "end dispatch client tinypb request, msgno=" << tmp->msg_req; 64 | return; 65 | 66 | } 67 | 68 | service_ptr service = (*it).second; 69 | 70 | const google::protobuf::MethodDescriptor* method = service->GetDescriptor()->FindMethodByName(method_name); 71 | if (!method) { 72 | reply_pk.err_code = ERROR_METHOD_NOT_FOUND; 73 | std::stringstream ss; 74 | ss << "not found method_name:[" << method_name << "]"; 75 | ErrorLog << reply_pk.msg_req << "|" << ss.str(); 76 | reply_pk.err_info = ss.str(); 77 | conn->getCodec()->encode(conn->getOutBuffer(), dynamic_cast(&reply_pk)); 78 | return; 79 | } 80 | 81 | google::protobuf::Message* request = service->GetRequestPrototype(method).New(); 82 | DebugLog << reply_pk.msg_req << "|request.name = " << request->GetDescriptor()->full_name(); 83 | 84 | if(!request->ParseFromString(tmp->pb_data)) { 85 | reply_pk.err_code = ERROR_FAILED_SERIALIZE; 86 | std::stringstream ss; 87 | ss << "faild to parse request data, request.name:[" << request->GetDescriptor()->full_name() << "]"; 88 | reply_pk.err_info = ss.str(); 89 | ErrorLog << reply_pk.msg_req << "|" << ss.str(); 90 | delete request; 91 | conn->getCodec()->encode(conn->getOutBuffer(), dynamic_cast(&reply_pk)); 92 | return; 93 | } 94 | 95 | InfoLog << "============================================================"; 96 | InfoLog << reply_pk.msg_req <<"|Get client request data:" << request->ShortDebugString(); 97 | InfoLog << "============================================================"; 98 | 99 | google::protobuf::Message* response = service->GetResponsePrototype(method).New(); 100 | 101 | DebugLog << reply_pk.msg_req << "|response.name = " << response->GetDescriptor()->full_name(); 102 | 103 | TinyPbRpcController rpc_controller; 104 | rpc_controller.SetMsgReq(reply_pk.msg_req); 105 | rpc_controller.SetMethodName(method_name); 106 | rpc_controller.SetMethodFullName(tmp->service_full_name); 107 | 108 | std::function reply_package_func = [](){}; 109 | 110 | TinyPbRpcClosure closure(reply_package_func); 111 | service->CallMethod(method, &rpc_controller, request, response, &closure); 112 | 113 | InfoLog << "Call [" << reply_pk.service_full_name << "] succ, now send reply package"; 114 | 115 | if (!(response->SerializeToString(&(reply_pk.pb_data)))) { 116 | reply_pk.pb_data = ""; 117 | ErrorLog << reply_pk.msg_req << "|reply error! encode reply package error"; 118 | reply_pk.err_code = ERROR_FAILED_SERIALIZE; 119 | reply_pk.err_info = "failed to serilize relpy data"; 120 | } else { 121 | InfoLog << "============================================================"; 122 | InfoLog << reply_pk.msg_req << "|Set server response data:" << response->ShortDebugString(); 123 | InfoLog << "============================================================"; 124 | } 125 | 126 | delete request; 127 | delete response; 128 | 129 | conn->getCodec()->encode(conn->getOutBuffer(), dynamic_cast(&reply_pk)); 130 | 131 | } 132 | 133 | 134 | bool TinyPbRpcDispacther::parseServiceFullName(const std::string& full_name, std::string& service_name, std::string& method_name) { 135 | if (full_name.empty()) { 136 | ErrorLog << "service_full_name empty"; 137 | return false; 138 | } 139 | std::size_t i = full_name.find("."); 140 | if (i == full_name.npos) { 141 | ErrorLog << "not found [.]"; 142 | return false; 143 | } 144 | 145 | service_name = full_name.substr(0, i); 146 | DebugLog << "service_name = " << service_name; 147 | method_name = full_name.substr(i + 1, full_name.length() - i - 1); 148 | DebugLog << "method_name = " << method_name; 149 | 150 | return true; 151 | 152 | } 153 | 154 | void TinyPbRpcDispacther::registerService(service_ptr service) { 155 | std::string service_name = service->GetDescriptor()->full_name(); 156 | m_service_map[service_name] = service; 157 | InfoLog << "succ register service[" << service_name << "]!"; 158 | } 159 | 160 | } -------------------------------------------------------------------------------- /tinyrpc/net/tinypb/tinypb_rpc_dispatcher.h: -------------------------------------------------------------------------------- 1 | #ifndef TINYRPC_NET_TINYPB_TINYPB_RPC_DISPATCHER_H 2 | #define TINYRPC_NET_TINYPB_TINYPB_RPC_DISPATCHER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "tinyrpc/net/abstract_dispatcher.h" 11 | #include "tinyrpc/net/tinypb/tinypb_data.h" 12 | 13 | 14 | namespace tinyrpc { 15 | 16 | class TinyPbRpcDispacther : public AbstractDispatcher { 17 | public: 18 | 19 | // typedef std::shared_ptr ptr; 20 | typedef std::shared_ptr service_ptr; 21 | 22 | TinyPbRpcDispacther() = default; 23 | ~TinyPbRpcDispacther() = default; 24 | 25 | void dispatch(AbstractData* data, TcpConnection* conn); 26 | 27 | bool parseServiceFullName(const std::string& full_name, std::string& service_name, std::string& method_name); 28 | 29 | void registerService(service_ptr service); 30 | 31 | public: 32 | 33 | // all services should be registerd on there before progress start 34 | // key: service_name 35 | std::map m_service_map; 36 | 37 | }; 38 | 39 | 40 | } 41 | 42 | 43 | 44 | #endif --------------------------------------------------------------------------------