├── .clang-format ├── .cmake-format.yaml ├── .gitattributes ├── .github ├── codeql │ └── codeql-config.yml └── workflows │ ├── main.yml │ └── stale.yml ├── .gitignore ├── .gitmodules ├── .vscode └── settings.json ├── BOOST_LICENSE_1_0.txt ├── CHANGELOG.md ├── CMakeLists.txt ├── CPPLINT.cfg ├── LICENSE ├── LICENSE-Apache.txt ├── NODE_S_LICENSE ├── README.md ├── atframework └── Repository.cmake ├── ci ├── do_ci.ps1 ├── do_ci.sh ├── format.sh └── requirements.txt ├── cmake_dev.sh ├── codecov.yml ├── docs ├── Benchmark.md ├── Build.md ├── README.md ├── Schedule.md ├── Usage.md └── experience │ ├── protocol_test.md │ ├── test_shm_create.cpp │ └── test_shm_delete.cpp ├── include ├── atbus_connection.h ├── atbus_endpoint.h ├── atbus_msg_handler.h ├── atbus_node.h ├── detail │ ├── buffer.h │ ├── libatbus_adapter_libuv.h │ ├── libatbus_channel_export.h │ ├── libatbus_channel_types.h │ ├── libatbus_config.h.in │ ├── libatbus_error.h │ └── libatbus_protocol.fbs ├── include.macro.cmake ├── libatbus.h ├── libatbus_protocol.h └── libatbus_protocol.proto ├── libatbus-config.cmake.in ├── project └── cmake │ ├── FetchDependeny.cmake │ └── ProjectBuildOption.cmake ├── sample ├── CMakeLists.txt ├── sample.custom-macro.cmake └── sample_usage_01.cpp ├── src ├── CMakeLists.txt ├── atbus_connection.cpp ├── atbus_endpoint.cpp ├── atbus_msg_handler.cpp ├── atbus_node.cpp ├── channel_io_stream.cpp ├── channel_mem.cpp ├── channel_shm.cpp ├── channel_utility.cpp ├── detail │ └── buffer.cpp └── libatbus.macro.cmake ├── test ├── CMakeLists.txt └── case │ ├── atbus_endpoint_test.cpp │ ├── atbus_node_msg_test.cpp │ ├── atbus_node_nodesync_test.cpp │ ├── atbus_node_reg_test.cpp │ ├── atbus_node_relationship_test.cpp │ ├── atbus_node_setup_test.cpp │ ├── atbus_test_utils.cpp │ ├── atbus_test_utils.h │ ├── buffer_test.cpp │ ├── channel_io_stream_tcp_test.cpp │ ├── channel_io_stream_unix_test.cpp │ ├── channel_mem_test.cpp │ └── channel_shm_test.cpp ├── third_party └── Repository.cmake └── tools ├── CMakeLists.txt ├── benchmark_io_stream_channel_recv.cpp ├── benchmark_io_stream_channel_send.cpp ├── benchmark_shm_channel_recv.cpp ├── benchmark_shm_channel_send.cpp ├── script ├── cppcheck.sh ├── startup_benchmark_io_stream.sh ├── startup_benchmark_shm.sh └── valgrind_memcheck.sh ├── show_shm_channel.cpp └── tools.macro.cmake /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | BasedOnStyle: Google 4 | ColumnLimit: 120 5 | DerivePointerAlignment: true 6 | PointerAlignment: Left 7 | 8 | # Only sort headers in each include block 9 | SortIncludes: true 10 | IncludeBlocks: Preserve 11 | 12 | # Ident #if/#else/#endif: 13 | # #if defined(WIN) 14 | # # include 15 | # #else 16 | # # include 17 | # #endif 18 | IndentPPDirectives: AfterHash 19 | 20 | IfMacros: ["UTIL_LIKELY_IF", "UTIL_UNLIKELY_IF"] 21 | --- 22 | 23 | --- 24 | Language: Proto 25 | BasedOnStyle: Google 26 | ColumnLimit: 120 27 | --- 28 | 29 | -------------------------------------------------------------------------------- /.cmake-format.yaml: -------------------------------------------------------------------------------- 1 | # @see https://cmake-format.readthedocs.io/en/latest/configuration.html for more details 2 | 3 | format: 4 | line_width: 120 5 | tab_size: 2 6 | use_tabchars: false 7 | line_ending: unix 8 | 9 | markup: 10 | first_comment_is_literal: True 11 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.h text working-tree-encoding=UTF-8 eol=lf 2 | *.hpp text working-tree-encoding=UTF-8 eol=lf 3 | *.cpp text working-tree-encoding=UTF-8 eol=lf 4 | *.cxx text working-tree-encoding=UTF-8 eol=lf 5 | *.cc text working-tree-encoding=UTF-8 eol=lf 6 | *.sh text encoding=UTF-8 eol=lf 7 | *.sh.mako text encoding=UTF-8 eol=lf 8 | *.sh.in text encoding=UTF-8 eol=lf 9 | *.py text encoding=UTF-8 eol=lf 10 | *.mako.py text encoding=UTF-8 eol=lf 11 | *.py.in text encoding=UTF-8 eol=lf 12 | *.py.mako text encoding=UTF-8 eol=lf 13 | *.md text encoding=UTF-8-BOM eol=crlf 14 | *.rst text encoding=UTF-8-BOM eol=crlf 15 | *.bat text encoding=UTF-8-BOM eol=crlf 16 | *.bat.in text encoding=UTF-8-BOM eol=crlf 17 | *.ps1 text encoding=UTF-8-BOM eol=crlf 18 | *.ps1.in text encoding=UTF-8-BOM eol=crlf 19 | *.tar.* filter=lfs diff=lfs merge=lfs -text 20 | *.tar filter=lfs diff=lfs merge=lfs -text 21 | *.gz filter=lfs diff=lfs merge=lfs -text 22 | *.xz filter=lfs diff=lfs merge=lfs -text 23 | *.7z filter=lfs diff=lfs merge=lfs -text 24 | *.tgz filter=lfs diff=lfs merge=lfs -text 25 | *.zip filter=lfs diff=lfs merge=lfs -text 26 | *.a filter=lfs diff=lfs merge=lfs -text 27 | *.so filter=lfs diff=lfs merge=lfs -text 28 | *.so.* filter=lfs diff=lfs merge=lfs -text 29 | *.lib filter=lfs diff=lfs merge=lfs -text 30 | *.dylib filter=lfs diff=lfs merge=lfs -text 31 | *.dll filter=lfs diff=lfs merge=lfs -text 32 | *.doc filter=lfs diff=lfs merge=lfs -text 33 | *.docx filter=lfs diff=lfs merge=lfs -text 34 | *.xls filter=lfs diff=lfs merge=lfs -text 35 | *.xlsx filter=lfs diff=lfs merge=lfs -text 36 | *.ppt filter=lfs diff=lfs merge=lfs -text 37 | *.pptx filter=lfs diff=lfs merge=lfs -text 38 | *.potx filter=lfs diff=lfs merge=lfs -text 39 | *.pdf filter=lfs diff=lfs merge=lfs -text 40 | *.png filter=lfs diff=lfs merge=lfs -text 41 | *.ico filter=lfs diff=lfs merge=lfs -text 42 | *.jpg filter=lfs diff=lfs merge=lfs -text 43 | *.psd filter=lfs diff=lfs merge=lfs -text 44 | *.jar filter=lfs diff=lfs merge=lfs -text 45 | *.exe filter=lfs diff=lfs merge=lfs -text 46 | *.7z filter=lfs diff=lfs merge=lfs -text 47 | *.gz filter=lfs diff=lfs merge=lfs -text 48 | -------------------------------------------------------------------------------- /.github/codeql/codeql-config.yml: -------------------------------------------------------------------------------- 1 | languages: 2 | - cpp 3 | queries: 4 | - name: Security And Quality 5 | uses: security-and-quality 6 | # "paths"/"paths-ignore" fields of the config only have effect for JavaScript, Python, and Ruby 7 | # paths: 8 | # - include 9 | # - src 10 | # paths-ignore: 11 | # - third_party 12 | # - test 13 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: "main" 2 | 3 | on: # @see https://help.github.com/en/articles/events-that-trigger-workflows#webhook-events 4 | push: 5 | branches: # Array of patterns that match refs/heads 6 | - master # Push events on master branch 7 | - main 8 | pull_request: 9 | branches: [main] 10 | 11 | jobs: 12 | format: 13 | name: Format 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v4 18 | - name: CI Job 19 | shell: bash 20 | run: | 21 | bash ci/do_ci.sh format ; 22 | unix_build: # job id, can be any string 23 | name: Unix Build 24 | # This job runs on Linux 25 | strategy: 26 | matrix: 27 | include: 28 | - os: ubuntu-latest 29 | triplet: x64-linux 30 | cc: gcc 31 | - os: ubuntu-20.04 32 | triplet: x64-linux 33 | cc: gcc-4.8 34 | - os: ubuntu-latest 35 | triplet: x64-linux 36 | cc: clang-latest 37 | - os: macos-latest 38 | triplet: x64-osx 39 | cc: clang-latest 40 | runs-on: ${{ matrix.os }} 41 | steps: 42 | - name: Checkout 43 | uses: actions/checkout@v4 44 | - name: Generate cache key 45 | shell: bash 46 | run: git submodule > '.github/.cache-key' 47 | - name: Cache packages 48 | uses: actions/cache@v4 49 | with: 50 | path: | 51 | third_party/install 52 | key: ${{ matrix.os }}-${{ matrix.cc }}-${{ hashFiles('.github/.cache-key') }} 53 | - name: Build & Test 54 | shell: bash 55 | env: 56 | USE_CC: ${{ matrix.cc }} 57 | VCPKG_TARGET_TRIPLET: ${{ matrix.triplet }} 58 | run: | 59 | # The OpenSSL config package in apple ci job is break 60 | if [ -e /opt/homebrew/lib/cmake/OpenSSL ]; then 61 | rm -rf /opt/homebrew/lib/cmake/OpenSSL || true 62 | fi 63 | if [[ "xgcc-4.8" == "x$USE_CC" ]]; then 64 | sudo apt-add-repository 'deb http://archive.ubuntu.com/ubuntu/ xenial main' 65 | sudo apt-add-repository 'deb http://archive.ubuntu.com/ubuntu/ xenial universe' 66 | sudo apt-get update ; 67 | sudo apt-get install --no-install-recommends --no-install-suggests -y g++-4.8 ; 68 | bash ci/do_ci.sh gcc.legacy.test ; 69 | elif [[ "x$USE_CC" =~ xclang.* ]]; then 70 | bash ci/do_ci.sh clang.test ; 71 | else 72 | bash ci/do_ci.sh ssl.openssl ; 73 | fi 74 | vs2019_2022_build: # job id, can be any string 75 | name: "Visual Studio 2019/2022 Build" 76 | strategy: 77 | matrix: 78 | include: 79 | - os: windows-latest 80 | generator: "Visual Studio 17 2022" 81 | build_shared_libs: "ON" 82 | platform: x64 83 | - os: windows-latest 84 | generator: "Visual Studio 17 2022" 85 | build_shared_libs: "OFF" 86 | platform: x64 87 | - os: windows-2019 88 | generator: "Visual Studio 16 2019" 89 | build_shared_libs: "OFF" 90 | platform: x64 91 | runs-on: ${{ matrix.os }} 92 | steps: 93 | - name: Checkout 94 | uses: actions/checkout@v4 95 | - name: Generate cache key 96 | shell: bash 97 | run: git submodule > '.github/.cache-key' 98 | - name: Cache packages 99 | uses: actions/cache@v4 100 | with: 101 | path: | 102 | third_party/install 103 | key: ${{ matrix.os }}-shared-${{ matrix.build_shared_libs }}-${{ hashFiles('.github/.cache-key') }} 104 | - name: Build & Test 105 | shell: pwsh 106 | env: 107 | CMAKE_GENERATOR: ${{ matrix.generator }} 108 | CMAKE_PLATFORM: ${{ matrix.platform }} 109 | BUILD_SHARED_LIBS: ${{ matrix.build_shared_libs }} 110 | CONFIGURATION: RelWithDebInfo 111 | run: | 112 | pwsh ci/do_ci.ps1 "msvc.2019+.test" ; 113 | # mingw_build: # job id, can be any string 114 | # name: MinGW Build 115 | # strategy: 116 | # matrix: 117 | # include: 118 | # - os: windows-latest 119 | # build_shared_libs: "ON" 120 | # runs-on: ${{ matrix.os }} 121 | # steps: 122 | # - name: Checkout 123 | # uses: actions/checkout@v4 124 | # - name: Generate cache key 125 | # shell: bash 126 | # run: git submodule > '.github/.cache-key' 127 | # - name: Cache packages 128 | # uses: actions/cache@v4 129 | # with: 130 | # path: | 131 | # third_party/install 132 | # C:/msys64/var/cache/pacman/pkg 133 | # key: ${{ matrix.os }}-mingw-shared-${{ matrix.build_shared_libs }}-${{ hashFiles('.github/.cache-key') }} 134 | # - name: Build & Test 135 | # shell: bash 136 | # env: 137 | # BUILD_SHARED_LIBS: ${{ matrix.build_shared_libs }} 138 | # run: | 139 | # C:/msys64/msys2_shell.cmd -mingw64 -defterm -no-start -here -lc "ci/do_ci.sh msys2.mingw.test" 140 | codeql: # job id, can be any string 141 | name: CodeQL 142 | # This job runs on Linux 143 | strategy: 144 | matrix: 145 | include: 146 | - os: ubuntu-latest 147 | triplet: x64-linux 148 | cc: gcc 149 | gcov_flags: "--coverage -fprofile-arcs -ftest-coverage" 150 | runs-on: ${{ matrix.os }} 151 | steps: 152 | - name: Checkout 153 | uses: actions/checkout@v4 154 | - name: Generate cache key 155 | shell: bash 156 | run: git submodule > '.github/.cache-key' 157 | - name: Cache packages 158 | uses: actions/cache@v4 159 | with: 160 | path: | 161 | third_party/install 162 | key: ${{ matrix.os }}-coverage-${{ hashFiles('.github/.cache-key') }} 163 | - name: Configure 164 | shell: bash 165 | env: 166 | USE_CC: ${{ matrix.cc }} 167 | VCPKG_TARGET_TRIPLET: ${{ matrix.triplet }} 168 | GCOV_FLAGS: "${{ matrix.gcov_flags }}" 169 | run: | 170 | bash ci/do_ci.sh codeql.configure 171 | - name: Initialize CodeQL 172 | uses: github/codeql-action/init@v3 173 | with: 174 | config-file: ./.github/codeql/codeql-config.yml 175 | - name: Build 176 | shell: bash 177 | env: 178 | USE_CC: ${{ matrix.cc }} 179 | run: | 180 | bash ci/do_ci.sh codeql.build 181 | - name: Perform CodeQL Analysis 182 | uses: github/codeql-action/analyze@v3 183 | with: 184 | category: "/language:cpp" 185 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: "Mark and close stale issues" 2 | on: 3 | schedule: 4 | - cron: "30 2 * * *" 5 | 6 | jobs: 7 | stale: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/stale@v6 11 | with: 12 | stale-issue-message: "This issue was marked as stale due to lack of activity." 13 | days-before-issue-stale: 90 14 | exempt-issue-labels: "do-not-stale" 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Compiled Dynamic libraries 8 | *.so 9 | *.dylib 10 | *.dll 11 | 12 | # Compiled Static libraries 13 | *.lai 14 | *.la 15 | *.a 16 | *.lib 17 | 18 | # Executables 19 | *.exe 20 | *.out 21 | *.app 22 | 23 | # Build directory 24 | build/* 25 | build_* 26 | 27 | # project files 28 | /.idea 29 | /.vs 30 | 31 | # generated file 32 | /include/detail/libatbus_config.h 33 | /include/detail/libatbus_protocol_generated.h 34 | /include/libatbus_protocol.pb.h 35 | /include/libatbus_protocol.pb 36 | /src/libatbus_protocol.pb.cc 37 | 38 | /atframework/cmake-toolset 39 | /atframework/atframe_utils 40 | 41 | # prebuilt directory 42 | /third_party/install 43 | /third_party/packages 44 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "atframework/atframe_utils"] 2 | path = atframework/atframe_utils 3 | url = https://github.com/atframework/atframe_utils.git 4 | branch = main 5 | [submodule "atframework/cmake-toolset"] 6 | path = atframework/cmake-toolset 7 | url = https://github.com/atframework/cmake-toolset.git 8 | branch = main 9 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cmake.configureSettings": { 3 | "BUILD_SHARED_LIBS": "YES", 4 | "PROJECT_ENABLE_UNITTEST": "YES", 5 | "PROJECT_ENABLE_SAMPLE": "YES", 6 | "PROJECT_ENABLE_TOOLS": "YES", 7 | "ATBUS_MACRO_ABORT_ON_PROTECTED_ERROR": "YES" 8 | // "CMAKE_CXX_FLAGS": "-fsanitize=address -fno-omit-frame-pointer", 9 | // "CMAKE_C_FLAGS": "-fsanitize=address -fno-omit-frame-pointer", 10 | // "CMAKE_EXE_LINKER_FLAGS=": "-static-libsan" 11 | }, 12 | "cmake.configureEnvironment": { 13 | "CPRINTF_MODE": "none" 14 | }, 15 | "cmake.buildEnvironment": { 16 | "CPRINTF_MODE": "none" 17 | }, 18 | "[cpp]": { 19 | "editor.formatOnSave": false 20 | }, 21 | "files.associations": { 22 | "*.ejs": "html", 23 | "*.h.in": "cpp", 24 | "*.h.cpp": "cpp", 25 | "*.ps1.in": "powershell", 26 | "*.sh.in": "shellscript", 27 | "*.bat.in": "bat", 28 | "array": "cpp", 29 | "atomic": "cpp", 30 | "*.tcc": "cpp", 31 | "bitset": "cpp", 32 | "cctype": "cpp", 33 | "chrono": "cpp", 34 | "clocale": "cpp", 35 | "cmath": "cpp", 36 | "cstddef": "cpp", 37 | "cstdint": "cpp", 38 | "cstdio": "cpp", 39 | "cstdlib": "cpp", 40 | "cstring": "cpp", 41 | "ctime": "cpp", 42 | "cwchar": "cpp", 43 | "cwctype": "cpp", 44 | "deque": "cpp", 45 | "list": "cpp", 46 | "unordered_map": "cpp", 47 | "unordered_set": "cpp", 48 | "vector": "cpp", 49 | "exception": "cpp", 50 | "string_view": "cpp", 51 | "fstream": "cpp", 52 | "functional": "cpp", 53 | "initializer_list": "cpp", 54 | "iomanip": "cpp", 55 | "iosfwd": "cpp", 56 | "iostream": "cpp", 57 | "istream": "cpp", 58 | "limits": "cpp", 59 | "memory": "cpp", 60 | "new": "cpp", 61 | "numeric": "cpp", 62 | "optional": "cpp", 63 | "ostream": "cpp", 64 | "ratio": "cpp", 65 | "sstream": "cpp", 66 | "stdexcept": "cpp", 67 | "streambuf": "cpp", 68 | "system_error": "cpp", 69 | "thread": "cpp", 70 | "cinttypes": "cpp", 71 | "tuple": "cpp", 72 | "type_traits": "cpp", 73 | "utility": "cpp", 74 | "typeinfo": "cpp", 75 | "__config": "cpp", 76 | "__nullptr": "cpp", 77 | "algorithm": "cpp", 78 | "cstdarg": "cpp", 79 | "condition_variable": "cpp", 80 | "iterator": "cpp", 81 | "map": "cpp", 82 | "memory_resource": "cpp", 83 | "regex": "cpp", 84 | "set": "cpp", 85 | "string": "cpp", 86 | "mutex": "cpp", 87 | "__bit_reference": "cpp", 88 | "__debug": "cpp", 89 | "__functional_base": "cpp", 90 | "__hash_table": "cpp", 91 | "__locale": "cpp", 92 | "__mutex_base": "cpp", 93 | "__split_buffer": "cpp", 94 | "__string": "cpp", 95 | "__threading_support": "cpp", 96 | "__tree": "cpp", 97 | "__tuple": "cpp", 98 | "ios": "cpp", 99 | "locale": "cpp", 100 | "queue": "cpp", 101 | "stack": "cpp", 102 | "xstring": "cpp", 103 | "xutility": "cpp", 104 | "*.inc": "cpp", 105 | "xmemory": "cpp", 106 | "random": "cpp", 107 | "concepts": "cpp", 108 | "forward_list": "cpp", 109 | "xfacet": "cpp", 110 | "xhash": "cpp", 111 | "xiosbase": "cpp", 112 | "xlocale": "cpp", 113 | "xlocbuf": "cpp", 114 | "xlocinfo": "cpp", 115 | "xlocmes": "cpp", 116 | "xlocmon": "cpp", 117 | "xlocnum": "cpp", 118 | "xloctime": "cpp", 119 | "xstddef": "cpp", 120 | "xtr1common": "cpp", 121 | "xtree": "cpp", 122 | "compare": "cpp" 123 | }, 124 | "C_Cpp.default.configurationProvider": "vector-of-bool.cmake-tools" 125 | } -------------------------------------------------------------------------------- /BOOST_LICENSE_1_0.txt: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | CHANGELOG 2 | ============ 3 | 4 | 2.1.0 5 | ------------ 6 | 7 | 1. 重构构建系统 8 | 2. 增加代码规范工具 9 | 3. 重构CI配置 10 | 11 | 2.0.0 12 | ------------ 13 | 14 | 这是一个比较大规模的重构,并且协议层向前不兼容,API除协议数据读取外基本兼容 15 | 16 | 1. 移除对msgpack的依赖,使用protobuf作为内部交互协议 17 | 2. 增加access_token的支持,防止误操作 18 | 3. 增加subnet功能,可以支持自身node的id不在自己管理的子节点集合中 19 | 4. 重构父节点范围管理的结构,现在更清晰易懂一些 20 | 5. 增加(共享)内存通道的版本号功能,增加协议版本号功能,用于跨版本兼容性检查 21 | 6. 连接层面也增加错误计数,如果超出容忍值直接断开连接 22 | 7. 支持字符串路径的共享内存(使用: ```shm_open/ftruncate/mmap/munmap/shm_unlink/close/fstat``` 来管理),支持字符串命名的共享内存(长度限定为NAME_MAX(255)) 23 | 8. 增加大量错误流程的单元测试,优化Unix Sock的单元测试 24 | 9. 优化工程脚本,逐步使用Modern CMake规范管理依赖链。 25 | 10. 增加对符号隐藏、符号导出和Windows下dll的支持。现在GCC/Clang/MSVC使用相同的符号可见性和导出规则。 26 | 11. 规范版本号规则:第一位变化表示有向前不兼容的变更;第二位表示有功能增加,向前兼容,第三位表示BUG修复和优化 27 | 12. 增加协议版本号机制,用于多个由atbus版本组成的系统中,可以根据最低要求版本号和当前版本号来决定是否互联(比如新的atproxy中不再会尝试连接不支持的版本) 28 | 29 | 1.1.0 30 | ------------ 31 | 32 | 第一个线上使用过的版本 33 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.24.0) 2 | 3 | if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.27.0") 4 | cmake_policy(SET CMP0144 NEW) 5 | endif() 6 | 7 | enable_testing() 8 | 9 | project( 10 | libatbus 11 | VERSION "2.3.1" 12 | HOMEPAGE_URL "https://github.com/atframework/libatbus" 13 | LANGUAGES C CXX) 14 | 15 | if(NOT DEFINED __COMPILER_OPTION_LOADED) 16 | if(MSVC) 17 | string(REGEX REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") 18 | string(REGEX REPLACE "/GR-?" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") 19 | else() 20 | string(REGEX REPLACE "-f(no-)?exceptions" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") 21 | string(REGEX REPLACE "-f(no-)?rtti" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") 22 | endif() 23 | endif() 24 | 25 | set(LIBATBUS_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}") 26 | set(LIBATBUS_VERSION_MINOR "${PROJECT_VERSION_MINOR}") 27 | set(LIBATBUS_VERSION_PATCH "${PROJECT_VERSION_PATCH}") 28 | set(LIBATBUS_VERSION "${PROJECT_VERSION}") 29 | 30 | include("${CMAKE_CURRENT_LIST_DIR}/project/cmake/ProjectBuildOption.cmake") 31 | include("${CMAKE_CURRENT_LIST_DIR}/third_party/Repository.cmake") 32 | include("${CMAKE_CURRENT_LIST_DIR}/atframework/Repository.cmake") 33 | 34 | unset(PROJECT_LIBATBUS_PRIVATE_COMPILE_OPTIONS) 35 | 36 | # ###################################################################################################################### 37 | # 导入项目配置 导入所有 macro 定义 38 | include("${CMAKE_CURRENT_LIST_DIR}/include/include.macro.cmake") 39 | include("${CMAKE_CURRENT_LIST_DIR}/src/libatbus.macro.cmake") 40 | include("${CMAKE_CURRENT_LIST_DIR}/tools/tools.macro.cmake") 41 | 42 | # 导入工程项目 43 | set(PROJECT_LIBATBUS_PUBLIC_LINK_NAMES 44 | ${ATFRAMEWORK_ATFRAME_UTILS_LINK_NAME} ${ATFRAMEWORK_CMAKE_TOOLSET_THIRD_PARTY_PROTOBUF_LINK_NAME} 45 | ${ATFRAMEWORK_CMAKE_TOOLSET_THIRD_PARTY_LIBUV_LINK_NAME}) 46 | 47 | if(COMPILER_STRICT_EXTRA_CFLAGS) 48 | list(APPEND PROJECT_LIBATBUS_PRIVATE_COMPILE_OPTIONS ${COMPILER_STRICT_EXTRA_CFLAGS}) 49 | endif() 50 | 51 | if(COMPILER_STRICT_CFLAGS) 52 | list(APPEND PROJECT_LIBATBUS_PRIVATE_COMPILE_OPTIONS ${COMPILER_STRICT_CFLAGS}) 53 | endif() 54 | 55 | if(COMPILER_STRICT_RECOMMEND_EXTRA_CFLAGS) 56 | list(APPEND PROJECT_LIBATBUS_PRIVATE_COMPILE_OPTIONS ${COMPILER_STRICT_RECOMMEND_EXTRA_CFLAGS}) 57 | endif() 58 | 59 | add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/src") 60 | 61 | if(PROJECT_ENABLE_SAMPLE) 62 | add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/sample") 63 | endif() 64 | 65 | if(PROJECT_ENABLE_UNITTEST OR BUILD_TESTING) 66 | atframework_atframe_utils_populate() 67 | include("${ATFRAMEWORK_ATFRAME_UTILS_REPO_DIR}/test/test.utils-macro.cmake") 68 | add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/test") 69 | endif() 70 | 71 | if(PROJECT_ENABLE_TOOLS) 72 | add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/tools") 73 | endif() 74 | 75 | # 生成文档和导入配置 76 | 77 | # Install configuration 78 | set(CMAKE_INSTALL_CMAKEDIR 79 | "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" 80 | CACHE STRING "Directory relative to CMAKE_INSTALL to install the cmake configuration files") 81 | 82 | include(CMakePackageConfigHelpers) 83 | set(INCLUDE_INSTALL_DIR include) 84 | 85 | file(MAKE_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/${PROJECT_NAME}") 86 | 87 | configure_package_config_file( 88 | "${CMAKE_CURRENT_LIST_DIR}/libatbus-config.cmake.in" 89 | "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/${PROJECT_NAME}/libatbus-config.cmake" 90 | INSTALL_DESTINATION ${CMAKE_INSTALL_CMAKEDIR} 91 | PATH_VARS LIBATBUS_VERSION INCLUDE_INSTALL_DIR CMAKE_INSTALL_LIBDIR PROJECT_SOURCE_DIR 92 | NO_CHECK_REQUIRED_COMPONENTS_MACRO) 93 | 94 | write_basic_package_version_file( 95 | "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/${PROJECT_NAME}/libatbus-config-version.cmake" 96 | VERSION ${LIBATBUS_VERSION} 97 | COMPATIBILITY SameMajorVersion) 98 | 99 | install(FILES "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/${PROJECT_NAME}/libatbus-config.cmake" 100 | "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/${PROJECT_NAME}/libatbus-config-version.cmake" 101 | DESTINATION ${CMAKE_INSTALL_CMAKEDIR}) 102 | 103 | export( 104 | EXPORT ${PROJECT_LIBATBUS_EXPORT_NAME} 105 | NAMESPACE atframework:: 106 | FILE "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/cmake/${PROJECT_NAME}/${PROJECT_LIBATBUS_EXPORT_NAME}.cmake") 107 | install( 108 | EXPORT ${PROJECT_LIBATBUS_EXPORT_NAME} 109 | NAMESPACE "atframework::" 110 | DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") 111 | -------------------------------------------------------------------------------- /CPPLINT.cfg: -------------------------------------------------------------------------------- 1 | linelength=120 2 | filter=-build/c++11,-build/c++14,-runtime/references 3 | exclude=third_party -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2023 atframework 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /NODE_S_LICENSE: -------------------------------------------------------------------------------- 1 | libuv is part of the Node project: http://nodejs.org/ 2 | libuv may be distributed alone under Node's license: 3 | 4 | ==== 5 | 6 | Copyright Joyent, Inc. and other Node contributors. All rights reserved. 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to 9 | deal in the Software without restriction, including without limitation the 10 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 | sell copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 | IN THE SOFTWARE. 24 | 25 | ==== 26 | 27 | This license applies to all parts of libuv that are not externally 28 | maintained libraries. 29 | 30 | The externally maintained libraries used by libuv are: 31 | 32 | - tree.h (from FreeBSD), copyright Niels Provos. Two clause BSD license. 33 | 34 | - inet_pton and inet_ntop implementations, contained in src/inet.c, are 35 | copyright the Internet Systems Consortium, Inc., and licensed under the ISC 36 | license. 37 | 38 | - stdint-msvc2008.h (from msinttypes), copyright Alexander Chemeris. Three 39 | clause BSD license. 40 | 41 | - pthread-fixes.h, pthread-fixes.c, copyright Google Inc. and Sony Mobile 42 | Communications AB. Three clause BSD license. 43 | 44 | - android-ifaddrs.h, android-ifaddrs.c, copyright Berkeley Software Design 45 | Inc, Kenneth MacKay and Emergya (Cloud4all, FP7/2007-2013, grant agreement 46 | n° 289016). Three clause BSD license. 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libatbus 2 | 3 | 用于搭建高性能、全异步(a)、树形结构(t)的BUS消息系统的跨平台框架库 4 | 5 | [![ci-badge]][ci-link] [![codecov badge]][codecov status] 6 | 7 | [ci-badge]: https://github.com/atframework/libatbus/actions/workflows/main.yml/badge.svg "Github action build status" 8 | [ci-link]: https://github.com/atframework/libatbus/actions/workflows/main.yml "Github action build status" 9 | [codecov badge]: https://codecov.io/gh/atframework/libatbus/branch/main/graph/badge.svg 10 | [codecov status]: https://codecov.io/gh/atframework/libatbus 11 | 12 | ## CI Job Matrix 13 | 14 | | Target System | Toolchain | Note | 15 | | ------------- | ------------------ | --------------------- | 16 | | Linux | GCC | 17 | | Linux | Clang | With libc++ | 18 | | Linux | GCC 4.8 | 19 | | MinGW64 | GCC | Dynamic linking | 20 | | Windows | Visual Studio 2022 | Static linking | 21 | | Windows | Visual Studio 2022 | Dynamic linking | 22 | | Windows | Visual Studio 2019 | Static linking | 23 | | macOS | AppleClang | With libc++ | 24 | 25 | ## 依赖 26 | 27 | + 支持c++0x或c++11的编译器(为了代码尽量简洁,特别是少做无意义的平台兼容,依赖部分 C11和C++11的功能,所以不支持过低版本的编译器) 28 | > + GCC: 4.8 及以上 29 | > + Clang: 3.8 及以上 30 | > + VC: 12 及以上 31 | 32 | + [cmake](https://cmake.org/download/) 3.16.0 以上 33 | 34 | ## 设计初衷和要点 35 | 36 | 1. **[扩展性]** 根据很多业务的需要,预留足够长的ID段(64位),用以给不同的ID段做不同类型的业务区分。 37 | > 现有很多框架都是32位(比如腾讯的tbus和云风的[skynet](https://github.com/cloudwu/skynet)),在服务类型比较多的时候必须小心设计服务ID,以免冲突。 38 | > 39 | > 当然也有考虑到以后可能会扩展为带Hash的字符串,所以在编译选项上做了预留。但是目前还是uint64_t 40 | 41 | 2. **[高性能]** 同物理机之间可以直接使用共享内存通信,大幅提高消息分发的性能。跨物理机之间会使用tcp通信。并且这个通信方式的选择是完全自动并透明的(尽可能选择更快的方式发送消息),业务层完全不需要关心。 42 | 3. **[跨平台]** 拥有不同习惯的Developer可以使用自己熟悉的工具,提高开发速度 43 | 4. **[动态路由]** 父子节点间会至少保持一条连接,自动断线重连。同父的兄弟节点之间完全按需建立连接。并且这个过程都是自动完成的,不需要提前初始化。 44 | > 同样,新增节点和移除节点也不需要做什么特别的初始化操作。不会影响到已经在线上的服务。 45 | 46 | 5. **[低消耗]** 采用无锁队列,提高CPU性能。(共享)内存通道支持多端写入,一端读取,减少内存浪费。 47 | > 如果N个节点两两互联,每个节点可以只拥有一个(共享)内存通道。即总共只有N个通道,内存消耗为N*每个通道内存占用 48 | > 49 | > 一些其他的系统(比如tbus和我们目前的服务器框架)如果N个节点两两互联,每两个节点之间都要创建(共享)内存通道。即总共只有N*N个通道,内存消耗为N*N*每个通道内存占用。非常浪费 50 | 51 | 6. **[简化设计]** 根据一些实际的项目情况,把父子节点间的关系限定为Bus ID的后N位有包含关系,类似路由器的路由表的策略。 52 | > 比如 0x12345678 可以控制的子节点有16位(0x12345678/16),那么0x12340000-0x1234FFFF都可以注册为它的子节点。 53 | > 54 | > 如同IP协议中 192.168.1.1/24 路由表能管理 192.168.1.0-192.168.1.255 一样。当然这里的24指前24位,而前面提到的16指后16位。 55 | > 56 | > 这么简化以后很多节点关系维护和通信都能简单很多并且能提高性能。 57 | 58 | ## 环境准备和构建流程 59 | 60 | 使用cmake标准构建方式,默认的编译目标为Debug版本,详见 [使用(编译)流程](docs/Build.md) 61 | 62 | **注意: 默认的编译选项是Debug模式,压测和正式环境请使用 cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo 源码目录 [其他选项] 编译(相当于gcc -O2 -g -ggdb -DNDEBUG -Wall -Werror或MSVC /O2)** 63 | 64 | **注意: Windows下私有共享内存不允许跨进程共享,公有共享内存必须有管理员权限。如果Windows下出现初始化共享内存错误请使用管理员权限运行。** 65 | 66 | ## 使用示例 67 | 68 | 简要的使用示例见 [使用示例](docs/Usage.md) 69 | 70 | 更加详细的请参考单元测试和[tools](tools)目录内的代码 71 | 72 | ## Benchmark 73 | 74 | 压力测试和对比见[docs/Benchmark.md](docs/Benchmark.md) 75 | 76 | ## 支持工具 77 | 78 | Linux下 GCC编译安装脚本(支持离线编译安装): 79 | 80 | 1. [GCC](https://github.com/owent-utils/bash-shell/tree/master/GCC%20Installer) 81 | 2. [LLVM & Clang](https://github.com/owent-utils/bash-shell/tree/master/LLVM%26Clang%20Installer) 82 | 83 | ## LICENSE 84 | 85 | + libatbus 采用[MIT License](LICENSE) 86 | + Flatbuffers 采用[Apache License, Version 2.0](LICENSE-Apache.txt) 87 | + libuv 采用[Node's license协议](NODE_S_LICENSE)(类似MIT License) 88 | -------------------------------------------------------------------------------- /atframework/Repository.cmake: -------------------------------------------------------------------------------- 1 | set(ATFRAMEWORK_ATFRAME_UTILS_REPO_DIR 2 | "${PROJECT_SOURCE_DIR}/atframework/atframe_utils" 3 | CACHE PATH "PATH to atframe_utils") 4 | 5 | macro(ATFRAMEWORK_ATFRAME_UTILS_POPULATE) 6 | if(NOT EXISTS "${ATFRAMEWORK_ATFRAME_UTILS_REPO_DIR}/CMakeLists.txt") 7 | execute_process( 8 | COMMAND ${GIT_EXECUTABLE} submodule update --depth 100 --recommend-shallow -f --init -- atframework/atframe_utils 9 | WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" ${ATFRAMEWORK_CMAKE_TOOLSET_EXECUTE_PROCESS_OUTPUT_OPTIONS}) 10 | set(ATFRAMEWORK_ATFRAME_UTILS_REPO_DIR 11 | "${PROJECT_SOURCE_DIR}/atframework/atframe_utils" 12 | CACHE PATH "PATH to atframe_utils" FORCE) 13 | endif() 14 | endmacro() 15 | 16 | if(TARGET atframe_utils) 17 | set(ATFRAMEWORK_ATFRAME_UTILS_LINK_NAME atframe_utils) 18 | elseif(TARGET atframework::atframe_utils) 19 | set(ATFRAMEWORK_ATFRAME_UTILS_LINK_NAME atframework::atframe_utils) 20 | else() 21 | set(ATFRAMEWORK_ATFRAME_UTILS_LINK_NAME atframe_utils) 22 | if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/_deps/${ATFRAMEWORK_ATFRAME_UTILS_LINK_NAME}") 23 | file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/_deps/${ATFRAMEWORK_ATFRAME_UTILS_LINK_NAME}") 24 | endif() 25 | atframework_atframe_utils_populate() 26 | add_subdirectory("${ATFRAMEWORK_ATFRAME_UTILS_REPO_DIR}" 27 | "${CMAKE_CURRENT_BINARY_DIR}/_deps/${ATFRAMEWORK_ATFRAME_UTILS_LINK_NAME}") 28 | endif() 29 | -------------------------------------------------------------------------------- /ci/do_ci.ps1: -------------------------------------------------------------------------------- 1 | $PSDefaultParameterValues['*:Encoding'] = 'UTF-8' 2 | 3 | $OutputEncoding = [System.Text.UTF8Encoding]::new() 4 | 5 | $SCRIPT_DIR = Split-Path -Parent $MyInvocation.MyCommand.Definition 6 | $WORK_DIR = Get-Location 7 | 8 | if ($IsWindows) { 9 | # See https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd 10 | New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" ` 11 | -Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force 12 | 13 | function Invoke-Environment { 14 | param 15 | ( 16 | [Parameter(Mandatory = $true)] 17 | [string] $Command 18 | ) 19 | cmd /c "$Command > nul 2>&1 && set" | . { process { 20 | if ($_ -match '^([^=]+)=(.*)') { 21 | [System.Environment]::SetEnvironmentVariable($matches[1], $matches[2]) 22 | } 23 | } } 24 | } 25 | $vswhere = "${Env:ProgramFiles(x86)}/Microsoft Visual Studio/Installer/vswhere.exe" 26 | $vsInstallationPath = & $vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath 27 | $winSDKDir = $(Get-ItemPropertyValue -Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Microsoft SDKs\Windows\v10.0" -Name "InstallationFolder") 28 | if ([string]::IsNullOrEmpty($winSDKDir)) { 29 | $winSDKDir = "${Env:ProgramFiles(x86)}/Windows Kits/10/Include/" 30 | } 31 | else { 32 | $winSDKDir = "$winSDKDir/Include/" 33 | } 34 | foreach ($sdk in $(Get-ChildItem $winSDKDir | Sort-Object -Property Name)) { 35 | if ($sdk.Name -match "[0-9]+\.[0-9]+\.[0-9\.]+") { 36 | $selectWinSDKVersion = $sdk.Name 37 | } 38 | } 39 | if (!(Test-Path Env:WindowsSDKVersion)) { 40 | $Env:WindowsSDKVersion = $selectWinSDKVersion 41 | } 42 | # Maybe using $selectWinSDKVersion = "10.0.18362.0" for better compatible 43 | Write-Output "Window SDKs:(Latest: $selectWinSDKVersion)" 44 | foreach ($sdk in $(Get-ChildItem $winSDKDir | Sort-Object -Property Name)) { 45 | Write-Output " - $sdk" 46 | } 47 | } 48 | 49 | Set-Location "$SCRIPT_DIR/.." 50 | $RUN_MODE = $args[0] 51 | 52 | if ( $RUN_MODE -eq "msvc.2019+.test" ) { 53 | Invoke-Environment "call ""$vsInstallationPath/VC/Auxiliary/Build/vcvars64.bat""" 54 | New-Item -Path "build_jobs_ci" -ItemType "directory" -Force 55 | Set-Location "build_jobs_ci" 56 | & cmake ".." "-G" "$Env:CMAKE_GENERATOR" "-A" $Env:CMAKE_PLATFORM "-DBUILD_SHARED_LIBS=$ENV:BUILD_SHARED_LIBS" ` 57 | "-DPROJECT_ENABLE_UNITTEST=ON" "-DPROJECT_ENABLE_SAMPLE=ON" "-DPROJECT_ENABLE_TOOLS=ON" "-DATBUS_MACRO_ABORT_ON_PROTECTED_ERROR=ON" ` 58 | "-DATFRAMEWORK_CMAKE_TOOLSET_THIRD_PARTY_PROTOBUF_ALLOW_SHARED_LIBS=OFF" ` 59 | "-DCMAKE_SYSTEM_VERSION=$selectWinSDKVersion" "-DATFRAMEWORK_CMAKE_TOOLSET_THIRD_PARTY_LOW_MEMORY_MODE=ON" 60 | if ( $LastExitCode -ne 0 ) { 61 | exit $LastExitCode 62 | } 63 | 64 | $ALL_DLL_FILES = Get-ChildItem -Path "../third_party/install/*.dll" -Recurse 65 | $ALL_DLL_DIRS = $(foreach ($dll_file in $ALL_DLL_FILES) { 66 | $dll_file.Directory.FullName 67 | }) | Sort-Object | Get-Unique 68 | $Env:PATH = ($ALL_DLL_DIRS -Join [IO.Path]::PathSeparator) + [IO.Path]::PathSeparator + $Env:PATH 69 | Write-Output "PATH=$Env:PATH" 70 | 71 | & cmake --build . --config $Env:CONFIGURATION 72 | if ( $LastExitCode -ne 0 ) { 73 | exit $LastExitCode 74 | } 75 | & ctest . -V -C $Env:CONFIGURATION -L libatbus.unit_test 76 | if ( $LastExitCode -ne 0 ) { 77 | exit $LastExitCode 78 | } 79 | } 80 | elseif ( $RUN_MODE -eq "msvc.2017.test" ) { 81 | Invoke-Environment "call ""$vsInstallationPath/VC/Auxiliary/Build/vcvars64.bat""" 82 | New-Item -Path "build_jobs_ci" -ItemType "directory" -Force 83 | Set-Location "build_jobs_ci" 84 | & cmake ".." "-G" "$Env:CMAKE_GENERATOR" "-DBUILD_SHARED_LIBS=$Env:BUILD_SHARED_LIBS" "-DPROJECT_ENABLE_UNITTEST=ON" ` 85 | "-DPROJECT_ENABLE_SAMPLE=ON" "-DPROJECT_ENABLE_TOOLS=ON" "-DATBUS_MACRO_ABORT_ON_PROTECTED_ERROR=ON" ` 86 | "-DATFRAMEWORK_CMAKE_TOOLSET_THIRD_PARTY_PROTOBUF_ALLOW_SHARED_LIBS=OFF" ` 87 | "-DCMAKE_SYSTEM_VERSION=$selectWinSDKVersion" "-DATFRAMEWORK_CMAKE_TOOLSET_THIRD_PARTY_LOW_MEMORY_MODE=ON" 88 | if ( $LastExitCode -ne 0 ) { 89 | exit $LastExitCode 90 | } 91 | 92 | $ALL_DLL_FILES = Get-ChildItem -Path "../third_party/install/*.dll" -Recurse 93 | $ALL_DLL_DIRS = $(foreach ($dll_file in $ALL_DLL_FILES) { 94 | $dll_file.Directory.FullName 95 | }) | Sort-Object | Get-Unique 96 | $Env:PATH = ($ALL_DLL_DIRS -Join [IO.Path]::PathSeparator) + [IO.Path]::PathSeparator + $Env:PATH 97 | Write-Output "PATH=$Env:PATH" 98 | 99 | & cmake --build . --config $Env:CONFIGURATION 100 | if ( $LastExitCode -ne 0 ) { 101 | exit $LastExitCode 102 | } 103 | & ctest . -V -C $Env:CONFIGURATION -L libatbus.unit_test 104 | if ( $LastExitCode -ne 0 ) { 105 | exit $LastExitCode 106 | } 107 | } 108 | 109 | Set-Location $WORK_DIR 110 | -------------------------------------------------------------------------------- /ci/do_ci.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd "$(cd "$(dirname $0)" && pwd)/.." 4 | 5 | set -ex 6 | 7 | if [[ -z "$CONFIGURATION" ]]; then 8 | CONFIGURATION=RelWithDebInfo 9 | fi 10 | 11 | if [[ "x$USE_CC" == "xclang-latest" ]]; then 12 | echo '#include 13 | int main() { std::cout<<"Hello"; }' >test-libc++.cpp 14 | SELECT_CLANG_VERSION="" 15 | SELECT_CLANG_HAS_LIBCXX=1 16 | clang -x c++ -stdlib=libc++ test-libc++.cpp -lc++ -lc++abi || SELECT_CLANG_HAS_LIBCXX=0 17 | if [[ $SELECT_CLANG_HAS_LIBCXX -eq 0 ]]; then 18 | CURRENT_CLANG_VERSION=$(clang -x c /dev/null -dM -E | grep __clang_major__ | awk '{print $NF}') 19 | for ((i = $CURRENT_CLANG_VERSION + 5; $i >= $CURRENT_CLANG_VERSION; --i)); do 20 | SELECT_CLANG_HAS_LIBCXX=1 21 | SELECT_CLANG_VERSION="-$i" 22 | clang$SELECT_CLANG_VERSION -x c++ -stdlib=libc++ test-libc++.cpp -lc++ -lc++abi || SELECT_CLANG_HAS_LIBCXX=0 23 | if [[ $SELECT_CLANG_HAS_LIBCXX -eq 1 ]]; then 24 | break 25 | fi 26 | done 27 | fi 28 | SELECT_CLANGPP_BIN=clang++$SELECT_CLANG_VERSION 29 | LINK_CLANGPP_BIN=0 30 | which $SELECT_CLANGPP_BIN || LINK_CLANGPP_BIN=1 31 | if [[ $LINK_CLANGPP_BIN -eq 1 ]]; then 32 | mkdir -p .local/bin 33 | ln -s "$(which "clang$SELECT_CLANG_VERSION")" "$PWD/.local/bin/clang++$SELECT_CLANG_VERSION" 34 | export PATH="$PWD/.local/bin:$PATH" 35 | fi 36 | export USE_CC=clang$SELECT_CLANG_VERSION 37 | elif [[ "x$USE_CC" == "xgcc-latest" ]]; then 38 | CURRENT_GCC_VERSION=$(gcc -x c /dev/null -dM -E | grep __GNUC__ | awk '{print $NF}') 39 | echo '#include 40 | int main() { std::cout<<"Hello"; }' >test-gcc-version.cpp 41 | let LAST_GCC_VERSION=$CURRENT_GCC_VERSION+10 42 | for ((i = $CURRENT_GCC_VERSION; $i <= $LAST_GCC_VERSION; ++i)); do 43 | TEST_GCC_VERSION=1 44 | g++-$i -x c++ test-gcc-version.cpp || TEST_GCC_VERSION=0 45 | if [[ $TEST_GCC_VERSION -eq 0 ]]; then 46 | break 47 | fi 48 | CURRENT_GCC_VERSION=$i 49 | done 50 | export USE_CC=gcc-$CURRENT_GCC_VERSION 51 | echo "Using $USE_CC" 52 | fi 53 | 54 | if [[ "$1" == "format" ]]; then 55 | python3 -m pip install --user -r ./ci/requirements.txt 56 | export PATH="$HOME/.local/bin:$PATH" 57 | bash ./ci/format.sh 58 | CHANGED="$(git -c core.autocrlf=true ls-files --modified)" 59 | if [[ ! -z "$CHANGED" ]]; then 60 | echo "The following files have changes:" 61 | echo "$CHANGED" 62 | git diff 63 | # exit 1 ; # Just warning, some versions of clang-format have different default style for unsupport syntax 64 | fi 65 | exit 0 66 | elif [[ "$1" == "coverage" ]]; then 67 | CONFIGURATION=Debug 68 | vcpkg install --triplet=$VCPKG_TARGET_TRIPLET fmt openssl libuv 69 | CRYPTO_OPTIONS="-DATFRAMEWORK_CMAKE_TOOLSET_THIRD_PARTY_CRYPTO_USE_OPENSSL=ON" 70 | bash cmake_dev.sh -lus -b $CONFIGURATION -r build_jobs_coverage -c $USE_CC -- $CRYPTO_OPTIONS "-DCMAKE_C_FLAGS=$GCOV_FLAGS" "-DCMAKE_CXX_FLAGS=$GCOV_FLAGS" \ 71 | "-DCMAKE_EXE_LINKER_FLAGS=$GCOV_FLAGS" -DCMAKE_TOOLCHAIN_FILE=$VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake \ 72 | -DVCPKG_TARGET_TRIPLET=$VCPKG_TARGET_TRIPLET -DATBUS_MACRO_ABORT_ON_PROTECTED_ERROR=ON "-DATFRAMEWORK_CMAKE_TOOLSET_THIRD_PARTY_LOW_MEMORY_MODE=ON" 73 | cd build_jobs_coverage 74 | cmake --build . -j --config $CONFIGURATION || cmake --build . --config $CONFIGURATION 75 | ctest -VV . -C $CONFIGURATION -L libatbus.unit_test 76 | timeout 5s ./tools/benchmark_shm_channel_recv 12345679 1024 4194304 >recv.log 2>&1 & 77 | timeout 6s ./tools/benchmark_shm_channel_send 12345679 1024 4194304 >send.log 2>&1 || true 78 | ./tools/show_shm_channel 12345679 1 16 >/dev/null || true 79 | elif [[ "$1" == "codeql.configure" ]]; then 80 | CONFIGURATION=Debug 81 | vcpkg install --triplet=$VCPKG_TARGET_TRIPLET fmt openssl libuv 82 | CRYPTO_OPTIONS="-DATFRAMEWORK_CMAKE_TOOLSET_THIRD_PARTY_CRYPTO_USE_OPENSSL=ON" 83 | bash cmake_dev.sh -lus -b $CONFIGURATION -r build_jobs_coverage -c $USE_CC -- $CRYPTO_OPTIONS "-DCMAKE_C_FLAGS=$GCOV_FLAGS" "-DCMAKE_CXX_FLAGS=$GCOV_FLAGS" \ 84 | "-DCMAKE_EXE_LINKER_FLAGS=$GCOV_FLAGS" -DCMAKE_TOOLCHAIN_FILE=$VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake \ 85 | -DVCPKG_TARGET_TRIPLET=$VCPKG_TARGET_TRIPLET -DATBUS_MACRO_ABORT_ON_PROTECTED_ERROR=ON "-DATFRAMEWORK_CMAKE_TOOLSET_THIRD_PARTY_LOW_MEMORY_MODE=ON" 86 | elif [[ "$1" == "codeql.build" ]]; then 87 | CONFIGURATION=Debug 88 | cd build_jobs_coverage 89 | cmake --build . -j --config $CONFIGURATION || cmake --build . --config $CONFIGURATION 90 | ctest -VV . -C $CONFIGURATION -L libatbus.unit_test 91 | timeout 5s ./tools/benchmark_shm_channel_recv 12345679 1024 4194304 >recv.log 2>&1 & 92 | timeout 6s ./tools/benchmark_shm_channel_send 12345679 1024 4194304 >send.log 2>&1 || true 93 | ./tools/show_shm_channel 12345679 1 16 >/dev/null || true 94 | elif [[ "$1" == "ssl.openssl" ]]; then 95 | CRYPTO_OPTIONS="-DATFRAMEWORK_CMAKE_TOOLSET_THIRD_PARTY_CRYPTO_USE_OPENSSL=ON" 96 | vcpkg install --triplet=$VCPKG_TARGET_TRIPLET fmt openssl libuv 97 | bash cmake_dev.sh -lus -b $CONFIGURATION -r build_jobs_ci -c $USE_CC -- $CRYPTO_OPTIONS -DVCPKG_TARGET_TRIPLET=$VCPKG_TARGET_TRIPLET \ 98 | -DCMAKE_TOOLCHAIN_FILE=$VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake -DATBUS_MACRO_ABORT_ON_PROTECTED_ERROR=ON \ 99 | "-DATFRAMEWORK_CMAKE_TOOLSET_THIRD_PARTY_LOW_MEMORY_MODE=ON" 100 | cd build_jobs_ci 101 | cmake --build . -j --config $CONFIGURATION || cmake --build . --config $CONFIGURATION 102 | ctest -VV . -C $CONFIGURATION -L libatbus.unit_test 103 | elif [[ "$1" == "gcc.legacy.test" ]]; then 104 | bash cmake_dev.sh -lus -b $CONFIGURATION -r build_jobs_ci -c $USE_CC -- "-DATFRAMEWORK_CMAKE_TOOLSET_THIRD_PARTY_LOW_MEMORY_MODE=ON" 105 | cd build_jobs_ci 106 | cmake --build . -j --config $CONFIGURATION || cmake --build . --config $CONFIGURATION 107 | ctest -VV . -C $CONFIGURATION -L libatbus.unit_test 108 | elif [[ "$1" == "clang.test" ]]; then 109 | CRYPTO_OPTIONS="-DATFRAMEWORK_CMAKE_TOOLSET_THIRD_PARTY_CRYPTO_USE_OPENSSL=ON" 110 | bash cmake_dev.sh -lus -b $CONFIGURATION -r build_jobs_ci -c $USE_CC -- $CRYPTO_OPTIONS -DATBUS_MACRO_ABORT_ON_PROTECTED_ERROR=ON \ 111 | "-DATFRAMEWORK_CMAKE_TOOLSET_THIRD_PARTY_LOW_MEMORY_MODE=ON" 112 | cd build_jobs_ci 113 | cmake --build . -j --config $CONFIGURATION || cmake --build . --config $CONFIGURATION 114 | ctest -VV . -C $CONFIGURATION -L libatbus.unit_test 115 | elif [[ "$1" == "msys2.mingw.test" ]]; then 116 | pacman -S --needed --noconfirm mingw-w64-x86_64-cmake mingw-w64-x86_64-make \ 117 | mingw-w64-x86_64-curl mingw-w64-x86_64-wget mingw-w64-x86_64-perl \ 118 | mingw-w64-x86_64-git-lfs mingw-w64-x86_64-toolchain mingw-w64-x86_64-libtool \ 119 | mingw-w64-x86_64-python mingw-w64-x86_64-python-pip mingw-w64-x86_64-python-setuptools || true 120 | echo "PATH=$PATH" 121 | # git config --global http.sslBackend openssl || true 122 | # pacman -S --needed --noconfirm mingw-w64-x86_64-protobuf 123 | mkdir -p build_jobs_ci 124 | cd build_jobs_ci 125 | cmake .. -G 'MinGW Makefiles' "-DBUILD_SHARED_LIBS=$BUILD_SHARED_LIBS" -DCMAKE_BUILD_TYPE=$CONFIGURATION -DPROJECT_ENABLE_UNITTEST=ON \ 126 | -DPROJECT_ENABLE_SAMPLE=ON -DPROJECT_ENABLE_TOOLS=ON -DATBUS_MACRO_ABORT_ON_PROTECTED_ERROR=ON \ 127 | -DATFRAMEWORK_CMAKE_TOOLSET_THIRD_PARTY_PROTOBUF_ALLOW_SHARED_LIBS=OFF \ 128 | "-DATFRAMEWORK_CMAKE_TOOLSET_THIRD_PARTY_LOW_MEMORY_MODE=ON" 129 | cmake --build . -j --config $CONFIGURATION || cmake --build . --config $CONFIGURATION 130 | # for EXT_PATH in $(find ../third_party/install/ -name "*.dll" | xargs dirname | sort -u); do 131 | # export PATH="$PWD/$EXT_PATH:$PATH" 132 | # done 133 | # ctest -VV . -C $CONFIGURATION -L libatbus.unit_test 134 | fi 135 | -------------------------------------------------------------------------------- /ci/format.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | find . -type f \ 4 | -regex "^./third_party/packages/.*" -prune \ 5 | -o -regex "^./third_party/install/.*" -prune \ 6 | -o -regex "^./build_jobs_.*" -prune \ 7 | -o -regex "^./atframework/cmake-toolset/.*" -prune \ 8 | -o -regex "^./atframework/atframe_utils/.*" -prune \ 9 | -o -name "*.cmake" -print \ 10 | -o -name "*.cmake.in" -print \ 11 | -o -name 'CMakeLists.txt' -print \ 12 | | xargs cmake-format -i 13 | 14 | find . -type f \ 15 | -regex "^./third_party/packages/.*" -prune \ 16 | -o -regex "^./third_party/install/.*" -prune \ 17 | -o -regex "^./build_jobs_.*" -prune \ 18 | -o -regex "^./atframework/cmake-toolset/.*" -prune \ 19 | -o -regex "^./atframework/atframe_utils/.*" -prune \ 20 | -o -name "*.h" -print \ 21 | -o -name "*.hpp" -print \ 22 | -o -name "*.cxx" -print \ 23 | -o -name '*.cpp' -print \ 24 | -o -name '*.cc' -print \ 25 | -o -name '*.c' -print \ 26 | | xargs -r -n 32 clang-format -i --style=file --fallback-style=none 27 | -------------------------------------------------------------------------------- /ci/requirements.txt: -------------------------------------------------------------------------------- 1 | cmake-format>=0.6.13 2 | PyYAML>=5.4.1 3 | -------------------------------------------------------------------------------- /cmake_dev.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SYS_NAME="$(uname -s)"; 4 | SYS_NAME="$(basename $SYS_NAME)"; 5 | CC=gcc; 6 | CXX=g++; 7 | CCACHE="$(which ccache)"; 8 | DISTCC=""; 9 | if [ ! -z "$DISTCC_HOSTS" ]; then 10 | DISTCC="$(which distcc 2>/dev/null)"; 11 | fi 12 | 13 | 14 | NINJA_BIN="$(which ninja 2>&1)"; 15 | if [ $? -ne 0 ]; then 16 | NINJA_BIN="$(which ninja-build 2>&1)"; 17 | if [ $? -ne 0 ]; then 18 | NINJA_BIN=""; 19 | fi 20 | fi 21 | 22 | CMAKE_OPTIONS=""; 23 | CMAKE_CLANG_TIDY=""; 24 | CMAKE_CLANG_ANALYZER=0; 25 | CMAKE_CLANG_ANALYZER_PATH=""; 26 | BUILD_DIR=$(echo "build_jobs_$SYS_NAME" | tr '[:upper:]' '[:lower:]'); 27 | CMAKE_BUILD_TYPE=Debug; 28 | 29 | if [ ! -z "$MSYSTEM" ]; then 30 | CHECK_MSYS=$(echo "${MSYSTEM:0:5}" | tr '[:upper:]' '[:lower:]'); 31 | else 32 | CHECK_MSYS=""; 33 | fi 34 | 35 | while getopts "ab:c:d:e:hlm:o:pr:stu-" OPTION; do 36 | case $OPTION in 37 | a) 38 | echo "Ready to check ccc-analyzer and c++-analyzer, please do not use -c to change the compiler when using clang-analyzer."; 39 | export CCC_CC="$CC" ; 40 | export CCC_CXX="$CXX" ; 41 | 42 | CC=$(which ccc-analyzer); 43 | CXX=$(which c++-analyzer); 44 | if [ 0 -ne $? ]; then 45 | # check mingw path 46 | if [ "mingw" == "$CHECK_MSYS" ]; then 47 | if [ ! -z "$MINGW_MOUNT_POINT" ] && [ -e "$MINGW_MOUNT_POINT/libexec/ccc-analyzer.bat" ] && [ -e "$MINGW_MOUNT_POINT/libexec/ccc-analyzer.bat" ]; then 48 | echo "clang-analyzer found in $MINGW_MOUNT_POINT"; 49 | export PATH=$PATH:$MINGW_MOUNT_POINT/libexec ; 50 | CC="$MINGW_MOUNT_POINT/libexec/ccc-analyzer.bat"; 51 | CXX="$MINGW_MOUNT_POINT/libexec/ccc-analyzer.bat"; 52 | CMAKE_CLANG_ANALYZER_PATH="$MINGW_MOUNT_POINT/libexec"; 53 | elif [ ! -z "$MINGW_PREFIX" ] && [ -e "$MINGW_PREFIX/libexec/ccc-analyzer.bat" ] && [ -e "$MINGW_PREFIX/libexec/c++-analyzer.bat" ]; then 54 | echo "clang-analyzer found in $MINGW_PREFIX"; 55 | export PATH=$PATH:$MINGW_PREFIX/libexec ; 56 | CC="$MINGW_PREFIX/libexec/ccc-analyzer.bat"; 57 | CXX="$MINGW_PREFIX/libexec/ccc-analyzer.bat"; 58 | CMAKE_CLANG_ANALYZER_PATH="$MINGW_PREFIX/libexec"; 59 | fi 60 | fi 61 | fi 62 | 63 | if [ -z "$CC" ] || [ -z "$CXX" ]; then 64 | echo "ccc-analyzer=$CC"; 65 | echo "c++-analyzer=$CXX"; 66 | echo "clang-analyzer not found, failed."; 67 | exit 1; 68 | fi 69 | echo "ccc-analyzer=$CC"; 70 | echo "c++-analyzer=$CXX"; 71 | echo "clang-analyzer setup completed."; 72 | CMAKE_CLANG_ANALYZER=1; 73 | BUILD_DIR="${BUILD_DIR}_analyzer"; 74 | ;; 75 | b) 76 | CMAKE_BUILD_TYPE="$OPTARG"; 77 | ;; 78 | c) 79 | if [[ $CMAKE_CLANG_ANALYZER -ne 0 ]]; then 80 | CCC_CC="$OPTARG"; 81 | CCC_CXX="${CCC_CC/%clang/clang++}"; 82 | CCC_CXX="${CCC_CXX/%gcc/g++}"; 83 | export CCC_CC; 84 | export CCC_CXX; 85 | else 86 | CC="$OPTARG"; 87 | CXX="$(echo "$CC" | sed 's/\(.*\)clang/\1clang++/')"; 88 | CXX="$(echo "$CXX" | sed 's/\(.*\)gcc/\1g++/')"; 89 | fi 90 | ;; 91 | d) 92 | DISTCC="$OPTARG"; 93 | ;; 94 | e) 95 | CCACHE="$OPTARG"; 96 | ;; 97 | h) 98 | echo "usage: $0 [options] [-- [cmake options...] ]"; 99 | echo "options:"; 100 | echo "-a using clang-analyzer."; 101 | echo "-c compiler toolchains(gcc, clang or others)."; 102 | echo "-d try to use specify distcc to speed up building."; 103 | echo "-e try to use specify ccache to speed up building."; 104 | echo "-h help message."; 105 | echo "-m [mbedtls root] set root of mbedtls."; 106 | echo "-o [openssl root] set root of openssl."; 107 | echo "-p abort on inner error."; 108 | echo "-t enable clang-tidy."; 109 | echo "-u enable unit test."; 110 | echo "-s enable sample."; 111 | echo "-l enable tools."; 112 | exit 0; 113 | ;; 114 | l) 115 | CMAKE_OPTIONS="$CMAKE_OPTIONS -DPROJECT_ENABLE_TOOLS=YES"; 116 | ;; 117 | m) 118 | if [ ! -z "$OPTARG" ]; then 119 | CMAKE_OPTIONS="$CMAKE_OPTIONS -DMBEDTLS_ROOT=$OPTARG"; 120 | else 121 | CMAKE_OPTIONS="$CMAKE_OPTIONS -DMBEDTLS_ROOT=c:/workspace/lib/crypt/prebuilt/win64"; 122 | fi 123 | ;; 124 | o) 125 | if [ ! -z "$OPTARG" ]; then 126 | CMAKE_OPTIONS="$CMAKE_OPTIONS -DOPENSSL_ROOT_DIR=$OPTARG"; 127 | else 128 | CMAKE_OPTIONS="$CMAKE_OPTIONS -DOPENSSL_ROOT_DIR=c:/workspace/lib/crypt/prebuilt/openssl-1.0.2h-vs2015"; 129 | fi 130 | ;; 131 | p) 132 | CMAKE_OPTIONS="$CMAKE_OPTIONS -DATBUS_MACRO_ABORT_ON_PROTECTED_ERROR=YES"; 133 | ;; 134 | r) 135 | CUSTOM_BUILD_DIR="$OPTARG"; 136 | ;; 137 | s) 138 | CMAKE_OPTIONS="$CMAKE_OPTIONS -DPROJECT_ENABLE_SAMPLE=YES"; 139 | ;; 140 | t) 141 | CMAKE_CLANG_TIDY="-D -checks=* --"; 142 | ;; 143 | u) 144 | CMAKE_OPTIONS="$CMAKE_OPTIONS -DPROJECT_ENABLE_UNITTEST=YES"; 145 | ;; 146 | -) 147 | break; 148 | ;; 149 | ?) 150 | echo "unkonw argument detected"; 151 | exit 1; 152 | ;; 153 | esac 154 | done 155 | 156 | shift $(($OPTIND - 1)); 157 | SCRIPT_DIR="$(cd $(dirname $0) && pwd)"; 158 | 159 | if [[ "x$CUSTOM_BUILD_DIR" != "x" ]]; then 160 | BUILD_DIR="$CUSTOM_BUILD_DIR"; 161 | fi 162 | 163 | mkdir -p "$SCRIPT_DIR/$BUILD_DIR"; 164 | cd "$SCRIPT_DIR/$BUILD_DIR"; 165 | 166 | if [ ! -z "$DISTCC" ] && [ "$DISTCC" != "disable" ] && [ "$DISTCC" != "disabled" ] && [ "$DISTCC" != "no" ] && [ "$DISTCC" != "false" ] && [ -e "$DISTCC" ]; then 167 | CMAKE_OPTIONS="$CMAKE_OPTIONS -DCMAKE_C_COMPILER_LAUNCHER=$DISTCC -DCMAKE_CXX_COMPILER_LAUNCHER=$DISTCC -DCMAKE_C_COMPILER=$CC -DCMAKE_CXX_COMPILER=$CXX"; 168 | elif [ ! -z "$CCACHE" ] && [ "$CCACHE" != "disable" ] && [ "$CCACHE" != "disabled" ] && [ "$CCACHE" != "no" ] && [ "$CCACHE" != "false" ] && [ -e "$CCACHE" ]; then 169 | #CMAKE_OPTIONS="$CMAKE_OPTIONS -DCMAKE_C_COMPILER=$CCACHE -DCMAKE_CXX_COMPILER=$CCACHE -DCMAKE_C_COMPILER_ARG1=$CC -DCMAKE_CXX_COMPILER_ARG1=$CXX"; 170 | CMAKE_OPTIONS="$CMAKE_OPTIONS -DCMAKE_C_COMPILER_LAUNCHER=$CCACHE -DCMAKE_CXX_COMPILER_LAUNCHER=$CCACHE -DCMAKE_C_COMPILER=$CC -DCMAKE_CXX_COMPILER=$CXX"; 171 | else 172 | CMAKE_OPTIONS="$CMAKE_OPTIONS -DCMAKE_C_COMPILER=$CC -DCMAKE_CXX_COMPILER=$CXX"; 173 | fi 174 | 175 | if [ "x$NINJA_BIN" != "x" ]; then 176 | cmake .. -G Ninja -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE $CMAKE_OPTIONS "$@"; 177 | elif [ "$CHECK_MSYS" == "mingw" ]; then 178 | cmake .. -G "MSYS Makefiles" -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE $CMAKE_OPTIONS "$@"; 179 | else 180 | cmake .. -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE $CMAKE_OPTIONS "$@"; 181 | fi 182 | 183 | 184 | if [ 1 -eq $CMAKE_CLANG_ANALYZER ]; then 185 | echo "========================================================================================================="; 186 | CMAKE_CLANG_ANALYZER_OPTIONS=""; 187 | if [ -e "$SCRIPT_DIR/.scan-build.enable" ]; then 188 | for OPT in $(cat "$SCRIPT_DIR/.scan-build.enable"); do 189 | CMAKE_CLANG_ANALYZER_OPTIONS="$CMAKE_CLANG_ANALYZER_OPTIONS -enable-checker $OPT"; 190 | done 191 | fi 192 | 193 | if [ -e "$SCRIPT_DIR/.scan-build.disable" ]; then 194 | for OPT in $(cat "$SCRIPT_DIR/.scan-build.disable"); do 195 | CMAKE_CLANG_ANALYZER_OPTIONS="$CMAKE_CLANG_ANALYZER_OPTIONS -disable-checker $OPT"; 196 | done 197 | fi 198 | 199 | if [ -z "$CMAKE_CLANG_ANALYZER_PATH" ]; then 200 | echo "cd '$SCRIPT_DIR/$BUILD_DIR' && scan-build -o report --html-title='atsf4g-co static analysis' $CMAKE_CLANG_ANALYZER_OPTIONS make -j4"; 201 | else 202 | echo "cd '$SCRIPT_DIR/$BUILD_DIR' && env PATH=\"\$PATH:$CMAKE_CLANG_ANALYZER_PATH\" scan-build -o report --html-title='libatbus static analysis' $CMAKE_CLANG_ANALYZER_OPTIONS make -j4"; 203 | fi 204 | echo "Now, you can run those code above to get a static analysis report"; 205 | echo "You can get help and binary of clang-analyzer and scan-build at http://clang-analyzer.llvm.org/scan-build.html" 206 | fi 207 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "**/sample/**" 3 | - "**/test/**" 4 | - "**/tools/**" 5 | - "**/build_jobs_coverage/CMakeFiles/**" 6 | - "**/docs/**" 7 | - "**/include/libatbus_protocol.pb.h" 8 | - "**/src/libatbus_protocol.pb.cc" 9 | - "**/third_party/**" 10 | - "**/atframework/**" -------------------------------------------------------------------------------- /docs/Benchmark.md: -------------------------------------------------------------------------------- 1 | 2 | Benchmark - Run On 2016-07-07 3 | ====== 4 | 环境 5 | ------ 6 | + 环境: CentOS 7.1, GCC 4.8.5 7 | + CPU: Xeon E3-1230 v2 3.30GHz*8 (sender和receiver都只用一个核心) 8 | + 内存: 24GB (这是总内存,具体使用数根据配置不同而不同) 9 | + 网络: 千兆网卡 * 1 10 | + 编译选项: -O2 -g -DNDEBUG -ggdb -Wall -Werror -Wno-unused-local-typedefs -std=gnu++11 -D_POSIX_MT_ 11 | + 配置选项: -DATBUS_MACRO_BUSID_TYPE=uint64_t -DATBUS_MACRO_CONNECTION_BACKLOG=128 -DATBUS_MACRO_CONNECTION_CONFIRM_TIMEOUT=30 -DATBUS_MACRO_DATA_ALIGN_TYPE=uint64_t -DATBUS_MACRO_DATA_NODE_SIZE=128 -DATBUS_MACRO_DATA_SMALL_SIZE=3072 -DATBUS_MACRO_HUGETLB_SIZE=4194304 -DATBUS_MACRO_MSG_LIMIT=65536 12 | 13 | 14 | 测试项 | 连接数 | 包长度 | CPU消耗 | 内存消耗 | 吞吐量 | QPS 15 | ----------------------------------------|----------------|---------------------|-----------------|--------------|--------------|--------------- 16 | Linux+本地回环+ipv6+静态缓冲区 | 1 | 8-16384字节 | 90%/100% | 5.8MB/24MB | 601MB/s | 95K/s 17 | Linux+本地回环+ipv6+静态缓冲区 | 1 | 8-128字节(模拟ping包) | 48%/100% | 5.8MB/27MB | 163MB/s | 2822K/s 18 | Linux+本地回环+ipv6+动态缓冲区(ptmalloc) | 1 | 8-16384字节 | 90%/100% | 5.8MB/24MB | 607MB/s | 96K/s 19 | Linux+本地回环+ipv6+动态缓冲区(ptmalloc) | 1 | 8-128字节(模拟ping包) | 48%/100% | 5.8MB/27MB | 165MB/s | 2857K/s 20 | Linux+共享内存 | 1 | 8-16384字节 | 98%/98% | 74MB/74MB | 1.56GB/s | 199K/s 21 | Linux+共享内存 | 1 | 8-128字节(模拟ping包) | 100%/83% | 74MB/74MB | 303MB/s | 5253K/s 22 | 23 | 24 | 压力测试说明 25 | ------ 26 | 27 | 1. 动态缓冲区指发送者发送缓冲区使用malloc和free来保存发送中的数据,静态缓冲区指使用内置的内存池来缓存。 28 | 2. 由于发送者的CPU消耗会高于接收者(接收者没有任何逻辑,发送者会有一次随机数操作),所以动态缓冲区时其实内存会持续增加。(内存碎片原因,实际测试过程中3分钟由20MB涨到28MB) 29 | 3. Windows下除了不支持Unix Socket外,共享内存和ipv4/ipv6连接都是支持的,但是没有跑压力测试。 30 | 31 | *PS: 目前没写多连接测试工具,后面有空再写吧* 32 | 33 | 测试命令如下(需要把tools/script里的脚本拷贝到[构建目录]/tools内) 34 | ------ 35 | 36 | ```bash 37 | # Linux+本地回环+ipv6+静态缓冲区:8-16384字节 测试命令 38 | ./startup_benchmark_io_stream.sh ipv6://::1:16389 2048 4194304 8096 39 | 40 | # Linux+本地回环+ipv6+静态缓冲区:8-128字节(模拟ping包) 测试命令 41 | ./startup_benchmark_io_stream.sh ipv6://::1:16389 16 4194304 8096 42 | 43 | # Linux+本地回环+动态缓冲区(ptmalloc):8-16384字节 测试命令 44 | ./startup_benchmark_io_stream.sh ipv6://::1:16389 2048 4194304 0 45 | 46 | # Linux+本地回环+动态缓冲区(ptmalloc):8-128字节(模拟ping包) 测试命令 47 | ./startup_benchmark_io_stream.sh ipv6://::1:16389 16 4194304 0 48 | 49 | # Linux+共享内存:8-16384字节 测试命令 50 | ./startup_benchmark_shm.sh 12345679 2048 51 | 52 | # Linux+共享内存:8-128字节(模拟ping包) 测试命令 53 | ./startup_benchmark_shm.sh 12345679 16 54 | ``` 55 | 56 | 57 | 对比tsf4g性能测试报告 - Run On 2014-01-14 58 | ------ 59 | + 环境: tlinux 1.0.7 (based on CentOS 6.2), GCC 4.8.2, gperftools 2.1(启用tcmalloc和cpu profile) 60 | + CPU: Xeon X3440 2.53GHz*8 61 | + 内存: 8GB (这是总内存,具体使用数根据配置不同而不同) 62 | + 网络: 千兆网卡 * 1 63 | + 编译选项: -O2 -g -DNDEBUG -ggdb -Wall -Werror -Wno-unused-local-typedefs -std=gnu++11 -D_POSIX_MT_ 64 | + 配置选项: 无 65 | 66 | 测试项 | 连接数 | 包长度 | CPU消耗 | 内存消耗 | 吞吐量 | QPS 67 | ----------------------------------------|--------------------|---------------------|-----------------|--------------|--------------|--------------- 68 | Linux+跨机器转发+ipv4 | 2(仅一个连接压力测试) | 16KB | 13%/100% | 280MB | 86.4MB/s | 5.4K/s 69 | Linux+跨机器转发+ipv4 | 2(仅一个连接压力测试) | 8KB | 13%/100% | 280MB | 96MB/s | 12K/s 70 | Linux+跨机器转发+ipv4 | 2(仅一个连接压力测试) | 4KB | 13%/100% | 280MB | 92MB/s | 23K/s 71 | Linux+跨机器转发+ipv4 | 2(仅一个连接压力测试) | 2KB | 15%/100% | 280MB | 88MB/s | 44K/s 72 | Linux+跨机器转发+ipv4 | 2(仅一个连接压力测试) | 1KB | 16%/100% | 280MB | 82MB/s | 82K/s 73 | Linux+跨机器转发+ipv4 | 2(仅一个连接压力测试) | 512字节 | 22%/100% | 280MB | 79.5MB/s | 159K/s 74 | Linux+跨机器转发+ipv4 | 2(仅一个连接压力测试) | 256字节 | 33%/100% | 280MB | 73.5MB/s | 294K/s 75 | Linux+跨机器转发+ipv4 | 2(仅一个连接压力测试) | 128字节 | 50%/100% | 280MB | 65.75MB/s | 526K/s 76 | Linux+共享内存 | 3(仅一个连接压力测试) | 32KB | 100%/100% | 280MB | 3.06GB/s | 98K/s 77 | Linux+共享内存 | 3(仅一个连接压力测试) | 16KB | 61%/71% | 280MB | 1.59GB/s | 102K/s 78 | Linux+共享内存 | 3(仅一个连接压力测试) | 8KB | 36%/70% | 280MB | 1.27GB/s | 163K/s 79 | Linux+共享内存 | 3(仅一个连接压力测试) | 4KB | 40%/73% | 280MB | 1.30MB/s | 333K/s 80 | Linux+共享内存 | 3(仅一个连接压力测试) | 2KB | 43%/93% | 280MB | 1.08GB/s | 556K/s 81 | Linux+共享内存 | 3(仅一个连接压力测试) | 1KB | 54%/100% | 280MB | 977MB/s | 1000K/s 82 | Linux+共享内存 | 3(仅一个连接压力测试) | 512字节 | 44%/100% | 280MB | 610MB/s | 1250K/s 83 | Linux+共享内存 | 3(仅一个连接压力测试) | 256字节 | 42%/100% | 280MB | 305MB/s | 1250K/s 84 | Linux+共享内存 | 3(仅一个连接压力测试) | 128字节 | 42%/100% | 280MB | 174MB/s | 1429K/s 85 | 86 | 87 | 对比结果分析: 88 | 89 | 1. atbus的吞吐量基本上高于tbus 90 | 2. [共享内存] QPS方面,atbus比tbus的的发送端性能高,接收端相近 91 | -------------------------------------------------------------------------------- /docs/Build.md: -------------------------------------------------------------------------------- 1 | # 使用(编译)流程 2 | 3 | ## 依赖工具集合库 4 | 5 | + 支持c++0x或c++11的编译器(为了代码尽量简洁,特别是少做无意义的平台兼容,依赖部分 C11和C++11的功能,所以不支持过低版本的编译器) 6 | 7 | > + GCC: 4.8 及以上 8 | > + Clang: 7.0 及以上 9 | > + MSVC: VS 2019 及以上 10 | 11 | + [cmake](https://cmake.org/download/) 3.24.0 以上 12 | + [protobuf](https://github.com/protocolbuffers/protobuf) 13 | 14 | > 用于协议打解包,仅使用头文件 15 | 16 | + [libuv](http://libuv.org/)(用于网络通道) 17 | 18 | > 用于协议打解包,仅使用头文件 19 | > 20 | > 手动编译libuv则需要额外的软件集,基本有: gcc/clang/msvc, autoconf, automake, make, pthread, m4 21 | 22 | + [atframe_utils](https://github.com/atframework/atframe_utils)(基础公共代码,检测到不存在会自动下载) 23 | + (可选)[python](http://python.org/) (周边工具集) 24 | + (可选)tar, curl, wget: 如果使用内置的脚本自动构建依赖的库,则这些是必要的工具 25 | 26 | ## 环境准备(开发环境最小依赖) 27 | 28 | ### Windows + MSVC 29 | 30 | 1. [cmake](https://cmake.org/download/) 31 | 2. [visual studio](https://www.visualstudio.com) 32 | 3. [libuv](http://dist.libuv.org/dist) 33 | 4. 执行 mkdir build && cd build && cmake .. -G "Visual Studio 15 2017 Win64" -DLIBUV_ROOT=[libuv安装目录] -DFlatbuffers_ROOT=[flatbuffers的安装目录] 34 | 5. 编译打开Visual Studio编译或 cmake --build . --config RelWithDebInfo 35 | 36 | 详情可参考 [Appceyor CI](../appveyor.yml) 脚本 37 | 38 | 或者也可以选择使用nmake编译。 39 | 40 | **生成目标(-G 选项的值)请按自己所在环境手动修改,否则会使用默认的配置,MSVC的默认会生成x86版本的工程文件** 41 | 42 | 上面最后一条命令可以根据实际环境修改参数,这里只提供一个示例 43 | 44 | ### Windows + MinGW(msys2) 45 | 46 | 1. 安装[Msys2](http://msys2.github.io/) 47 | 2. Msys2里安装依赖组件 48 | > ```bash 49 | > for pkg_name in git m4 curl wget tar autoconf automake mingw-w64-i686-toolchain mingw-w64-x86_64-toolchain mingw-w64-x86_64-libtool mingw-w64-i686-libtool python; do pacman -S --noconfirm --needed $pkg_name; done 50 | > ``` 51 | > 具体可以根据 编译目标裁剪,这里把32位和64位依赖库都安装上了 52 | 53 | 3. MinGW shell 下执行cmake构建命令 54 | > 注意一定是要MingGW的shell(libuv不支持msys shell),msys2默认开启的是msys shell 55 | > 56 | > 通常情况下可以通过以下方式打开MingGW shell 57 | > + C:\msys64\mingw32.exe -- 32位 58 | > + C:\msys64\mingw64.exe -- 64位 59 | > 60 | > 请指定生成 MSYS Makefiles 工程文件(-G "MSYS Makefiles") 61 | 62 | 其他MinGW环境请自行安装依赖库 63 | 64 | 详情可参考 [Appceyor CI](../appveyor.yml) 脚本 65 | 66 | ### Linux 67 | 1. gcc 4.4及以上 68 | 2. autoconf 69 | 3. gdb 70 | 4. valgrind 71 | 5. curl 72 | 6. wget 73 | 7. tar 74 | 8. m4 75 | 9. cmake 76 | 10. automake 77 | 11. make 78 | 12. git 79 | 80 | 以上请用Linux发行版的包管理器安装,然后正常使用cmake即可 81 | 82 | 比如CentOS: 83 | 84 | ```bash 85 | yum install gcc gcc-c++ autoconf automake gdb valgrind curl wget tar m4 automake make git; 86 | wget -c "https://cmake.org/files/v3.9/cmake-3.9.4-Linux-x86_64.sh" -O "cmake-Linux-x86_64.sh"; 87 | bash cmake-Linux-x86_64.sh --skip-license --prefix=/usr ; 88 | ``` 89 | 90 | 详情可参考 [Travis CI](../.travis.yml) 脚本 91 | 92 | ### OSX 93 | 94 | 1. 安装 [brew](http://brew.sh/) 95 | 2. 安装 xcode 96 | 3. sudo brew install gcc gdb autoconf automake make curl wget tar m4 cmake git 97 | 98 | 详情可参考 [Travis CI](../.travis.yml) 脚本 99 | 100 | 编译和构建 101 | ------ 102 | 103 | ### 编译选项 104 | 105 | 除了cmake标准编译选项外,libatbus还提供一些额外选项 106 | 107 | + CMAKE_BUILD_TYPE (默认: Debug): 构建类型,目前**默认是Debug**方式构建。生产环境建议使用**-DCMAKE_BUILD_TYPE=RelWithDebInfo**(相当于gcc -O2 -g -ggdb -DNDEBUG) 108 | + LIBUV_ROOT: 手动指定libuv的安装目录 109 | + Flatbuffers_ROOT: 手动指定flatbuffers的安装目录,需要符合cmake的find_package规则,使用flatbuffers官方提供的config文件,且必须编译lib和flatc 110 | + CMAKE_MSVC_RUNTIME (默认: MD): 使用MSVC编译时默认使用MD/MDd运行时,如果需要尽可能一处依赖并使用MT请把这个值设为MT 111 | + PROJECT_ENABLE_SAMPLE (默认: NO): 是否编译Sample代码 112 | + PROJECT_ENABLE_UNITTEST (默认: NO): 是否编译单元测试代码 113 | + PROJECT_ENABLE_TOOLS (默认: NO): 是否编译工具集(主要是压力测试工具) 114 | + ============= 以上选项根据实际环境配置,以下选项不建议修改 ============= 115 | + ATBUS_MACRO_BUSID_TYPE (默认: uint64_t): busid的类型,建议不要设置成大于64位,否则需要修改protocol目录内的busid类型,并且重新生成协议文件 116 | + ATBUS_MACRO_DATA_NODE_SIZE (默认: 256): atbus的内存通道node大小(必须是2的倍数) 117 | + ATBUS_MACRO_DATA_ALIGN_SIZE (默认: 16): atbus的内存内存块对齐大小,大多数某些架构要求对齐到16 118 | + ATBUS_MACRO_DATA_SMALL_SIZE (默认: 3072): 流通道小数据块大小(用于优化减少内存拷贝) 119 | + ATBUS_MACRO_HUGETLB_SIZE (默认: 4194304): 大页表分页大小(用于优化共享内存分页,此功能暂时关闭,所以并不生效) 120 | + ATBUS_MACRO_MESSAGE_LIMIT (默认: 2097152): 默认消息体大小限制 121 | + ATBUS_MACRO_CONNECTION_CONFIRM_TIMEOUT (默认: 30): 默认连接确认时限 122 | + ATBUS_MACRO_CONNECTION_BACKLOG (默认: 128): 默认握手队列的最大连接数 123 | + ATBUS_MACRO_SHM_MEM_CHANNEL_LENGTH (默认: 8388608): 共享内存和内存通道的默认大小 124 | + ATBUS_MACRO_IOS_SEND_BUFFER_LENGTH (默认: 4194304): IO流(tcp/unix sock)发送通道的默认大小 125 | + GTEST_ROOT: 使用GTest单元测试框架 126 | + BOOST_ROOT: 设置Boost库根目录 127 | + PROJECT_TEST_ENABLE_BOOST_UNIT_TEST: 使用Boost.Test单元测试框架(如果GTEST_ROOT和此项都不设置,则使用内置单元测试框架) 128 | 129 | ### 示例构建脚本(MinGW64) 130 | 131 | ```bash 132 | git clone --depth=1 "https://github.com/atframework/libatbus.git" 133 | mkdir libatbus/build; 134 | cd libatbus/build; 135 | # cmake .. -G "MSYS Makefiles" [其他可选项] 136 | cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local/libatbus; 137 | cmake --build .; # 或 make 138 | cmake --build . --target install; # 或 make install 139 | ``` 140 | 141 | ### 运行和测试 142 | 143 | ```bash 144 | # MSVC请在构建目录下使用以下命令运行单元测试,其中Debug和之气按编译时的--config选项内容保持一致 145 | ctest . -V -C Debug 146 | # Unix like环境(包括mingw)在构建目录运行下面命令即可 147 | ctest . -V 148 | ``` 149 | 150 | 单元测试会生成在[构建目录]/test下,sample会生成在[构建目录]/sample下,工具程序(比如压力测试程序)会生成在[构建目录]/tools下。并且不会被install 151 | 152 | cmake --build . --target install(或者make构建系统的make install) 仅会安装include目录和编译好的libs 153 | 154 | **注意:** Windows下MSVC直接安装的libuv会链接dll库,但是构建脚本不会把dll拷贝到执行目录,所以直接运行可能会出错。这时候把libuv.dll手动拷贝到执行目录即可 155 | 156 | 附加说明 157 | ------ 158 | 159 | ### 目录结构说明 160 | 161 | + third_party: 外部组件(不一定是依赖项) 162 | + docs: 文档目录 163 | + include: 导出lib的包含文件(注意不导出的内部接口后文件会直接在src目录里) 164 | + project: 工程工具和配置文件集 165 | + protocol: 协议描述文件目录 166 | + sample: 使用示例目录,每一个cpp文件都是一个完全独立的例子 167 | + src: 源文件和内部接口申明目录 168 | + test: 测试框架及测试用例目录 169 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | ### 编译选项 2 | 除了cmake标准编译选项外,libatbus还提供一些额外选项 3 | 4 | + ATBUS_MACRO_BUSID_TYPE: busid的类型(默认: uint64_t),建议不要设置成大于64位,否则需要修改protocol目录内的busid类型,并且重新生成协议文件 5 | + GTEST_ROOT: 使用GTest单元测试框架 6 | + BOOST_ROOT: 设置Boost库根目录 7 | + PROJECT_TEST_ENABLE_BOOST_UNIT_TEST: 使用Boost.Test单元测试框架(如果GTEST_ROOT和此项都不设置,则使用内置单元测试框架) 8 | 9 | 10 | ## 开发文档 11 | ### 目录结构说明 12 | 13 | + third_party: 外部组件(不一定是依赖项) 14 | + docs: 文档目录 15 | + include: 导出lib的包含文件(注意不导出的内部接口后文件会直接在src目录里) 16 | + project: 工程工具和配置文件集 17 | + protocol: 协议描述文件目录 18 | + sample: 使用示例目录,每一个cpp文件都是一个完全独立的例子 19 | + src: 源文件和内部接口申明目录 20 | + test: 测试框架及测试用例目录 21 | 22 | ### 关于 #pragma once 23 | 由于目标平台和环境的编译器均已支持 #pragma once 功能,故而所有源代码直接使用这个关键字,以提升编译速度。 24 | 25 | 详见:[pragma once](http://zh.wikipedia.org/wiki/Pragma_once) 26 | 27 | 28 | ### 内存通道设计 29 | 单多写状态 30 | ``` 31 | ▼ ▼ 32 | -------------------WWWW####WWWW###---------------- 33 | △ 34 | ``` 35 | |长度| 节点头结构 | 说明 | 36 | |---|------------------------------|------------------| 37 | |1B | 标记 flag |是否写完、是否是头节点| 38 | |1B | 写权限(原子操作) | | 39 | |4B | 首读时间(毫秒) |最大容忍误差是49天| 40 | 41 | 42 | **内存通道结构(内存和共享内存)** 43 | 44 | 所有消息对齐到size_t的大小 45 | |4K通道头|数据节点头*数据节点个数|数据区| 46 | 47 | ```cpp 48 | // 通道头 49 | struct mem_channel { 50 | // 数据节点 51 | size_t node_size; /** 每个节点的size **/ 52 | size_t node_size_bin_power; // (用于优化算法) node_size = 1 << node_size_bin_power 53 | size_t node_count; /** 数据节点个数 **/ 54 | 55 | // [atomic_read_cur, atomic_write_cur) 内的数据块都是已使用的数据块 56 | // atomic_write_cur指向的数据块一定是空块,故而必然有一个node的空洞 57 | // c11的stdatomic.h在很多编译器不支持并且还有些潜规则(gcc 不能使用-fno-builtin 和 -march=xxx),故而使用c++版本 58 | volatile std::atomic atomic_read_cur; // std::atomic也是POD类型 59 | volatile std::atomic atomic_write_cur; // std::atomic也是POD类型 60 | 61 | // 第一次读到正在写入数据的时间 62 | uint32_t first_failed_writing_time; /** 第一次读到正在写节点的时间,用于跳过错误写 **/ 63 | 64 | volatile std::atomic atomic_operation_seq; // 操作序列号(用于保证只有一个接收者) 65 | 66 | // 配置 67 | mem_conf conf; 68 | size_t area_channel_offset; /** 地址偏移: channel **/ 69 | size_t area_head_offset; /** 地址偏移: 数据节点头 **/ 70 | size_t area_data_offset; /** 地址偏移: 数据区 **/ 71 | size_t area_end_offset; /** 地址偏移: 使用的缓冲区尾部 **/ 72 | 73 | // 统计信息 74 | size_t block_bad_count; // 读取到坏块次数 75 | size_t block_timeout_count; // 读取到写入超时块次数 76 | size_t node_bad_count; // 读取到坏node次数 77 | }; 78 | 79 | // 配置数据结构 80 | struct mem_conf { 81 | size_t protect_node_count; /** 保护节点个数:用于降低冲突概率 **/ 82 | size_t protect_memory_size; /** 保护内存大小:用于降低冲突概率 **/ 83 | uint64_t conf_send_timeout_ms; /** 发送超时阀值:用于降低冲突概率 **/ 84 | 85 | // TODO 接收端校验号(用于保证只有一个接收者) 86 | volatile std::atomic atomic_receiver_identify; 87 | }; 88 | ``` 89 | 90 | **写数据步骤:** 91 | 92 | 1. 获取写游标,比较读游标,判断是否有空间 93 | 2. 分配操作序号 94 | 3. 顺序设置操作序号,交换0序号块,失败则返回空间不足 95 | 4. 逆序写数据,设置写完状态 96 | 97 | 98 | **读数据步骤:** 99 | 100 | 1. 获取读游标,比较写游标,判断是否有数据 101 | 2. 分配操作序号 102 | 2. 获取第一个节点是否准备完成状态 103 | 3. 如果不是完成状态尝试设置首读时间,如果首读超出阀值则认为写错误。此时reset脏节点(非头且不到写游标节点)后移动读游标 104 | 105 | 106 | **关于冲突:** 107 | 108 | 1. **读-读冲突:**只考虑单点读,没有这个问题。 109 | 2. **读-写冲突:**head有写完毕标记位,当写数据块准备完毕时才开始读。 110 | 3. **写-写冲突:**写游标是原子操作,每个节点写缓冲区独立。如果两个节点同时写一个块,则只有一个能写成功。如果写序列中任意块写失败,则整体返回空间不足,写失败。(防止读失败后释放的内存被重新写导致写冲突) 111 | 4. **写进程崩溃:**会产生赃数据块,即写完标记永远是未写完。这时候可以利用上上面提到的第一次读取时间。如果是0,则取当前时间赋值,否则如果超出容忍值,就视为赃数据块。取时间可以使用clock函数(Linux下实测每次执行消耗约160ns),也可以用汇编直接提取CPU时钟。一般情况下系统应该在数百次读取无数据后休眠至少一个时间片的时间(Linux下一般最少有4ms),这时候写进程还没写完基本可以认为是出现赃数据。 112 | 5. **读进程崩溃:**移动读游标是最后的操作,下次启动时可以继续,不会丢失数据 113 | 114 | **写-读失败-写覆盖问题:** 115 | 116 | 有一个目前无法解决的是**写-读失败-写覆盖**的问题。这个问题比较难处理,而且发生情况很少。为了这个偶现的问题增加锁和复杂的错误处理逻辑我认为是很不值得的,所以这里采用一些措施来提早发现问题。 117 | 118 | + **第一个措施**是增加一个保护区,当剩于空间不足某个阀值时直接返回空间不足 119 | + **第二个措施**是增加一个简单的校验码,当校验不通过时返回错误 120 | 121 | 在设置合理的情况下这两个措施基本能保证数据不出错(如果设置合理,再出错的概率按某人的说法就是,硬件也会出错坏掉的啊) 122 | 123 | **共享内存通道压力测试** 124 | 1个读进程,5个写进程 125 | 读进程满负荷运行3小时,接收数据3390712433次,接收数据12933GB,出现9次数据坏块错误,无数据校验错误 126 | 出错率低于3.7亿分之一 127 | 128 | 129 | ### 网络通道设计 130 | 131 | 网络消息收发走socket协议,然而由于**socket是一对一**的,所以需要对消息接收做一个汇总操作。另外网络通道由于不是使用预分配的内存,所以还需要一个回收操作。 132 | 133 | 消息接收的汇总聚合需要IO复用的支持,为了简化网络层跨平台适配,我们直接使用libuv。 134 | 135 | 另外网络通道和内存通道还有几个不同的地方: 136 | 137 | 1. 网络通道并不是一个真实的通道,所以**逻辑上接收通道(通过init创建)不能发送数据**,**发送通道(通过attach创建)不能用于接收数据**。这种情况下,获取数据时需要带回socket标识,用以做安全性控制。 138 | 2. 由于接收通道和发送通道socket是分离的,意味着一个节点可能会有多个接收通道。 139 | 3. 由于每条连接的接收端不一样,所以每个接收socket需要有自己的缓冲区。 140 | 4. 需要处理被动断线和断线重连的问题。而断线重连时也需要区分连接是否能成功的不同逻辑。 141 | 5. 发送接口除了发送成功和发送失败以外还有一个**发送中的状态**。(由于MTU分片,有些数据一次发不完,需要一点一点地发) 142 | 143 | 根据以上特点,主要设计思路如下: 144 | 145 | 1. 每个**数据节点**拥有一个libuv的context,用于异步分发fd事件。 146 | 2. 每个**数据节点**需要有一个连接池,连接池内的连接需要保存一些连接数据,包含发送缓冲区、接收缓冲区、状态等等。 147 | 3. 连接的发缓冲区有两种形式,一种是固定缓冲区(固定大小,固定个数)。另一种是动态缓冲区,动态缓冲区会频繁malloc,所以最好要使用jemalloc之类的内存分配器,并且动态缓冲区是一个链表,要有最大上限。 148 | 4. 数据发送、接收需要统计数据。 149 | 5. 断开连接时需要能够通过析构逻辑释放所有缓冲区和待发送项,并且回调失败接口。 150 | 6. 网络出现问题(包含超时、断开等)需要进行重连逻辑,但是重连逻辑需要有重试次数限制。立即重试失败则会有定时重试机制。 151 | 7. 网络断开事件中要清理节点的连接信息。 152 | 8. 如果数据很小能直接发掉,就直接发送(直接进入系统socket缓冲区),不需要过缓冲区(当然当前缓冲区必须为空)。发送接口防止多线程要加锁(先全加自旋锁,后面可以考虑抽空移植BOOST中对线程支持的判定,有多线程支持时加自旋锁)。 153 | 154 | ```cpp 155 | // Sock通道状态 156 | struct sock_status_t { 157 | enum type { 158 | INIT = 0, 159 | CONNECTING, 160 | CONNECTED, 161 | }; 162 | }; 163 | 164 | // Sock通道头 165 | struct io_stream_channel { 166 | std::string host; // 主机地址 167 | uint16_t port; // 端口 168 | int fd; // socket设备描述符/HANDLE 169 | int status; // 状态 170 | 171 | // 数据区域 172 | buffer_manager write_buffers; // 写数据缓冲区(两种Buffer管理方式,一种动态,一种静态) 173 | buffer_manager read_buffers; // 读数据缓冲区(两种Buffer管理方式,一种动态,一种静态) 174 | 175 | // 回调函数 176 | connect_callback_t on_connect; 177 | disconnect_callback_t on_disconnect; 178 | recv_callback_t on_recv; 179 | 180 | // 统计信息 181 | size_t block_bad_count; // 读取到坏块次数 182 | size_t block_timeout_count; // 读取到写入超时块次数 183 | size_t node_bad_count; // 读取到坏node次数 184 | }; 185 | ``` 186 | 187 | ### 数据节点 188 | 189 | 数据节点从接收通道上从逻辑区分可以有**命令通道**、**数据通道**。控制命令优先走**命令通道**,数据收发走**数据通道**。并且每种逻辑通道都可以是上面提到的任意N种类型。不过**libatbus**对通道的收发类型不做明确限制,而是根据协议来判定。 190 | 191 | **libatbus**会把IO流通道,accept的节点作为命令通道发送节点。数据通道另外发起连接。而对于内存或共享内存节点。不区分数据通道或命令通道。 192 | 193 | 数据节点的发送通道可以多种多样,但是KEY都是节点的ID。Value里包含连接信息,并且能根据连接信息来判定怎么建立连接或者如何发送数据。 194 | 195 | 对单个数据节点的操作必须是单线程的。包含节点更新、获取、查找等。 196 | 197 | 另外libatbus不规定通信模式(不像zeromq一样必须指定一种通信模式)。所以基本没有回包一说。但是因为存在网络延迟发送和发送过程,所以会出现发送失败的问题。 198 | 199 | 然而,在最极端的条件下,即便TCP连接的底层接口返回发送成功,也不能保证对端能正确收到(因为是异步接口并且底层可能发送到一半连接断开并且重试失败),能保证的只是对方收到的情况下的顺序和内容。 200 | 为了尽可能的抛出网络问题,调用发送接口时。我们在尝试重连的时候直接向上层直接返回错误。其他情况下, EAGAIN和EWOULDBLOCK、EINTR则直接重试,其他错误直接返回错误。 201 | 202 | 连接协议使用类似zeromq的方式。具体实施规则如下: 203 | 204 | + TCP网络连接: ipv4://IP:端口, ipv6://IP:端口, dns://域名或IP:端口 205 | + Unix Socket连接: unix://文件名路径 (如果是绝对路径,比如/tmp/atbus.sock的完整路径是 unit:///tmp/atbus.sock) 206 | + 共享内存连接: shm://共享内存Key 207 | + 堆内存连接: mem://名称 208 | 209 | 内部协议类型: 210 | 1. 转发协议 211 | 2. 节点树同步协议 212 | 3. 注册协议 213 | 4. 建立连接协议 214 | 5. Ping协议 215 | -------------------------------------------------------------------------------- /docs/Schedule.md: -------------------------------------------------------------------------------- 1 | # Schedule List 2 | 3 | 1. endpoint短线重连后的重发机制 4 | 1.1 endpoint断开后短期内不移除(pending_endpoint_gc_list 也采用定时器,影响单元测试的析构判定,也需要做相应变更) 5 | 1.2 custom command和forward协议增加和endpoint绑定的sequence,用于对重发的消息回调去重(其他协议不需要去重) 6 | 1.3 根据hash code、hostname、pid允许重置和endpoint绑定的sequence 7 | 1.4 endpoint握手仅连接最快可访问的数据链接(ios连接需要排队挨个重试),需要防止正在连接导致的误判,需要处理正在连接过程中GC生效的问题 8 | 1.5 ios channel允许重绑定写出缓冲区管理器,和endpoint内共享。 9 | 1.6 buffer_manager增加atomic的private_guard用于CAS操作处理正在写出的独占connection。connection释放时要解除占用。endpoint定期检查独占有效性(防止死锁) 10 | 1.7 connection握手成功后需要开始尝试重发和endpoint内共享的缓冲区 11 | 1.8 ios channel在写出完成的会调用发现需要关闭connection或正在关闭connection不再清理buffer_manager 12 | 1.9 增加ios channel拆包接口,用于处理如果endpoint丢弃时有些包需要通知发送失败的回调+单元测试 13 | 1.10 兄弟节点endpoint在进入gc列表时定期自动重连(父子节点会由子节点自动重连)(node非CLOSING时) 14 | 1.11 已绑定endpoint的connection在收到注册协议时要检查endpoint信息是否和原来一致。不一致说明同地址换endpoint了,需要移除endpoint的无效地址缓存,并重置connection的binding_ 15 | 1.12 已绑定endpoint的connection在收到注册协议时要检查endpoint的数据节点是否和上报地址匹配,不一致说明同地址换endpoint了,移除endpoint的无效地址缓存,并移除无效的connection后需要重新发起endpoint的数据通道连接流程 16 | 1.13 endpoint的数据通道全部离线后不再下线,而改为进入GC检查列表后尝试重新发起endpoint的数据通道连接流程 17 | 1.14 endpoint的控制通道全部离线后不再下线,而改为进入GC检查列表后尝试重新发起endpoint的控制通道连接流程 18 | 1.15 ios channel切换到shm/mem channel后发送的data/cmd消息要重排序,并且要处理shm/mem channel拥塞后的自动重发 19 | 1.16 增加消息超时机制,用于处理重发和GC机制联动导致的消息事件重复触发,forward_response事件增加不确定是否成功的错误码 20 | -------------------------------------------------------------------------------- /docs/Usage.md: -------------------------------------------------------------------------------- 1 | 使用示例 2 | ====== 3 | 4 | + 配置里的 subnets 决定了子节点的BUS ID范围,规则类似路由器。 5 | > 比如 mask_bits=8,id_prefix=0x12345678, 则0x12345600-0x123456FF都是它的子节点,0x12345778则是它的兄弟节点 6 | 7 | + 父子节点之间会自动断线重连 8 | + 拥有相同父节点的兄弟节点之间会自动按需断线重连 9 | + 没有相同父节点的兄弟节点之间**不会自动断线重连**。建议使用心跳或其他机制重新执行***connect***api来维持在线信息 10 | 11 | 12 | 监听和连接的地址目前支持: 13 | 14 | 1. ipv4://IP地址:端口 15 | 2. ipv6://IP地址:端口 16 | 3. unix://Unix Socket地址(仅Unix like系统下有效) 17 | 4. dns://域名:端口 18 | 5. shm://共享内存Key(整数,仅本机通信有效,支持16进制或10进制表示,比如 shm://0x1234FF00 或 shm://305463040) 19 | 6. mem://内存地址(整数,仅本机通信有效,支持16进制或10进制表示,内存通道必须先分配好。比如 mem://0x1234FF00 或 mem://305463040) 20 | 21 | 最简单的完整代码流程如下: 22 | ```cpp 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | 31 | #include 32 | #include 33 | 34 | int main() { 35 | // 初始化默认配置 36 | atbus::node::conf_t conf; 37 | atbus::node::default_conf(&conf); 38 | 39 | // 子域的范围设为16(后16位都是子节点), id_prefix=0 等于使用endpoint自己的ID 40 | conf.subnets.push_back(atbus::endpoint_subnet_conf(0, 16)); 41 | 42 | // 初始化libuv事件分发器 43 | uv_loop_t ev_loop; 44 | uv_loop_init(&ev_loop); 45 | 46 | // 指定事件分发器 47 | conf.ev_loop = &ev_loop; 48 | 49 | { 50 | // 创建两个通信节点 51 | atbus::node::ptr_t node1 = atbus::node::create(); 52 | atbus::node::ptr_t node2 = atbus::node::create(); 53 | 54 | // 初始化 55 | node1->init(0x12345678, &conf); // BUS ID=0x12345678, 0x1234XXXX 都是子节点 56 | node2->init(0x12356789, &conf); // BUS ID=0x12356789, 0x1235XXXX 都是子节点 57 | // 所以这两个都是兄弟节点 58 | 59 | // 各自监听地址 60 | node1->listen("ipv4://127.0.0.1:16387"); 61 | node2->listen("ipv4://127.0.0.1:16388"); 62 | 63 | // 启动初始化 64 | node1->start(); 65 | node2->start(); 66 | 67 | // 启动连接 68 | node1->connect("ipv4://127.0.0.1:16388"); 69 | 70 | // 等待连接成功 71 | // 如果是拥有共同父节点的兄弟节点不能这么判定,因为在第一次发消息前是不会建立连接的 72 | for (int i = 0; i < 512; ++i) { 73 | if (node2->is_endpoint_available(node1->get_id()) && node1->is_endpoint_available(node2->get_id())) { 74 | break; 75 | } 76 | 77 | uv_run(conf.ev_loop, UV_RUN_ONCE); 78 | 79 | // 定期执行proc函数,用于处理内部定时器 80 | // 第一个参数是Unix时间戳(秒),第二个参数是微秒 81 | node1->proc(time(nullptr), 0); 82 | node2->proc(time(nullptr), 0); 83 | } 84 | 85 | // 设置接收到消息后的回调函数 86 | bool recved = false; 87 | node2->set_on_recv_handle([&recved](const atbus::node &n, const atbus::endpoint *ep, const atbus::connection *conn, 88 | const atbus::msg_t &m, const void *buffer, size_t len) { 89 | if (nullptr != ep && nullptr != conn) { 90 | std::cout << "atbus node 0x" << std::ios::hex << n.get_id() << " receive data from 0x" << std::ios::hex << ep->get_id() 91 | << "(connection: " << conn->get_address().address << "): "; 92 | } 93 | std::cout.write(reinterpret_cast(buffer), len); 94 | std::cout << std::endl; 95 | recved = true; 96 | return 0; 97 | }); 98 | 99 | 100 | // 发送数据 101 | std::string send_data = "hello world!"; 102 | node1->send_data(node2->get_id(), 0, send_data.data(), send_data.size()); 103 | 104 | // 等待发送完成 105 | while (!recved) { 106 | uv_run(conf.ev_loop, UV_RUN_ONCE); 107 | 108 | // 定期执行proc函数,用于处理内部定时器 109 | // 第一个参数是Unix时间戳(秒),第二个参数是微秒 110 | node1->proc(time(nullptr), 0); 111 | node2->proc(time(nullptr), 0); 112 | } 113 | 114 | // 析构时会自动关闭所持有的资源 115 | } 116 | 117 | // 关闭libuv事件分发器 118 | while (UV_EBUSY == uv_loop_close(&ev_loop)) { 119 | uv_run(&ev_loop, UV_RUN_ONCE); 120 | } 121 | return 0; 122 | } 123 | ``` 124 | 125 | 编译时请包含msgpack、libuv和libatbus的include目录,链接atbus、atframe_utils和libuv 126 | -------------------------------------------------------------------------------- /docs/experience/test_shm_create.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include /* For O_* constants */ 3 | #include 4 | #include /* For mode constants */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int main() { 12 | // GNU libc (>=2.19) validates the shared memory name. Specifically, the shared memory object MUST now be at the root 13 | // of the shmfs mount point. 14 | // @see 15 | // https://stackoverflow.com/questions/23145458/shm-open-fails-with-einval-when-creating-shared-memory-in-subdirectory-of-dev 16 | // @see https://sourceware.org/git/?p=glibc.git;a=commit;h=b20de2c3d9d751eb259c321426188eefc64fcbe9 17 | // @see https://sourceware.org/bugzilla/show_bug.cgi?id=16274 18 | // link with -lrt 19 | // int test_fd = shm_open("/dev/shm/libatbus-test-shm.bus", O_RDWR | O_CREAT, S_IRWXU | S_IRGRP | S_IWGRP | S_IROTH | 20 | // S_IWOTH); glibc接口的shm_unlink不允许子目录 21 | #if 22 | 23 | mkdir("/dev/shm/libatbus", S_IRWXU | S_IRWXG | S_IRWXO); 24 | mkdir("/dev/shm/libatbus/test", S_IRWXU | S_IRWXG | S_IRWXO); 25 | int test_fd = openat(AT_FDCWD, "/dev/shm/libatbus/test/shm.bus", O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC, 26 | S_IRWXU | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); 27 | if (test_fd < 0) { 28 | printf("shm_open failed, err: %d, %s\n", errno, strerror(errno)); 29 | return 1; 30 | } 31 | 32 | struct stat statbuf; 33 | if (0 != fstat(test_fd, &statbuf)) { 34 | printf("fstat failed, err: %d, %s\n", errno, strerror(errno)); 35 | close(test_fd); 36 | return 1; 37 | } 38 | 39 | puts("================================ read ================================"); 40 | printf("stat.dev %lld\n", static_cast(statbuf.st_dev)); /* ID of device containing file */ 41 | printf("stat.ino %lld\n", static_cast(statbuf.st_ino)); /* Inode number */ 42 | printf("stat.mode %lld\n", static_cast(statbuf.st_mode)); /* File type and mode */ 43 | printf("stat.nlink %lld\n", static_cast(statbuf.st_nlink)); /* Number of hard links */ 44 | printf("stat.uid %lld\n", static_cast(statbuf.st_uid)); /* User ID of owner */ 45 | printf("stat.gid %lld\n", static_cast(statbuf.st_gid)); /* Group ID of owner */ 46 | printf("stat.dev %lld\n", static_cast(statbuf.st_rdev)); /* Device ID (if special file) */ 47 | printf("stat.off %lld\n", static_cast(statbuf.st_size)); /* Total size, in bytes */ 48 | printf("stat.blksize %lld\n", static_cast(statbuf.st_blksize)); /* Block size for filesystem I/O */ 49 | printf("stat.blkcnt %lld\n", static_cast(statbuf.st_blocks)); /* Number of 512B blocks allocated */ 50 | 51 | if (statbuf.st_size <= 0) { 52 | if (0 != ftruncate(test_fd, 2 * 1024 * 1024)) { 53 | printf("ftruncate failed, err: %d, %s\n", errno, strerror(errno)); 54 | close(test_fd); 55 | return 1; 56 | } 57 | 58 | if (0 != fstat(test_fd, &statbuf)) { 59 | printf("fstat failed, err: %d, %s\n", errno, strerror(errno)); 60 | close(test_fd); 61 | return 1; 62 | } 63 | 64 | puts("================================ create ================================"); 65 | printf("stat.dev %lld\n", static_cast(statbuf.st_dev)); /* ID of device containing file */ 66 | printf("stat.ino %lld\n", static_cast(statbuf.st_ino)); /* Inode number */ 67 | printf("stat.mode %lld\n", static_cast(statbuf.st_mode)); /* File type and mode */ 68 | printf("stat.nlink %lld\n", static_cast(statbuf.st_nlink)); /* Number of hard links */ 69 | printf("stat.uid %lld\n", static_cast(statbuf.st_uid)); /* User ID of owner */ 70 | printf("stat.gid %lld\n", static_cast(statbuf.st_gid)); /* Group ID of owner */ 71 | printf("stat.dev %lld\n", static_cast(statbuf.st_rdev)); /* Device ID (if special file) */ 72 | printf("stat.off %lld\n", static_cast(statbuf.st_size)); /* Total size, in bytes */ 73 | printf("stat.blksize %lld\n", static_cast(statbuf.st_blksize)); /* Block size for filesystem I/O */ 74 | printf("stat.blkcnt %lld\n", static_cast(statbuf.st_blocks)); /* Number of 512B blocks allocated */ 75 | } 76 | 77 | int shmflag = MAP_SHARED; 78 | 79 | # ifdef __linux__ 80 | shmflag |= MAP_NORESERVE; 81 | # endif 82 | 83 | puts("================================ mmap ================================"); 84 | void* access_data = mmap(nullptr, statbuf.st_size, PROT_READ | PROT_WRITE, shmflag, test_fd, 0); 85 | if (MAP_FAILED == access_data) { 86 | printf("mmap failed, err: %d, %s\n", errno, strerror(errno)); 87 | close(test_fd); 88 | return 1; 89 | } 90 | 91 | for (unsigned int i = 0; i < statbuf.st_size; ++i) { 92 | (*((unsigned char*)access_data + i)) = (unsigned char)(i & 0xFF); 93 | } 94 | 95 | if (0 != munmap(access_data, statbuf.st_size)) { 96 | printf("munmap failed, err: %d, %s\n", errno, strerror(errno)); 97 | close(test_fd); 98 | return 1; 99 | } 100 | 101 | close(test_fd); 102 | return 0; 103 | } 104 | -------------------------------------------------------------------------------- /docs/experience/test_shm_delete.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include /* For O_* constants */ 3 | #include 4 | #include /* For mode constants */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | int main() { 11 | // glibc接口的shm_unlink不允许子目录 12 | // int res = shm_unlink("/libatbus-test-shm.bus"); 13 | int res = unlink("/dev/shm/libatbus/test/shm.bus"); 14 | if (res < 0) { 15 | printf("shm_unlink failed, err: %d, %s", errno, strerror(errno)); 16 | return 1; 17 | } 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /include/atbus_connection.h: -------------------------------------------------------------------------------- 1 | // Copyright 2022 atframework 2 | // Created by owent on on 2015-11-20 3 | 4 | #pragma once 5 | 6 | #ifdef _MSC_VER 7 | # include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "std/explicit_declare.h" 23 | 24 | #include "detail/libatbus_channel_export.h" 25 | #include "detail/libatbus_config.h" 26 | #include "detail/libatbus_error.h" 27 | 28 | #include "libatbus_protocol.h" // NOLINT: build/include_subdir 29 | 30 | namespace atbus { 31 | namespace protocol { 32 | class msg; 33 | } 34 | 35 | class node; 36 | class endpoint; 37 | 38 | template 39 | struct timer_desc_ls { 40 | using pair_type = std::pair; 41 | using type = std::list; 42 | }; 43 | 44 | class connection final : public atfw::util::design_pattern::noncopyable { 45 | public: 46 | using ptr_t = std::shared_ptr; 47 | 48 | /** 并没有非常复杂的状态切换,所以没有引入状态机 **/ 49 | struct state_t { 50 | enum type { 51 | DISCONNECTED = 0, /** 未连接 **/ 52 | CONNECTING, /** 正在连接 **/ 53 | HANDSHAKING, /** 正在握手 **/ 54 | CONNECTED, /** 已连接 **/ 55 | DISCONNECTING, /** 正在断开连接 **/ 56 | }; 57 | }; 58 | 59 | struct flag_t { 60 | enum type { 61 | REG_PROC = 0, /** 注册了proc记录到node,清理的时候需要移除 **/ 62 | REG_FD, /** 关联了fd到node或endpoint,清理的时候需要移除 **/ 63 | ACCESS_SHARE_ADDR, /** 共享内部地址(内存通道的地址共享) **/ 64 | ACCESS_SHARE_HOST, /** 共享物理机(共享内存通道的物理机共享) **/ 65 | RESETTING, /** 正在执行重置(防止递归死循环) **/ 66 | DESTRUCTING, /** 正在执行析构(屏蔽某些接口) **/ 67 | LISTEN_FD, /** 是否是用于listen的连接 **/ 68 | TEMPORARY, /** 是否是临时连接 **/ 69 | PEER_CLOSED, /** 对端已关闭 **/ 70 | MAX 71 | }; 72 | }; 73 | 74 | struct stat_t { 75 | size_t push_start_times; 76 | size_t push_start_size; 77 | size_t push_success_times; 78 | size_t push_success_size; 79 | size_t push_failed_times; 80 | size_t push_failed_size; 81 | 82 | size_t pull_times; 83 | size_t pull_size; 84 | 85 | size_t fault_count; 86 | }; 87 | 88 | UTIL_DESIGN_PATTERN_NOCOPYABLE(connection) 89 | UTIL_DESIGN_PATTERN_NOMOVABLE(connection) 90 | 91 | private: 92 | connection(); 93 | 94 | public: 95 | static ATBUS_MACRO_API ptr_t create(node *owner); 96 | 97 | ATBUS_MACRO_API ~connection(); 98 | 99 | ATBUS_MACRO_API void reset(); 100 | 101 | /** 102 | * @brief 执行一帧 103 | * @param sec 当前时间-秒 104 | * @param usec 当前时间-微秒 105 | * @return 本帧处理的消息数 106 | */ 107 | ATBUS_MACRO_API int proc(node &n, time_t sec, time_t usec); 108 | 109 | /** 110 | * @brief 监听数据接收地址 111 | * @param addr 监听地址 112 | * @param is_caddr 是否是控制节点 113 | * @return 0或错误码 114 | */ 115 | ATBUS_MACRO_API int listen(const char *addr); 116 | 117 | /** 118 | * @brief 连接到目标地址 119 | * @param addr 连接目标地址 120 | * @return 0或错误码 121 | */ 122 | ATBUS_MACRO_API int connect(const char *addr); 123 | 124 | /** 125 | * @brief 断开连接 126 | * @note 此接口不会主动把自己从endpoint或者node中移除。如果要断开连接且移除connection,请使用 reset() 接口 127 | * @return 0或错误码 128 | */ 129 | ATBUS_MACRO_API int disconnect(); 130 | 131 | /** 132 | * @brief 发送数据 133 | * @param buffer 数据块地址 134 | * @param s 数据块长度 135 | * @return 0或错误码 136 | * @note 接收端收到的数据很可能不是地址对齐的,所以这里不建议发送内存数据 137 | * 如果非要发送内存数据的话,一定要memcpy,不能直接类型转换,除非手动设置了地址对齐规则 138 | */ 139 | ATBUS_MACRO_API int push(const void *buffer, size_t s); 140 | 141 | /** 增加错误计数 **/ 142 | ATBUS_MACRO_API size_t add_stat_fault(); 143 | 144 | /** 清空错误计数 **/ 145 | ATBUS_MACRO_API void clear_stat_fault(); 146 | 147 | /** 148 | * @brief 获取连接的地址 149 | */ 150 | ATBUS_MACRO_API const channel::channel_address_t &get_address() const; 151 | 152 | /** 153 | * @brief 是否已连接 154 | */ 155 | ATBUS_MACRO_API bool is_connected() const; 156 | 157 | /** 158 | * @brief 获取关联的端点 159 | */ 160 | ATBUS_MACRO_API endpoint *get_binding(); 161 | 162 | /** 163 | * @brief 获取关联的端点 164 | */ 165 | ATBUS_MACRO_API const endpoint *get_binding() const; 166 | 167 | ATBUS_MACRO_API state_t::type get_status() const; 168 | ATBUS_MACRO_API bool check_flag(flag_t::type f) const; 169 | 170 | ATBUS_MACRO_API void set_temporary(); 171 | 172 | /** 173 | * @brief 获取自身的智能指针 174 | * @note 在析构阶段这个接口无效 175 | */ 176 | ATBUS_MACRO_API ptr_t watch() const; 177 | 178 | /** 是否正在连接、或者握手或者已连接 **/ 179 | ATBUS_MACRO_API bool is_running() const; 180 | 181 | ATBUS_MACRO_API const stat_t &get_statistic() const; 182 | 183 | ATBUS_MACRO_API void remove_owner_checker(const timer_desc_ls::type::iterator &v); 184 | 185 | private: 186 | ATBUS_MACRO_API void set_status(state_t::type v); 187 | #if !defined(_WIN32) 188 | ATBUS_MACRO_API void unlock_address() noexcept; 189 | #endif 190 | 191 | public: 192 | static ATBUS_MACRO_API void iostream_on_listen_cb(channel::io_stream_channel *channel, 193 | channel::io_stream_connection *connection, int status, void *buffer, 194 | size_t s); 195 | static ATBUS_MACRO_API void iostream_on_connected_cb(channel::io_stream_channel *channel, 196 | channel::io_stream_connection *connection, int status, 197 | void *buffer, size_t s); 198 | 199 | static ATBUS_MACRO_API void iostream_on_recv_cb(channel::io_stream_channel *channel, 200 | channel::io_stream_connection *connection, int status, void *buffer, 201 | size_t s); 202 | static ATBUS_MACRO_API void iostream_on_accepted(channel::io_stream_channel *channel, 203 | channel::io_stream_connection *connection, int status, void *buffer, 204 | size_t s); 205 | static ATBUS_MACRO_API void iostream_on_connected(channel::io_stream_channel *channel, 206 | channel::io_stream_connection *connection, int status, void *buffer, 207 | size_t s); 208 | static ATBUS_MACRO_API void iostream_on_disconnected(channel::io_stream_channel *channel, 209 | channel::io_stream_connection *connection, int status, 210 | void *buffer, size_t s); 211 | static ATBUS_MACRO_API void iostream_on_written(channel::io_stream_channel *channel, 212 | channel::io_stream_connection *connection, int status, void *buffer, 213 | size_t s); 214 | 215 | #ifdef ATBUS_CHANNEL_SHM 216 | static ATBUS_MACRO_API int shm_proc_fn(node &n, connection &conn, time_t sec, time_t usec); 217 | 218 | static ATBUS_MACRO_API int shm_free_fn(node &n, connection &conn); 219 | 220 | static ATBUS_MACRO_API int shm_push_fn(connection &conn, const void *buffer, size_t s); 221 | #endif 222 | 223 | static ATBUS_MACRO_API int mem_proc_fn(node &n, connection &conn, time_t sec, time_t usec); 224 | 225 | static ATBUS_MACRO_API int mem_free_fn(node &n, connection &conn); 226 | 227 | static ATBUS_MACRO_API int mem_push_fn(connection &conn, const void *buffer, size_t s); 228 | 229 | static ATBUS_MACRO_API int ios_free_fn(node &n, connection &conn); 230 | 231 | static ATBUS_MACRO_API int ios_push_fn(connection &conn, const void *buffer, size_t s); 232 | 233 | static ATBUS_MACRO_API bool unpack(connection &conn, ::atbus::protocol::msg *&m, 234 | ::ATBUS_MACRO_PROTOBUF_NAMESPACE_ID::Arena &arena, std::vector &in); 235 | 236 | private: 237 | state_t::type state_; 238 | channel::channel_address_t address_; 239 | #if !defined(_WIN32) 240 | int address_lock_; 241 | std::string address_lock_path_; 242 | #endif 243 | std::bitset flags_; 244 | 245 | // 这里不用智能指针是为了该值在上层对象(node或者endpoint)析构时仍然可用 246 | node *owner_; 247 | timer_desc_ls::type::iterator owner_checker_; 248 | endpoint *binding_; 249 | std::weak_ptr watcher_; 250 | 251 | struct conn_data_mem { 252 | channel::mem_channel *channel; 253 | void *buffer; 254 | size_t len; 255 | }; 256 | 257 | #ifdef ATBUS_CHANNEL_SHM 258 | struct conn_data_shm { 259 | channel::shm_channel *channel; 260 | size_t len; 261 | }; 262 | #endif 263 | 264 | struct conn_data_ios { 265 | channel::io_stream_channel *channel; 266 | channel::io_stream_connection *conn; 267 | }; 268 | 269 | struct connection_data_t { 270 | union shared_t { 271 | conn_data_mem mem; 272 | #ifdef ATBUS_CHANNEL_SHM 273 | conn_data_shm shm; 274 | #endif 275 | conn_data_ios ios_fd; 276 | }; 277 | using proc_fn_t = int (*)(node &n, connection &conn, time_t sec, time_t usec); 278 | using free_fn_t = int (*)(node &n, connection &conn); 279 | using push_fn_t = int (*)(connection &conn, const void *buffer, size_t s); 280 | 281 | shared_t shared; 282 | proc_fn_t proc_fn; 283 | free_fn_t free_fn; 284 | push_fn_t push_fn; 285 | }; 286 | connection_data_t conn_data_; 287 | stat_t stat_; 288 | 289 | friend class endpoint; 290 | }; 291 | } // namespace atbus 292 | -------------------------------------------------------------------------------- /include/atbus_msg_handler.h: -------------------------------------------------------------------------------- 1 | /** 2 | * atbus_msg_handler.h 3 | * 4 | * Created on: 2015年12月14日 5 | * Author: owent 6 | */ 7 | 8 | #pragma once 9 | 10 | #ifndef LIBATBUS_MSG_HANDLER_H 11 | # define LIBATBUS_MSG_HANDLER_H 12 | 13 | # pragma once 14 | 15 | # include 16 | # include 17 | # include 18 | 19 | # include "detail/libatbus_config.h" 20 | 21 | namespace atbus { 22 | namespace protocol { 23 | class msg; 24 | } 25 | 26 | class node; 27 | class endpoint; 28 | class connection; 29 | 30 | struct msg_handler { 31 | using handler_fn_t = int (*)(node &n, connection *conn, ::atbus::protocol::msg ATBUS_MACRO_RVALUE_REFERENCES, 32 | int status, int errcode); 33 | 34 | static ATBUS_MACRO_API int dispatch_msg(node &n, connection *conn, 35 | ::atbus::protocol::msg ATBUS_MACRO_RVALUE_REFERENCES, int status, 36 | int errcode); 37 | 38 | static ATBUS_MACRO_API const char *get_body_name(int body_case); 39 | 40 | static ATBUS_MACRO_API int send_ping(node &n, connection &conn, uint64_t seq); 41 | 42 | static ATBUS_MACRO_API int send_reg(int32_t msg_id, node &n, connection &conn, int32_t ret_code, uint64_t seq); 43 | 44 | static ATBUS_MACRO_API int send_transfer_rsp(node &n, ::atbus::protocol::msg ATBUS_MACRO_RVALUE_REFERENCES, 45 | int32_t ret_code); 46 | 47 | static ATBUS_MACRO_API int send_custom_cmd_rsp(node &n, connection *conn, const std::list &rsp_data, 48 | int32_t type, int32_t ret_code, uint64_t sequence, 49 | uint64_t from_bus_id); 50 | 51 | static ATBUS_MACRO_API int send_node_connect_sync(node &n, uint64_t direct_from_bus_id, endpoint &dst_ep); 52 | 53 | static ATBUS_MACRO_API int send_msg(node &n, connection &conn, const ::atbus::protocol::msg &msg); 54 | 55 | // ========================= 接收handle ========================= 56 | static ATBUS_MACRO_API int on_recv_data_transfer_req(node &n, connection *conn, 57 | ::atbus::protocol::msg ATBUS_MACRO_RVALUE_REFERENCES, int status, 58 | int errcode); 59 | static ATBUS_MACRO_API int on_recv_data_transfer_rsp(node &n, connection *conn, 60 | ::atbus::protocol::msg ATBUS_MACRO_RVALUE_REFERENCES, int status, 61 | int errcode); 62 | 63 | static ATBUS_MACRO_API int on_recv_custom_cmd_req(node &n, connection *conn, 64 | ::atbus::protocol::msg ATBUS_MACRO_RVALUE_REFERENCES, int status, 65 | int errcode); 66 | static ATBUS_MACRO_API int on_recv_custom_cmd_rsp(node &n, connection *conn, 67 | ::atbus::protocol::msg ATBUS_MACRO_RVALUE_REFERENCES, int status, 68 | int errcode); 69 | 70 | static ATBUS_MACRO_API int on_recv_node_sync_req(node &n, connection *conn, 71 | ::atbus::protocol::msg ATBUS_MACRO_RVALUE_REFERENCES, int status, 72 | int errcode); 73 | static ATBUS_MACRO_API int on_recv_node_sync_rsp(node &n, connection *conn, 74 | ::atbus::protocol::msg ATBUS_MACRO_RVALUE_REFERENCES, int status, 75 | int errcode); 76 | static ATBUS_MACRO_API int on_recv_node_reg_req(node &n, connection *conn, 77 | ::atbus::protocol::msg ATBUS_MACRO_RVALUE_REFERENCES, int status, 78 | int errcode); 79 | static ATBUS_MACRO_API int on_recv_node_reg_rsp(node &n, connection *conn, 80 | ::atbus::protocol::msg ATBUS_MACRO_RVALUE_REFERENCES, int status, 81 | int errcode); 82 | static ATBUS_MACRO_API int on_recv_node_conn_syn(node &n, connection *conn, 83 | ::atbus::protocol::msg ATBUS_MACRO_RVALUE_REFERENCES, int status, 84 | int errcode); 85 | static ATBUS_MACRO_API int on_recv_node_ping(node &n, connection *conn, 86 | ::atbus::protocol::msg ATBUS_MACRO_RVALUE_REFERENCES, int status, 87 | int errcode); 88 | static ATBUS_MACRO_API int on_recv_node_pong(node &n, connection *conn, 89 | ::atbus::protocol::msg ATBUS_MACRO_RVALUE_REFERENCES, int status, 90 | int errcode); 91 | }; 92 | } // namespace atbus 93 | 94 | #endif /* LIBATBUS_MSG_HANDLER_H_ */ 95 | -------------------------------------------------------------------------------- /include/detail/buffer.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by owent on 2015/8/11. 3 | // 4 | 5 | #ifndef LIBATBUS_BUFFER_H 6 | #define LIBATBUS_BUFFER_H 7 | 8 | #pragma once 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "detail/libatbus_config.h" 16 | 17 | #include "design_pattern/nomovable.h" 18 | #include "design_pattern/noncopyable.h" 19 | 20 | namespace atbus { 21 | namespace detail { 22 | namespace fn { 23 | ATBUS_MACRO_API void *buffer_next(void *pointer, size_t step); 24 | ATBUS_MACRO_API const void *buffer_next(const void *pointer, size_t step); 25 | 26 | ATBUS_MACRO_API void *buffer_prev(void *pointer, size_t step); 27 | ATBUS_MACRO_API const void *buffer_prev(const void *pointer, size_t step); 28 | 29 | ATBUS_MACRO_API size_t buffer_offset(const void *l, const void *r); 30 | 31 | /** 32 | * @brief try to read a dynamic int from buffer 33 | * @param out output integer 34 | * @param pointer buffer address 35 | * @param s buffer size 36 | * @note encoding: like protobuf varint, first bit means more or last byte, big endian, padding right 37 | * @note can not used with signed integer 38 | * @return how much bytes the integer cost, 0 if failed 39 | **/ 40 | ATBUS_MACRO_API size_t read_vint(uint64_t &out, const void *pointer, size_t s); 41 | 42 | /** 43 | * @brief try to write a dynamic int to buffer 44 | * @param in input integer 45 | * @param pointer buffer address 46 | * @param s buffer size 47 | * @note encoding: like protobuf varint, first bit means more or last byte, big endian, padding right 48 | * @note can not used with signed integer 49 | * @return how much bytes the integer cost, 0 if failed 50 | **/ 51 | ATBUS_MACRO_API size_t write_vint(uint64_t in, void *pointer, size_t s); 52 | } // namespace fn 53 | 54 | class buffer_manager; 55 | 56 | /** 57 | * @brief buffer block, not thread safe 58 | */ 59 | class buffer_block { 60 | public: 61 | ATBUS_MACRO_API void *data(); 62 | ATBUS_MACRO_API const void *data() const; 63 | ATBUS_MACRO_API void *raw_data(); 64 | ATBUS_MACRO_API const void *raw_data() const; 65 | 66 | ATBUS_MACRO_API size_t size() const; 67 | 68 | ATBUS_MACRO_API size_t raw_size() const; 69 | 70 | ATBUS_MACRO_API void *pop(size_t s); 71 | 72 | ATBUS_MACRO_API size_t instance_size() const; 73 | 74 | public: 75 | /** alloc and init buffer_block **/ 76 | static ATBUS_MACRO_API buffer_block *malloc(size_t s); 77 | 78 | /** destroy and free buffer_block **/ 79 | static ATBUS_MACRO_API void free(buffer_block *p); 80 | 81 | /** 82 | * @brief init buffer_block as specify address 83 | * @param pointer data address 84 | * @param s data max size 85 | * @param bs buffer size 86 | * @return unused data address 87 | **/ 88 | static ATBUS_MACRO_API void *create(void *pointer, size_t s, size_t bs); 89 | 90 | /** init buffer_block as specify address **/ 91 | static ATBUS_MACRO_API void *destroy(buffer_block *p); 92 | 93 | static ATBUS_MACRO_API size_t padding_size(size_t s); 94 | static ATBUS_MACRO_API size_t head_size(size_t s); 95 | static ATBUS_MACRO_API size_t full_size(size_t s); 96 | 97 | private: 98 | friend class buffer_manager; 99 | size_t size_; 100 | size_t used_; 101 | void *pointer_; 102 | }; 103 | 104 | /** 105 | * @brief buffer block manager, not thread safe 106 | */ 107 | class buffer_manager { 108 | public: 109 | struct limit_t { 110 | size_t cost_number_; 111 | size_t cost_size_; 112 | 113 | size_t limit_number_; 114 | size_t limit_size_; 115 | }; 116 | 117 | UTIL_DESIGN_PATTERN_NOCOPYABLE(buffer_manager) 118 | UTIL_DESIGN_PATTERN_NOMOVABLE(buffer_manager) 119 | 120 | public: 121 | ATBUS_MACRO_API buffer_manager(); 122 | ATBUS_MACRO_API ~buffer_manager(); 123 | 124 | ATBUS_MACRO_API const limit_t &limit() const; 125 | 126 | /** 127 | * @brief set limit when in dynamic mode 128 | * @param max_size size limit of dynamic, set 0 if unlimited 129 | * @param max_number number limit of dynamic, set 0 if unlimited 130 | * @return true on success 131 | */ 132 | ATBUS_MACRO_API bool set_limit(size_t max_size, size_t max_number); 133 | 134 | ATBUS_MACRO_API buffer_block *front(); 135 | 136 | ATBUS_MACRO_API int front(void *&pointer, size_t &nread, size_t &nwrite); 137 | 138 | ATBUS_MACRO_API buffer_block *back(); 139 | 140 | ATBUS_MACRO_API int back(void *&pointer, size_t &nread, size_t &nwrite); 141 | 142 | ATBUS_MACRO_API int push_back(void *&pointer, size_t s); 143 | 144 | ATBUS_MACRO_API int push_front(void *&pointer, size_t s); 145 | 146 | ATBUS_MACRO_API int pop_back(size_t s, bool free_unwritable = true); 147 | 148 | ATBUS_MACRO_API int pop_front(size_t s, bool free_unwritable = true); 149 | 150 | /** 151 | * @brief append buffer and merge to the tail of the last buffer block 152 | * @note if manager is empty now, just like push_back 153 | * @param pointer output the writable buffer address 154 | * @param s buffer size 155 | * @return 0 or error code 156 | */ 157 | ATBUS_MACRO_API int merge_back(void *&pointer, size_t s); 158 | 159 | /** 160 | * @brief append buffer and merge to the tail of the first buffer block 161 | * @note if manager is empty now, just like push_front 162 | * @param pointer output the writable buffer address 163 | * @param s buffer size 164 | * @return 0 or error code 165 | */ 166 | ATBUS_MACRO_API int merge_front(void *&pointer, size_t s); 167 | 168 | ATBUS_MACRO_API bool empty() const; 169 | 170 | ATBUS_MACRO_API void reset(); 171 | 172 | /** 173 | * @brief set dynamic mode(use malloc when push buffer) or static mode(malloc a huge buffer at once) 174 | * @param max_size circle buffer size when static mode, 0 when dynamic mode 175 | * @param max_number buffer number when static mode 176 | * @note this api will clear buffer data already exists 177 | */ 178 | ATBUS_MACRO_API void set_mode(size_t max_size, size_t max_number); 179 | 180 | ATBUS_MACRO_API bool is_static_mode() const; 181 | ATBUS_MACRO_API bool is_dynamic_mode() const; 182 | 183 | private: 184 | buffer_block *static_front(); 185 | 186 | buffer_block *static_back(); 187 | 188 | int static_push_back(void *&pointer, size_t s); 189 | 190 | int static_push_front(void *&pointer, size_t s); 191 | 192 | int static_pop_back(size_t s, bool free_unwritable); 193 | 194 | int static_pop_front(size_t s, bool free_unwritable); 195 | 196 | int static_merge_back(void *&pointer, size_t s); 197 | 198 | int static_merge_front(void *&pointer, size_t s); 199 | 200 | bool static_empty() const; 201 | 202 | buffer_block *dynamic_front(); 203 | 204 | buffer_block *dynamic_back(); 205 | 206 | int dynamic_push_back(void *&pointer, size_t s); 207 | 208 | int dynamic_push_front(void *&pointer, size_t s); 209 | 210 | int dynamic_pop_back(size_t s, bool free_unwritable); 211 | 212 | int dynamic_pop_front(size_t s, bool free_unwritable); 213 | 214 | int dynamic_merge_back(void *&pointer, size_t s); 215 | 216 | int dynamic_merge_front(void *&pointer, size_t s); 217 | 218 | bool dynamic_empty() const; 219 | 220 | private: 221 | struct static_buffer_t { 222 | void *buffer_; 223 | size_t size_; 224 | 225 | size_t head_; 226 | size_t tail_; 227 | std::vector circle_index_; 228 | }; 229 | 230 | static_buffer_t static_buffer_; 231 | std::list dynamic_buffer_; 232 | 233 | limit_t limit_; 234 | }; 235 | } // namespace detail 236 | } // namespace atbus 237 | 238 | #endif // LIBATBUS_BUFFER_H 239 | -------------------------------------------------------------------------------- /include/detail/libatbus_adapter_libuv.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by owent on 2015/9/15. 3 | // 4 | 5 | #ifndef LIBATBUS_LIBATBUS_ADAPTER_LIBUV_H 6 | #define LIBATBUS_LIBATBUS_ADAPTER_LIBUV_H 7 | 8 | #pragma once 9 | 10 | #include "uv.h" 11 | 12 | namespace atbus { 13 | namespace adapter { 14 | using loop_t = uv_loop_t; 15 | using poll_t = uv_poll_t; 16 | using stream_t = uv_stream_t; 17 | using pipe_t = uv_pipe_t; 18 | using tty_t = uv_tty_t; 19 | using tcp_t = uv_tcp_t; 20 | using handle_t = uv_handle_t; 21 | using timer_t = uv_timer_t; 22 | using shutdown_t = uv_shutdown_t; 23 | 24 | using fd_t = uv_os_fd_t; 25 | 26 | enum run_mode_t { 27 | RUN_DEFAULT = UV_RUN_DEFAULT, 28 | RUN_ONCE = UV_RUN_ONCE, 29 | RUN_NOWAIT = UV_RUN_NOWAIT, 30 | }; 31 | } // namespace adapter 32 | } // namespace atbus 33 | 34 | #endif // LIBATBUS_LIBATBUS_ADAPTER_LIBUV_H 35 | -------------------------------------------------------------------------------- /include/detail/libatbus_channel_export.h: -------------------------------------------------------------------------------- 1 | /** 2 | * libatbus_channel_export.h 3 | * 4 | * Created on: 2014年8月13日 5 | * Author: owent 6 | */ 7 | 8 | #pragma once 9 | 10 | #ifndef LIBATBUS_CHANNEL_EXPORT_H 11 | # define LIBATBUS_CHANNEL_EXPORT_H 12 | 13 | # pragma once 14 | 15 | # include 16 | # include 17 | # include 18 | # include 19 | # include 20 | 21 | # include "detail/libatbus_config.h" 22 | 23 | # include "detail/libatbus_adapter_libuv.h" 24 | 25 | # include "detail/libatbus_channel_types.h" 26 | 27 | namespace atbus { 28 | namespace channel { 29 | // utility functions 30 | ATBUS_MACRO_API bool make_address(const char *in, channel_address_t &addr); 31 | ATBUS_MACRO_API void make_address(const char *scheme, const char *host, int port, channel_address_t &addr); 32 | 33 | /** 34 | * @brief If it's a duplex address, means both enpoint has a connection to receive and send data 35 | * @param in address , start with unix:/ipv4:/ipv6:/dns:/shm: and etc. 36 | * @return true if it's a duplex address 37 | */ 38 | ATBUS_MACRO_API bool is_duplex_address(const char *in); 39 | 40 | /** 41 | * @brief If it's a simplex address, means the other node has no connection and can only receive data 42 | * @param in address , start with unix:/ipv4:/ipv6:/dns:/shm: and etc. 43 | * @return true if it's a simplex address 44 | */ 45 | ATBUS_MACRO_API bool is_simplex_address(const char *in); 46 | 47 | /** 48 | * @brief If it's a address that can only be connected by nodes on the same machine 49 | * @param in address , start with unix:/ipv4:/ipv6:/dns:/shm: and etc. 50 | * @return true if it's a address that can only be connected by nodes on the same machine 51 | */ 52 | ATBUS_MACRO_API bool is_local_host_address(const char *in); 53 | 54 | /** 55 | * @brief If it's a address that can only be connected by nodes on the same process 56 | * @param in address , start with unix:/ipv4:/ipv6:/dns:/shm: and etc. 57 | * @return true it's a address that can only be connected by nodes on the same process 58 | */ 59 | ATBUS_MACRO_API bool is_local_process_address(const char *in); 60 | 61 | // memory channel 62 | ATBUS_MACRO_API int mem_configure_set_write_timeout(mem_channel *channel, uint64_t ms); 63 | ATBUS_MACRO_API uint64_t mem_configure_get_write_timeout(mem_channel *channel); 64 | ATBUS_MACRO_API int mem_configure_set_write_retry_times(mem_channel *channel, size_t times); 65 | ATBUS_MACRO_API size_t mem_configure_get_write_retry_times(mem_channel *channel); 66 | ATBUS_MACRO_API uint16_t mem_info_get_version(mem_channel *channel); 67 | ATBUS_MACRO_API uint16_t mem_info_get_align_size(mem_channel *channel); 68 | ATBUS_MACRO_API uint16_t mem_info_get_host_size(mem_channel *channel); 69 | 70 | ATBUS_MACRO_API int mem_attach(void *buf, size_t len, mem_channel **channel, const mem_conf *conf); 71 | ATBUS_MACRO_API int mem_init(void *buf, size_t len, mem_channel **channel, const mem_conf *conf); 72 | ATBUS_MACRO_API int mem_send(mem_channel *channel, const void *buf, size_t len); 73 | ATBUS_MACRO_API int mem_recv(mem_channel *channel, void *buf, size_t len, size_t *recv_size); 74 | ATBUS_MACRO_API std::pair mem_last_action(); 75 | ATBUS_MACRO_API void mem_show_channel(mem_channel *channel, std::ostream &out, bool need_node_status, 76 | size_t need_node_data); 77 | 78 | ATBUS_MACRO_API void mem_stats_get_error(mem_channel *channel, mem_stats_block_error &out); 79 | 80 | # ifdef ATBUS_CHANNEL_SHM 81 | // shared memory channel 82 | ATBUS_MACRO_API int shm_configure_set_write_timeout(shm_channel *channel, uint64_t ms); 83 | ATBUS_MACRO_API uint64_t shm_configure_get_write_timeout(shm_channel *channel); 84 | ATBUS_MACRO_API int shm_configure_set_write_retry_times(shm_channel *channel, size_t times); 85 | ATBUS_MACRO_API size_t shm_configure_get_write_retry_times(shm_channel *channel); 86 | ATBUS_MACRO_API uint16_t shm_info_get_version(shm_channel *channel); 87 | ATBUS_MACRO_API uint16_t shm_info_get_align_size(shm_channel *channel); 88 | ATBUS_MACRO_API uint16_t shm_info_get_host_size(shm_channel *channel); 89 | 90 | /** 91 | * @brief shm_attach/shm_init/shm_close with shm_path 92 | * @param shm_path shm_path can be a number(means shared memory key) or a path begin with '/' 93 | * @note shm_path can only contains one '/' and the length shoud not extend 255 according to POSIX 94 | * On Windows, we will add prefix of "Global\\" for shm_path, so the length of shm_path can 95 | * not be grater than 248 96 | * @see http://man7.org/linux/man-pages/man3/shm_open.3.html 97 | * @see https://linux.die.net/man/3/shm_open 98 | * @see https://man.openbsd.org/shm_open.3 99 | */ 100 | ATBUS_MACRO_API int shm_attach(const char *shm_path, size_t len, shm_channel **channel, const shm_conf *conf); 101 | ATBUS_MACRO_API int shm_init(const char *shm_path, size_t len, shm_channel **channel, const shm_conf *conf); 102 | ATBUS_MACRO_API int shm_close(const char *shm_path); 103 | ATBUS_MACRO_API int shm_send(shm_channel *channel, const void *buf, size_t len); 104 | ATBUS_MACRO_API int shm_recv(shm_channel *channel, void *buf, size_t len, size_t *recv_size); 105 | ATBUS_MACRO_API std::pair shm_last_action(); 106 | ATBUS_MACRO_API void shm_show_channel(shm_channel *channel, std::ostream &out, bool need_node_status, 107 | size_t need_node_data); 108 | 109 | ATBUS_MACRO_API void shm_stats_get_error(shm_channel *channel, shm_stats_block_error &out); 110 | # endif 111 | 112 | // stream channel(tcp,pipe(unix socket) and etc. udp is not a stream) 113 | ATBUS_MACRO_API void io_stream_init_configure(io_stream_conf *conf); 114 | 115 | ATBUS_MACRO_API int io_stream_init(io_stream_channel *channel, adapter::loop_t *ev_loop, const io_stream_conf *conf); 116 | 117 | // it will block and wait for all connections are disconnected success. 118 | ATBUS_MACRO_API int io_stream_close(io_stream_channel *channel); 119 | 120 | ATBUS_MACRO_API int io_stream_run(io_stream_channel *channel, adapter::run_mode_t mode = adapter::RUN_NOWAIT); 121 | 122 | ATBUS_MACRO_API int io_stream_listen(io_stream_channel *channel, const channel_address_t &addr, 123 | io_stream_callback_t callback, void *priv_data, size_t priv_size); 124 | 125 | ATBUS_MACRO_API int io_stream_connect(io_stream_channel *channel, const channel_address_t &addr, 126 | io_stream_callback_t callback, void *priv_data, size_t priv_size); 127 | 128 | ATBUS_MACRO_API int io_stream_disconnect(io_stream_channel *channel, io_stream_connection *connection, 129 | io_stream_callback_t callback); 130 | ATBUS_MACRO_API int io_stream_disconnect_fd(io_stream_channel *channel, adapter::fd_t fd, 131 | io_stream_callback_t callback); 132 | ATBUS_MACRO_API int io_stream_try_write(io_stream_connection *connection); 133 | ATBUS_MACRO_API int io_stream_send(io_stream_connection *connection, const void *buf, size_t len); 134 | ATBUS_MACRO_API size_t io_stream_get_max_unix_socket_length(); 135 | 136 | ATBUS_MACRO_API void io_stream_show_channel(io_stream_channel *channel, std::ostream &out); 137 | } // namespace channel 138 | } // namespace atbus 139 | 140 | #endif /* LIBATBUS_CHANNEL_EXPORT_H_ */ 141 | -------------------------------------------------------------------------------- /include/detail/libatbus_channel_types.h: -------------------------------------------------------------------------------- 1 | /** 2 | * libatbus_channel_types.h 3 | * 4 | * Created on: 2014年8月13日 5 | * Author: owent 6 | */ 7 | #ifndef LIBATBUS_CHANNEL_TYPES_H 8 | #define LIBATBUS_CHANNEL_TYPES_H 9 | 10 | #pragma once 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "lock/seq_alloc.h" 22 | 23 | #include "detail/libatbus_config.h" 24 | 25 | #include "buffer.h" 26 | #include "detail/libatbus_adapter_libuv.h" 27 | 28 | #if defined(__ANDROID__) 29 | #elif defined(__APPLE__) 30 | # if __dest_os == __mac_os_x 31 | # include 32 | # include 33 | 34 | # define ATBUS_CHANNEL_SHM 1 35 | # endif 36 | #elif defined(__unix__) 37 | # include 38 | # include 39 | 40 | # define ATBUS_CHANNEL_SHM 1 41 | #else 42 | # include 43 | 44 | # define ATBUS_CHANNEL_SHM 1 45 | #endif 46 | 47 | namespace atbus { 48 | namespace channel { 49 | // utility functions 50 | struct ATBUS_MACRO_API_HEAD_ONLY channel_address_t { 51 | std::string address; // 主机完整地址,比如:ipv4://127.0.0.1:8123 或 unix:///tmp/atbut.sock 52 | std::string scheme; // 协议名称,比如:ipv4 或 unix 53 | std::string host; // 主机地址,比如:127.0.0.1 或 /tmp/atbut.sock 54 | int port; // 端口。(仅网络连接有效) 55 | }; 56 | 57 | // memory channel 58 | struct mem_channel; 59 | struct mem_conf; 60 | 61 | struct ATBUS_MACRO_API_HEAD_ONLY mem_stats_block_error { 62 | // 统计信息 63 | size_t write_check_sequence_failed_count; // 写完后校验操作序号错误 64 | size_t write_retry_count; // 写操作内部重试次数 65 | 66 | size_t read_bad_node_count; // 读到的错误数据节点数量 67 | size_t read_bad_block_count; // 读到的错误数据块数量 68 | size_t read_write_timeout_count; // 读到的写超时保护数量 69 | size_t read_check_block_size_failed_count; // 读到的数据块长度检查错误数量 70 | size_t read_check_node_size_failed_count; // 读到的数据节点和长度检查错误数量 71 | size_t read_check_hash_failed_count; // 读到的数据hash值检查错误数量 72 | }; 73 | 74 | #ifdef ATBUS_CHANNEL_SHM 75 | // shared memory channel 76 | struct shm_channel; 77 | struct shm_conf; 78 | 79 | using shm_stats_block_error = mem_stats_block_error; 80 | #endif 81 | 82 | // stream channel(tcp,pipe(unix socket) and etc. udp is not a stream) 83 | struct io_stream_connection; 84 | struct io_stream_channel; 85 | using io_stream_callback_t = void (*)(io_stream_channel *channel, // 事件触发的channel 86 | io_stream_connection *connection, // 事件触发的连接 87 | int status, // libuv传入的转态码 88 | void *, // 额外参数(不同事件不同含义) 89 | size_t s // 额外参数长度 90 | ); 91 | 92 | struct ATBUS_MACRO_API_HEAD_ONLY io_stream_callback_evt_t { 93 | enum mem_fn_t { 94 | EN_FN_ACCEPTED = 0, 95 | EN_FN_CONNECTED, // 连接或listen成功 96 | EN_FN_DISCONNECTED, 97 | EN_FN_RECVED, 98 | EN_FN_WRITEN, 99 | MAX 100 | }; 101 | // 回调函数 102 | io_stream_callback_t callbacks[MAX]; 103 | }; 104 | 105 | // 以下不是POD类型,所以不得不暴露出来 106 | struct ATBUS_MACRO_API_HEAD_ONLY io_stream_connection { 107 | enum flag_t { 108 | EN_CF_LISTEN = 0, 109 | EN_CF_CONNECT, 110 | EN_CF_ACCEPT, 111 | EN_CF_WRITING, 112 | EN_CF_CLOSING, 113 | EN_CF_MAX, 114 | }; 115 | 116 | channel_address_t addr; 117 | std::shared_ptr handle; // 流设备 118 | adapter::fd_t fd; // 文件描述符 119 | 120 | enum status_t { EN_ST_CREATED = 0, EN_ST_CONNECTED, EN_ST_DISCONNECTING, EN_ST_DISCONNECTED }; 121 | status_t status; // 状态 122 | int flags; // flag 123 | io_stream_channel *channel; 124 | 125 | // 事件响应 126 | io_stream_callback_evt_t evt; 127 | io_stream_callback_t act_disc_cbk; // 主动关闭连接的回调(为了减少额外分配而采用的缓存策略) 128 | 129 | // 数据区域 130 | ::atbus::detail::buffer_manager read_buffers; // 读数据缓冲区(两种Buffer管理方式,一种动态,一种静态) 131 | /** 132 | * @brief 由于大多数数据包都比较小 133 | * 当数据包比较小时和动态直接放在动态int的数据包一起,这样可以减少内存拷贝次数 134 | */ 135 | struct read_head_t { 136 | char buffer[ATBUS_MACRO_DATA_SMALL_SIZE]; // varint数据暂存区和小数据包存储区 137 | size_t len; // varint数据暂存区和小数据包存储区已使用长度 138 | }; 139 | read_head_t read_head; 140 | ::atbus::detail::buffer_manager write_buffers; // 写数据缓冲区(两种Buffer管理方式,一种动态,一种静态) 141 | 142 | // 自定义数据区域 143 | void *data; 144 | }; 145 | 146 | struct ATBUS_MACRO_API_HEAD_ONLY io_stream_conf { 147 | time_t keepalive; 148 | 149 | bool is_noblock; 150 | bool is_nodelay; 151 | size_t send_buffer_static; 152 | size_t recv_buffer_static; 153 | size_t send_buffer_max_size; 154 | size_t send_buffer_limit_size; 155 | size_t recv_buffer_max_size; 156 | size_t recv_buffer_limit_size; 157 | 158 | int backlog; // backlog indicates the number of connections the kernel might queue 159 | 160 | time_t confirm_timeout; 161 | size_t max_read_net_eagain_count; 162 | size_t max_read_check_block_size_failed_count; 163 | size_t max_read_check_hash_failed_count; 164 | }; 165 | 166 | struct ATBUS_MACRO_API_HEAD_ONLY io_stream_channel { 167 | enum flag_t { 168 | EN_CF_IS_LOOP_OWNER = 0, 169 | EN_CF_CLOSING, 170 | EN_CF_IN_CALLBACK, 171 | EN_CF_MAX, 172 | }; 173 | 174 | adapter::loop_t *ev_loop; 175 | int flags; 176 | 177 | io_stream_conf conf; 178 | 179 | using conn_pool_t = std::unordered_map>; 180 | conn_pool_t conn_pool; 181 | using conn_gc_pool_t = std::unordered_map>; 182 | conn_gc_pool_t conn_gc_pool; 183 | 184 | // 事件响应 185 | io_stream_callback_evt_t evt; 186 | 187 | int error_code; // 记录外部的错误码 188 | // 统计信息 189 | atfw::util::lock::seq_alloc_u32 active_reqs; // 正在进行的req数量 190 | size_t read_net_eagain_count; // 读到的网络重试错误数量 191 | size_t read_check_block_size_failed_count; // 读到的数据块长度检查错误数量 192 | size_t read_check_hash_failed_count; // 读到的数据hash检查错误数量 193 | 194 | // 自定义数据区域 195 | void *data; 196 | }; 197 | 198 | #define ATBUS_CHANNEL_IOS_CHECK_FLAG(f, v) (0 != ((f) & (1 << (v)))) 199 | #define ATBUS_CHANNEL_IOS_SET_FLAG(f, v) (f) |= (1 << (v)) 200 | #define ATBUS_CHANNEL_IOS_UNSET_FLAG(f, v) (f) &= ~(1 << (v)) 201 | #define ATBUS_CHANNEL_IOS_CLEAR_FLAG(f) (f) = 0 202 | 203 | #define ATBUS_CHANNEL_REQ_START(channel) (channel)->active_reqs.inc() 204 | #define ATBUS_CHANNEL_REQ_ACTIVE(channel) ((channel)->active_reqs.get() > 0) 205 | 206 | #define ATBUS_CHANNEL_REQ_END(channel) \ 207 | assert(ATBUS_CHANNEL_REQ_ACTIVE(channel)); \ 208 | (channel)->active_reqs.dec() 209 | } // namespace channel 210 | } // namespace atbus 211 | 212 | #endif /* LIBATBUS_CHANNEL_EXPORT_H_ */ 213 | -------------------------------------------------------------------------------- /include/detail/libatbus_config.h.in: -------------------------------------------------------------------------------- 1 | #ifndef LIBATBUS_DETAIL_LIBATBUS_CONFIG_H 2 | #define LIBATBUS_DETAIL_LIBATBUS_CONFIG_H 3 | 4 | #pragma once 5 | 6 | // This file is generated by cmake, please don't edit it 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #cmakedefine LIBATBUS_VERSION_MAJOR @LIBATBUS_VERSION_MAJOR@ 13 | #ifndef LIBATBUS_VERSION_MAJOR 14 | #define LIBATBUS_VERSION_MAJOR 0 15 | #endif 16 | #cmakedefine LIBATBUS_VERSION_MINOR @LIBATBUS_VERSION_MINOR@ 17 | #ifndef LIBATBUS_VERSION_MINOR 18 | #define LIBATBUS_VERSION_MINOR 0 19 | #endif 20 | #cmakedefine LIBATBUS_VERSION_PATCH @LIBATBUS_VERSION_PATCH@ 21 | #ifndef LIBATBUS_VERSION_PATCH 22 | #define LIBATBUS_VERSION_PATCH 0 23 | #endif 24 | #cmakedefine LIBATBUS_VERSION "@LIBATBUS_VERSION@" 25 | 26 | #cmakedefine ATBUS_MACRO_BUSID_TYPE @ATBUS_MACRO_BUSID_TYPE@ 27 | #cmakedefine ATBUS_MACRO_MESSAGE_LIMIT @ATBUS_MACRO_MESSAGE_LIMIT@ 28 | #cmakedefine ATBUS_MACRO_MAX_FRAME_HEADER @ATBUS_MACRO_MAX_FRAME_HEADER@ 29 | #cmakedefine ATBUS_MACRO_CONNECTION_CONFIRM_TIMEOUT @ATBUS_MACRO_CONNECTION_CONFIRM_TIMEOUT@ 30 | #cmakedefine ATBUS_MACRO_CONNECTION_BACKLOG @ATBUS_MACRO_CONNECTION_BACKLOG@ 31 | #cmakedefine ATBUS_MACRO_DATA_SMALL_SIZE @ATBUS_MACRO_DATA_SMALL_SIZE@ 32 | 33 | #cmakedefine ATBUS_MACRO_DATA_NODE_SIZE @ATBUS_MACRO_DATA_NODE_SIZE@ 34 | #cmakedefine ATBUS_MACRO_DATA_ALIGN_SIZE @ATBUS_MACRO_DATA_ALIGN_SIZE@ 35 | #cmakedefine ATBUS_MACRO_DATA_MAX_PROTECT_SIZE @ATBUS_MACRO_DATA_MAX_PROTECT_SIZE@ 36 | 37 | #cmakedefine ATBUS_MACRO_HUGETLB_SIZE @ATBUS_MACRO_HUGETLB_SIZE@ 38 | 39 | #cmakedefine ATBUS_MACRO_SHM_MEM_CHANNEL_LENGTH @ATBUS_MACRO_SHM_MEM_CHANNEL_LENGTH@ 40 | #cmakedefine ATBUS_MACRO_IOS_SEND_BUFFER_LENGTH @ATBUS_MACRO_IOS_SEND_BUFFER_LENGTH@ 41 | #cmakedefine01 ATBUS_MACRO_ABORT_ON_PROTECTED_ERROR 42 | 43 | 44 | #include 45 | #include 46 | 47 | #if defined(__cplusplus) && __cplusplus >= 201103L 48 | #define ATBUS_MACRO_ENABLE_STATIC_ASSERT 1 49 | #elif defined(_MSC_VER) && _MSC_VER >= 1600 50 | #define ATBUS_MACRO_ENABLE_STATIC_ASSERT 1 51 | #endif 52 | 53 | #cmakedefine ATBUS_MACRO_WITH_UNIX_SOCK @ATBUS_MACRO_WITH_UNIX_SOCK@ 54 | 55 | #define ATBUS_MACRO_RVALUE_REFERENCES && 56 | #define ATBUS_MACRO_MOVE(x) std::move(x) 57 | 58 | #ifndef ATBUS_MACRO_API 59 | # if defined(ATBUS_MACRO_API_NATIVE) && ATBUS_MACRO_API_NATIVE 60 | # if defined(ATBUS_MACRO_API_DLL) && ATBUS_MACRO_API_DLL 61 | # define ATBUS_MACRO_API ATFW_UTIL_SYMBOL_EXPORT 62 | # else 63 | # define ATBUS_MACRO_API ATFW_UTIL_SYMBOL_VISIBLE 64 | # endif 65 | # else 66 | # if defined(ATBUS_MACRO_API_DLL) && ATBUS_MACRO_API_DLL 67 | # define ATBUS_MACRO_API ATFW_UTIL_SYMBOL_IMPORT 68 | # else 69 | # define ATBUS_MACRO_API ATFW_UTIL_SYMBOL_VISIBLE 70 | # endif 71 | # endif 72 | #endif 73 | #define ATBUS_MACRO_API_HEAD_ONLY ATFW_UTIL_SYMBOL_VISIBLE 74 | #define ATBUS_MACRO_API_C(R) extern "C" ATBUS_MACRO_API R __cdecl 75 | 76 | #ifndef ATBUS_MACRO_PROTOCOL_API 77 | # if defined(ATBUS_MACRO_API_NATIVE) && ATBUS_MACRO_API_NATIVE 78 | # if defined(ATBUS_MACRO_API_DLL) && ATBUS_MACRO_API_DLL 79 | # define ATBUS_MACRO_PROTOCOL_API ATFW_UTIL_SYMBOL_IMPORT 80 | # else 81 | # define ATBUS_MACRO_PROTOCOL_API ATFW_UTIL_SYMBOL_VISIBLE 82 | # endif 83 | # else 84 | # define ATBUS_MACRO_PROTOCOL_API ATBUS_MACRO_API 85 | # endif 86 | #endif 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /include/detail/libatbus_error.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBATBUS_DETAIL_LIBATBUS_ERROR_H 2 | #define LIBATBUS_DETAIL_LIBATBUS_ERROR_H 3 | 4 | #pragma once 5 | 6 | enum ATBUS_ERROR_TYPE { 7 | EN_ATBUS_ERR_SUCCESS = 0, 8 | 9 | EN_ATBUS_ERR_PARAMS = -1, 10 | EN_ATBUS_ERR_INNER = -2, 11 | EN_ATBUS_ERR_NO_DATA = -3, // 无数据 12 | EN_ATBUS_ERR_BUFF_LIMIT = -4, // 缓冲区不足 13 | EN_ATBUS_ERR_MALLOC = -5, // 分配失败 14 | EN_ATBUS_ERR_SCHEME = -6, // 协议错误 15 | EN_ATBUS_ERR_BAD_DATA = -7, // 数据校验不通过 16 | EN_ATBUS_ERR_INVALID_SIZE = -8, // 数据大小异常 17 | EN_ATBUS_ERR_NOT_INITED = -9, // 未初始化 18 | EN_ATBUS_ERR_ALREADY_INITED = -10, // 已填充初始数据 19 | EN_ATBUS_ERR_ACCESS_DENY = -11, // 不允许的操作 20 | EN_ATBUS_ERR_UNPACK = -12, // 解包失败 21 | EN_ATBUS_ERR_PACK = -13, // 打包失败 22 | EN_ATBUS_ERR_UNSUPPORTED_VERSION = -14, // 版本不受支持 23 | EN_ATBUS_ERR_CLOSING = -15, // 正在关闭或已关闭 24 | 25 | EN_ATBUS_ERR_ATNODE_NOT_FOUND = -65, // 查找不到目标节点 26 | EN_ATBUS_ERR_ATNODE_INVALID_ID = -66, // 不可用的ID 27 | EN_ATBUS_ERR_ATNODE_NO_CONNECTION = -67, // 无可用连接 28 | EN_ATBUS_ERR_ATNODE_FAULT_TOLERANT = -68, // 超出容错值 29 | EN_ATBUS_ERR_ATNODE_INVALID_MSG = -69, // 错误的消息 30 | EN_ATBUS_ERR_ATNODE_BUS_ID_NOT_MATCH = -70, // Bus ID不匹配 31 | EN_ATBUS_ERR_ATNODE_TTL = -71, // ttl限制 32 | EN_ATBUS_ERR_ATNODE_MASK_CONFLICT = -72, // 域范围错误或冲突 33 | EN_ATBUS_ERR_ATNODE_ID_CONFLICT = -73, // ID冲突 34 | EN_ATBUS_ERR_ATNODE_SRC_DST_IS_SAME = -75, // 发送源和发送目标不能相同 35 | 36 | EN_ATBUS_ERR_CHANNEL_SIZE_TOO_SMALL = -101, 37 | EN_ATBUS_ERR_CHANNEL_BUFFER_INVALID = -102, // 缓冲区错误(已被其他模块使用或检测冲突) 38 | EN_ATBUS_ERR_CHANNEL_ADDR_INVALID = -103, // 地址错误 39 | EN_ATBUS_ERR_CHANNEL_CLOSING = -104, // 正在关闭 40 | EN_ATBUS_ERR_CHANNEL_NOT_SUPPORT = -105, // 不支持的通道 41 | EN_ATBUS_ERR_CHANNEL_UNSUPPORTED_VERSION = -106, // 通道版本不受支持 42 | EN_ATBUS_ERR_CHANNEL_ALIGN_SIZE_MISMATCH = -107, // 对齐参数不一致 43 | EN_ATBUS_ERR_CHANNEL_ARCH_SIZE_T_MISMATCH = -108, // 架构size_t不匹配 44 | 45 | EN_ATBUS_ERR_NODE_BAD_BLOCK_NODE_NUM = -202, // 发现写坏的数据块 - 节点数量错误 46 | EN_ATBUS_ERR_NODE_BAD_BLOCK_BUFF_SIZE = -203, // 发现写坏的数据块 - 节点数量错误 47 | EN_ATBUS_ERR_NODE_BAD_BLOCK_WSEQ_ID = -204, // 发现写坏的数据块 - 写操作序列错误 48 | EN_ATBUS_ERR_NODE_BAD_BLOCK_CSEQ_ID = -205, // 发现写坏的数据块 - 检查操作序列错误 49 | 50 | EN_ATBUS_ERR_NODE_TIMEOUT = -211, // 操作超时 51 | 52 | EN_ATBUS_ERR_SHM_GET_FAILED = -301, // 连接共享内存出错,具体错误原因可以查看errno或类似的位置 53 | EN_ATBUS_ERR_SHM_NOT_FOUND = -302, // 共享内存未找到 54 | EN_ATBUS_ERR_SHM_CLOSE_FAILED = -303, // 移除共享内存出错,具体错误原因可以查看errno或类似的位置 55 | EN_ATBUS_ERR_SHM_PATH_INVALID = -304, // 共享内存地址错误 56 | EN_ATBUS_ERR_SHM_MAP_FAILED = -305, // 共享内存地址映射错误 57 | 58 | EN_ATBUS_ERR_SOCK_BIND_FAILED = -401, // 绑定地址或端口失败 59 | EN_ATBUS_ERR_SOCK_LISTEN_FAILED = -402, // 监听失败 60 | EN_ATBUS_ERR_SOCK_CONNECT_FAILED = -403, // 连接失败 61 | 62 | EN_ATBUS_ERR_PIPE_BIND_FAILED = -501, // 绑定地址或端口失败 63 | EN_ATBUS_ERR_PIPE_LISTEN_FAILED = -502, // 监听失败 64 | EN_ATBUS_ERR_PIPE_CONNECT_FAILED = -503, // 连接失败 65 | EN_ATBUS_ERR_PIPE_ADDR_TOO_LONG = -504, // 地址路径过长,绝对路径长度要小于 sizeof(sockaddr_un.sun_path) - 1 66 | EN_ATBUS_ERR_PIPE_REMOVE_FAILED = -505, // 删除老socket失败 67 | EN_ATBUS_ERR_PIPE_PATH_EXISTS = -506, // 该地址已被占用 68 | EN_ATBUS_ERR_PIPE_LOCK_PATH_FAILED = -507, // 锁地址失败 69 | 70 | EN_ATBUS_ERR_DNS_GETADDR_FAILED = -601, // DNS解析失败 71 | EN_ATBUS_ERR_CONNECTION_NOT_FOUND = -602, // 找不到连接 72 | EN_ATBUS_ERR_WRITE_FAILED = -603, // 底层API写失败 73 | EN_ATBUS_ERR_READ_FAILED = -604, // 底层API读失败 74 | EN_ATBUS_ERR_EV_RUN = -605, // 底层API事件循环失败 75 | EN_ATBUS_ERR_NO_LISTEN = -606, // 尚未监听(绑定) 76 | EN_ATBUS_ERR_NOT_READY = -607, // 未准备好(没有握手完成) 77 | 78 | EN_ATBUS_ERR_MIN = -999, 79 | }; 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /include/detail/libatbus_protocol.fbs: -------------------------------------------------------------------------------- 1 | 2 | namespace atbus.protocol; 3 | 4 | // --gen-mutable --gen-name-strings --no-includes --natural-utf8 --allow-non-utf8 5 | 6 | enum ATBUS_PROTOCOL_CONST : byte { 7 | ATBUS_PROTOCOL_VERSION = 2, 8 | } 9 | 10 | enum ATBUS_PROTOCOL_COMPACT : byte { 11 | ATBUS_PROTOCOL_MINIMAL_VERSION = 2, // minimal protocol version supported 12 | } 13 | 14 | enum ATBUS_FORWARD_DATA_FLAG_TYPE : uint32 (bit_flags) { 15 | REQUIRE_RSP = 1 16 | } 17 | 18 | table custom_command_argv { 19 | arg: [ubyte] (id: 0); 20 | } 21 | 22 | table custom_command_data { 23 | from : uint64 (id: 0); 24 | commands : [custom_command_argv] (id: 1); 25 | access_keys : [access_data] (id: 2); // ID: 2 26 | } 27 | 28 | table forward_data { 29 | from : uint64 (id: 0); 30 | to : uint64 (id: 1); 31 | router : [uint64] (id: 2); 32 | content : [ubyte] (id: 3); 33 | flags : uint32 (id: 4); 34 | } 35 | 36 | table access_data { 37 | token_salt : uint32 (id: 0); 38 | token_hash1: uint64 (id: 1); 39 | token_hash2: uint64 (id: 2); 40 | } 41 | 42 | table channel_data { 43 | address: string (id: 0); // ID: 0 44 | } 45 | 46 | table node_data { 47 | bus_id : uint64 (id: 0); // ID: 0 48 | overwrite : bool (id: 1); // ID: 1 49 | flags : bool (id: 2); // ID: 2 50 | children_id_mask : uint64 (id: 3); // ID: 3 51 | children_id_prefix : uint64 (id: 4); // ID: 4(0 for using bus_id) 52 | children : [node_data] (id: 5); // ID: 5 53 | } 54 | 55 | table node_tree { 56 | nodes: [node_data] (id: 0); 57 | } 58 | 59 | table ping_data { 60 | time_point: int64 (id: 0); // ID: 0 61 | } 62 | 63 | table register_data { 64 | bus_id : uint64 (id: 0); // ID: 0 65 | pid : int32 (id: 1); // ID: 1 66 | hostname : string (id: 2); // ID: 2 67 | channels : [channel_data] (id: 3); // ID: 3 68 | children_id_mask : uint32 (id: 4); // ID: 4 69 | children_id_prefix : uint64 (id: 5); // ID: 5(0 for using bus_id) 70 | flags : uint32 (id: 6); // ID: 6 71 | access_keys : [access_data] (id: 7); // ID: 7 72 | } 73 | 74 | table connection_data { 75 | address: channel_data (id: 0); // ID: 0 76 | } 77 | 78 | union msg_body { 79 | // invalid_body : string (id: 0); 80 | custom_command_req : custom_command_data = 1, 81 | custom_command_rsp : custom_command_data = 2, 82 | data_transform_req : forward_data = 3, 83 | data_transform_rsp : forward_data = 4, 84 | node_sync_req : node_tree = 5, 85 | node_sync_rsp : node_tree = 6, 86 | node_register_req : register_data = 7, 87 | node_register_rsp : register_data = 8, 88 | node_connect_sync : connection_data = 10, 89 | node_ping_req : ping_data = 11, 90 | node_pong_rsp : ping_data = 12, 91 | } 92 | 93 | table msg_head { 94 | version : int32 (id: 0); 95 | type : int32 (id: 1); 96 | ret : int32 (id: 2); 97 | sequence : uint64 (id: 3); 98 | src_bus_id : uint64 (id: 4); 99 | } 100 | 101 | table msg { 102 | head: msg_head (id: 0); 103 | body: msg_body (id: 2); // id: 1 is implicitly added for body case by flatc 104 | } 105 | 106 | root_type msg; -------------------------------------------------------------------------------- /include/include.macro.cmake: -------------------------------------------------------------------------------- 1 | # =========== include - macro =========== 2 | set(PROJECT_LIBATBUS_ROOT_INC_DIR ${CMAKE_CURRENT_LIST_DIR}) 3 | 4 | set(PROJECT_LIBATBUS_GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/_generated") 5 | file(MAKE_DIRECTORY "${PROJECT_LIBATBUS_GENERATED_DIR}/include/detail") 6 | file(MAKE_DIRECTORY "${PROJECT_LIBATBUS_GENERATED_DIR}/src") 7 | file(MAKE_DIRECTORY "${PROJECT_LIBATBUS_GENERATED_DIR}/temp") 8 | 9 | # define CONF from cmake to c macro 10 | configure_file("${CMAKE_CURRENT_LIST_DIR}/detail/libatbus_config.h.in" 11 | "${PROJECT_LIBATBUS_GENERATED_DIR}/temp/libatbus_config.h" @ONLY) 12 | 13 | execute_process( 14 | COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${PROJECT_LIBATBUS_GENERATED_DIR}/temp/libatbus_config.h" 15 | "${PROJECT_LIBATBUS_GENERATED_DIR}/include/detail") 16 | -------------------------------------------------------------------------------- /include/libatbus.h: -------------------------------------------------------------------------------- 1 | /** 2 | * libatbus.h 3 | * 4 | * Created on: 2014年8月11日 5 | * Author: owent 6 | */ 7 | 8 | #pragma once 9 | 10 | #ifndef LIBATBUS_H 11 | # define LIBATBUS_H 12 | 13 | # pragma once 14 | 15 | # include "atbus_msg_handler.h" 16 | # include "atbus_node.h" 17 | 18 | #endif /* LIBATBUS_H_ */ 19 | -------------------------------------------------------------------------------- /include/libatbus_protocol.h: -------------------------------------------------------------------------------- 1 | /** 2 | * libatbus.h 3 | * 4 | * Created on: 2014年8月11日 5 | * Author: owent 6 | */ 7 | 8 | #pragma once 9 | 10 | #pragma once 11 | 12 | #include "detail/libatbus_config.h" 13 | 14 | // clang-format off 15 | # include "config/compiler/protobuf_prefix.h" 16 | // clang-format on 17 | 18 | #include "google/protobuf/arena.h" 19 | 20 | #include "libatbus_protocol.pb.h" // NOLINT 21 | 22 | // clang-format off 23 | # include "config/compiler/protobuf_suffix.h" 24 | // clang-format on 25 | 26 | namespace atbus { 27 | using msg_t = ::atbus::protocol::msg; 28 | } // namespace atbus 29 | 30 | #define ATBUS_MACRO_RESERVED_SIZE 1024 31 | 32 | #ifndef ATBUS_MACRO_PROTOBUF_NAMESPACE_ID 33 | # define ATBUS_MACRO_PROTOBUF_NAMESPACE_ID google::protobuf 34 | #endif 35 | -------------------------------------------------------------------------------- /include/libatbus_protocol.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package atbus.protocol; 4 | 5 | option optimize_for = SPEED; 6 | // option optimize_for = LITE_RUNTIME; 7 | // option optimize_for = CODE_SIZE; 8 | // --cpp_out=lite:,--cpp_out= 9 | option cc_enable_arenas = true; 10 | 11 | enum ATBUS_PROTOCOL_CONST { 12 | option allow_alias = true; 13 | ATBUS_PROTOCOL_CONST_UNKNOWN = 0; 14 | ATBUS_PROTOCOL_VERSION = 2; 15 | ATBUS_PROTOCOL_MINIMAL_VERSION = 2; // minimal protocol version supported 16 | } 17 | 18 | enum ATBUS_FORWARD_DATA_FLAG_TYPE { 19 | FORWARD_DATA_FLAG_NONE = 0; 20 | // all flags must be power of 2 21 | FORWARD_DATA_FLAG_REQUIRE_RSP = 1; 22 | } 23 | 24 | message custom_command_argv { bytes arg = 1; } 25 | 26 | message custom_command_data { 27 | uint64 from = 1; 28 | repeated custom_command_argv commands = 2; 29 | repeated access_data access_keys = 3; 30 | } 31 | 32 | message forward_data { 33 | uint64 from = 1; 34 | uint64 to = 2; 35 | repeated uint64 router = 3; 36 | bytes content = 4; 37 | uint32 flags = 5; 38 | } 39 | 40 | message access_data { 41 | uint32 token_salt = 1; 42 | uint64 token_hash1 = 2; 43 | uint64 token_hash2 = 3; 44 | } 45 | 46 | message channel_data { string address = 1; } 47 | 48 | message node_data { 49 | uint64 bus_id = 1; 50 | bool overwrite = 2; 51 | bool flags = 3; 52 | uint64 children_id_mask = 4; 53 | uint64 children_id_prefix = 5; 54 | repeated node_data children = 6; 55 | } 56 | 57 | message node_tree { repeated node_data nodes = 1; } 58 | 59 | message ping_data { int64 time_point = 1; } 60 | 61 | message subnet_range { 62 | uint64 id_prefix = 1; 63 | uint32 mask_bits = 2; // suffix 64 | } 65 | 66 | message register_data { 67 | uint64 bus_id = 1; 68 | int32 pid = 2; 69 | string hostname = 3; 70 | repeated channel_data channels = 4; 71 | uint32 flags = 7; 72 | repeated access_data access_keys = 8; 73 | repeated subnet_range subnets = 9; 74 | string hash_code = 10; 75 | } 76 | 77 | message connection_data { channel_data address = 1; } 78 | 79 | message msg_head { 80 | int32 version = 1; 81 | int32 type = 2; 82 | sint32 ret = 3; 83 | uint64 sequence = 4; 84 | uint64 src_bus_id = 5; 85 | } 86 | 87 | message msg { 88 | msg_head head = 1; 89 | oneof msg_body { 90 | custom_command_data custom_command_req = 11; 91 | custom_command_data custom_command_rsp = 12; 92 | forward_data data_transform_req = 13; 93 | forward_data data_transform_rsp = 14; 94 | node_tree node_sync_req = 15; 95 | node_tree node_sync_rsp = 16; 96 | register_data node_register_req = 17; 97 | register_data node_register_rsp = 18; 98 | connection_data node_connect_sync = 20; 99 | ping_data node_ping_req = 21; 100 | ping_data node_pong_rsp = 22; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /libatbus-config.cmake.in: -------------------------------------------------------------------------------- 1 | #[=======================================================================[.rst: 2 | libatbus-config.cmake 3 | --------------------- 4 | 5 | Find the native libatbus includes and library. 6 | 7 | 8 | Result Variables 9 | ^^^^^^^^^^^^^^^^ 10 | 11 | This module defines the following variables: 12 | 13 | ``Libatbus_INCLUDE_DIRS`` 14 | Where to find detail/libatbus_config.h , etc. 15 | ``Libatbus_PROTOCOL_DIRS`` 16 | Where to find libatbus_protocol.proto , etc. 17 | ``Libatbus_LIBRARY_DIRS`` 18 | Where to find (lib)atbus.(a/so/lib/dll/dylib), etc. 19 | ``Libatbus_LIBRARIES`` 20 | List of libraries when using libatbus. 21 | ``Libatbus_FOUND`` 22 | True if libatbus found. 23 | ``Libatbus_VERSION`` 24 | Full version of libatbus 25 | 26 | 27 | The following :prop_tgt:`IMPORTED` targets are also defined: 28 | 29 | ``atframework::atbus`` 30 | The libatbus library 31 | 32 | ============================================================================= 33 | Copyright 2020 OWenT. 34 | 35 | Distributed under the OSI-approved BSD License (the "License"); 36 | see accompanying file Copyright.txt for details. 37 | 38 | This software is distributed WITHOUT ANY WARRANTY; without even the 39 | implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 40 | See the License for more information. 41 | ============================================================================= 42 | (To distribute this file outside of CMake, substitute the full License text for 43 | the above reference.) 44 | 45 | #]=======================================================================] 46 | 47 | set(${CMAKE_FIND_PACKAGE_NAME}_VERSION "@LIBATBUS_VERSION@") 48 | 49 | @PACKAGE_INIT@ 50 | 51 | # ###################################################################################################################### 52 | # libatbus source dir 53 | set(${CMAKE_FIND_PACKAGE_NAME}_SOURCE_DIR "@PROJECT_SOURCE_DIR@") 54 | 55 | set_and_check(${CMAKE_FIND_PACKAGE_NAME}_INCLUDE_DIRS "@PACKAGE_INCLUDE_INSTALL_DIR@") 56 | set_and_check(${CMAKE_FIND_PACKAGE_NAME}_LIBRARY_DIRS "@PACKAGE_CMAKE_INSTALL_LIBDIR@") 57 | set_and_check(${CMAKE_FIND_PACKAGE_NAME}_PROTOCOL_DIRS "@PACKAGE_INCLUDE_INSTALL_DIR@") 58 | 59 | include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_LIBATBUS_EXPORT_NAME@.cmake") 60 | if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@PROJECT_LIBATBUS_EXPORT_NAME@.cmake") 61 | include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_LIBATBUS_EXPORT_NAME@.cmake") 62 | endif() 63 | # Normal search. 64 | set(${CMAKE_FIND_PACKAGE_NAME}_LIBRARIES atframework::atbus) 65 | 66 | # handle the QUIETLY and REQUIRED arguments and set LIBATBUS_FOUND to TRUE if all listed variables are TRUE 67 | include("FindPackageHandleStandardArgs") 68 | find_package_handle_standard_args( 69 | ${CMAKE_FIND_PACKAGE_NAME} 70 | FOUND_VAR ${CMAKE_FIND_PACKAGE_NAME}_FOUND 71 | REQUIRED_VARS ${CMAKE_FIND_PACKAGE_NAME}_INCLUDE_DIRS ${CMAKE_FIND_PACKAGE_NAME}_LIBRARIES) 72 | 73 | if(${CMAKE_FIND_PACKAGE_NAME}_FOUND) 74 | set(LIBATBUS_FOUND ${${CMAKE_FIND_PACKAGE_NAME}_FOUND}) 75 | endif() 76 | 77 | # check_required_components(${CMAKE_FIND_PACKAGE_NAME}) 78 | -------------------------------------------------------------------------------- /project/cmake/FetchDependeny.cmake: -------------------------------------------------------------------------------- 1 | include_guard(GLOBAL) 2 | 3 | find_package(Git REQUIRED) 4 | 5 | set(ATFRAMEWORK_CMAKE_TOOLSET_DIR 6 | "${PROJECT_SOURCE_DIR}/atframework/cmake-toolset" 7 | CACHE PATH "PATH to cmake-toolset") 8 | 9 | if(NOT ATFRAMEWORK_CMAKE_TOOLSET_EXECUTE_PROCESS_OUTPUT_OPTIONS) 10 | unset(ATFRAMEWORK_CMAKE_TOOLSET_EXECUTE_PROCESS_OUTPUT_OPTIONS) 11 | if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.15") 12 | list(APPEND ATFRAMEWORK_CMAKE_TOOLSET_EXECUTE_PROCESS_OUTPUT_OPTIONS COMMAND_ECHO STDOUT) 13 | endif() 14 | if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18") 15 | list(APPEND ATFRAMEWORK_CMAKE_TOOLSET_EXECUTE_PROCESS_OUTPUT_OPTIONS ECHO_OUTPUT_VARIABLE ECHO_ERROR_VARIABLE) 16 | endif() 17 | endif() 18 | 19 | if(NOT EXISTS "${ATFRAMEWORK_CMAKE_TOOLSET_DIR}/Import.cmake") 20 | execute_process( 21 | COMMAND ${GIT_EXECUTABLE} submodule update --depth 100 --recommend-shallow -f --init -- atframework/cmake-toolset 22 | WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" ${ATFRAMEWORK_CMAKE_TOOLSET_EXECUTE_PROCESS_OUTPUT_OPTIONS}) 23 | set(ATFRAMEWORK_CMAKE_TOOLSET_DIR 24 | "${PROJECT_SOURCE_DIR}/atframework/cmake-toolset" 25 | CACHE PATH "PATH to cmake-toolset" FORCE) 26 | endif() 27 | 28 | include("${ATFRAMEWORK_CMAKE_TOOLSET_DIR}/Import.cmake") 29 | -------------------------------------------------------------------------------- /project/cmake/ProjectBuildOption.cmake: -------------------------------------------------------------------------------- 1 | # 默认配置选项 2 | # ###################################################################################################################### 3 | 4 | include("${CMAKE_CURRENT_LIST_DIR}/FetchDependeny.cmake") 5 | include(IncludeDirectoryRecurse) 6 | include(EchoWithColor) 7 | 8 | # atbus 选项 9 | set(ATBUS_MACRO_BUSID_TYPE 10 | "uint64_t" 11 | CACHE STRING "busid type") 12 | set(ATBUS_MACRO_DATA_NODE_SIZE 13 | 256 14 | CACHE STRING "node size of (shared) memory channel(must be power of 2)") 15 | set(ATBUS_MACRO_DATA_ALIGN_SIZE 16 | 16 17 | CACHE STRING "memory align size, most architecture require to padding to 16") 18 | set(ATBUS_MACRO_DATA_MAX_PROTECT_SIZE 19 | 16384 20 | CACHE STRING "max protected node size for mem/shm channel") 21 | 22 | # By now, other component in io_stream_connection cost 472 bytes, make_shared will also cost some memory. we hope one 23 | # connection will cost no more than 8KB, so 100K connections will cost no more than 800MB memory so we use 7KB for small 24 | # message buffer, and left about 500 Bytes in future use. This can be 512 or smaller (but not smaller than 32), but in 25 | # most server environment, memory is cheap and there are only few connections between server and server. 26 | set(ATBUS_MACRO_DATA_SMALL_SIZE 27 | 7168 28 | CACHE STRING 29 | "small message buffer for io_stream channel(used to reduce memory copy when there are many small messages)") 30 | 31 | set(ATBUS_MACRO_HUGETLB_SIZE 32 | 4194304 33 | CACHE STRING "huge page size in shared memory channel(unused now)") 34 | set(ATBUS_MACRO_MESSAGE_LIMIT 35 | 2097152 36 | CACHE STRING "message size hard limit") 37 | set(ATBUS_MACRO_MAX_FRAME_HEADER 38 | 1024 39 | CACHE STRING "message header size limit") 40 | set(ATBUS_MACRO_CONNECTION_CONFIRM_TIMEOUT 41 | 30 42 | CACHE STRING "connection confirm timeout") 43 | set(ATBUS_MACRO_CONNECTION_BACKLOG 44 | 256 45 | CACHE STRING "tcp backlog") 46 | set(ATBUS_MACRO_SHM_MEM_CHANNEL_LENGTH 47 | 167510016 48 | CACHE STRING "channel size for shm/mem channel") 49 | set(ATBUS_MACRO_IOS_SEND_BUFFER_LENGTH 50 | 4194304 51 | CACHE STRING "send buffer size for iostream channel") 52 | option(ATBUS_MACRO_ABORT_ON_PROTECTED_ERROR "abort when any inner error found." OFF) 53 | 54 | option(ATFRAMEWORK_USE_DYNAMIC_LIBRARY "Build and linking with dynamic libraries." OFF) 55 | 56 | # libuv选项 57 | set(LIBUV_ROOT 58 | "" 59 | CACHE STRING "libuv root directory") 60 | 61 | # 测试配置选项 62 | set(GTEST_ROOT 63 | "" 64 | CACHE STRING "GTest root directory") 65 | set(BOOST_ROOT 66 | "" 67 | CACHE STRING "Boost root directory") 68 | option(PROJECT_TEST_ENABLE_BOOST_UNIT_TEST "Enable boost unit test." OFF) 69 | 70 | # find if we have Unix Sock 71 | include(CheckIncludeFiles) 72 | check_include_files("sys/un.h;sys/socket.h" ATBUS_MACRO_WITH_UNIX_SOCK) 73 | -------------------------------------------------------------------------------- /sample/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | echowithcolor(COLOR GREEN "-- Configure ${CMAKE_CURRENT_LIST_DIR}") 2 | 3 | include("${CMAKE_CURRENT_LIST_DIR}/sample.custom-macro.cmake") 4 | 5 | # ============ sample - [...] ============ 6 | 7 | file( 8 | GLOB SAMPLE_SRC_LIST 9 | RELATIVE "${PROJECT_SAMPLE_SRC_DIR}" 10 | ${PROJECT_SAMPLE_SRC_DIR}/*.cpp ${PROJECT_SAMPLE_SRC_DIR}/*.cc ${PROJECT_SAMPLE_SRC_DIR}/*.c 11 | ${PROJECT_SAMPLE_SRC_DIR}/*.cxx) 12 | 13 | set(CMAKE_BUILD_RPATH "${CMAKE_INSTALL_RPATH}") 14 | if(NOT (WIN32 AND BUILD_SHARED_LIBS)) 15 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/sample") 16 | endif() 17 | 18 | foreach(SAMPLE_SRC_FILE IN LISTS SAMPLE_SRC_LIST) 19 | get_filename_component(SAMPLE_SRC_BIN_NAME ${SAMPLE_SRC_FILE} NAME_WE) 20 | set(SAMPLE_SRC_BIN_NAME "atbus_${SAMPLE_SRC_BIN_NAME}") 21 | 22 | add_executable(${SAMPLE_SRC_BIN_NAME} ${SAMPLE_SRC_FILE}) 23 | target_link_libraries(${SAMPLE_SRC_BIN_NAME} atframework::atbus) 24 | 25 | target_compile_options(${SAMPLE_SRC_BIN_NAME} PRIVATE ${PROJECT_LIBATBUS_PRIVATE_COMPILE_OPTIONS}) 26 | 27 | set_property(TARGET ${SAMPLE_SRC_BIN_NAME} PROPERTY FOLDER "atframework/sample/atbus") 28 | if(MSVC) 29 | add_target_properties(${SAMPLE_SRC_BIN_NAME} LINK_FLAGS /NODEFAULTLIB:library) 30 | endif() 31 | endforeach() 32 | -------------------------------------------------------------------------------- /sample/sample.custom-macro.cmake: -------------------------------------------------------------------------------- 1 | # =========== sample =========== 2 | set(PROJECT_SAMPLE_BAS_DIR ${CMAKE_CURRENT_LIST_DIR}) 3 | set(PROJECT_SAMPLE_INC_DIR ${PROJECT_SAMPLE_BAS_DIR}) 4 | set(PROJECT_SAMPLE_SRC_DIR ${PROJECT_SAMPLE_BAS_DIR}) 5 | -------------------------------------------------------------------------------- /sample/sample_usage_01.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | int main() { 12 | #if defined(UTIL_CONFIG_COMPILER_CXX_LAMBDAS) && UTIL_CONFIG_COMPILER_CXX_LAMBDAS 13 | // 初始化默认配置 14 | atbus::node::conf_t conf; 15 | atbus::node::default_conf(&conf); 16 | 17 | // 子域的范围设为16(后16位都是子节点), id_prefix=0 等于使用endpoint自己的ID 18 | conf.subnets.push_back(atbus::endpoint_subnet_conf(0, 16)); 19 | 20 | // 初始化libuv事件分发器 21 | uv_loop_t ev_loop; 22 | uv_loop_init(&ev_loop); 23 | 24 | // 指定事件分发器 25 | conf.ev_loop = &ev_loop; 26 | 27 | { 28 | // 创建两个通信节点 29 | atbus::node::ptr_t node1 = atbus::node::create(); 30 | atbus::node::ptr_t node2 = atbus::node::create(); 31 | 32 | // 初始化 33 | node1->init(0x12345678, &conf); // BUS ID=0x12345678, 0x1234XXXX 都是子节点 34 | node2->init(0x12356789, &conf); // BUS ID=0x12356789, 0x1235XXXX 都是子节点 35 | // 所以这两个都是兄弟节点 36 | 37 | // 各自监听地址 38 | node1->listen("ipv4://127.0.0.1:16387"); 39 | node2->listen("ipv4://127.0.0.1:16388"); 40 | 41 | // 启动初始化 42 | node1->start(); 43 | node2->start(); 44 | 45 | // 启动连接 46 | node1->connect("ipv4://127.0.0.1:16388"); 47 | 48 | // 等待连接成功 49 | // 如果是拥有共同父节点的兄弟节点不能这么判定,因为在第一次发消息前是不会建立连接的 50 | for (int i = 0; i < 512; ++i) { 51 | if (node2->is_endpoint_available(node1->get_id()) && node1->is_endpoint_available(node2->get_id())) { 52 | break; 53 | } 54 | 55 | uv_run(conf.ev_loop, UV_RUN_ONCE); 56 | 57 | // 定期执行proc函数,用于处理内部定时器 58 | // 第一个参数是Unix时间戳(秒),第二个参数是微秒 59 | node1->proc(time(nullptr), 0); 60 | node2->proc(time(nullptr), 0); 61 | } 62 | 63 | // 设置接收到消息后的回调函数 64 | bool recved = false; 65 | node2->set_on_recv_handle([&recved](const atbus::node &n, const atbus::endpoint *ep, const atbus::connection *conn, 66 | const atbus::msg_t &, const void *buffer, size_t len) { 67 | if (nullptr != ep && nullptr != conn) { 68 | std::cout << "atbus node 0x" << std::ios::hex << n.get_id() << " receive data from 0x" << std::ios::hex 69 | << ep->get_id() << "(connection: " << conn->get_address().address << "): "; 70 | } 71 | std::cout.write(reinterpret_cast(buffer), static_cast(len)); 72 | std::cout << std::endl; 73 | recved = true; 74 | return 0; 75 | }); 76 | 77 | // 发送数据 78 | std::string send_data = "hello world!"; 79 | node1->send_data(node2->get_id(), 0, send_data.data(), send_data.size()); 80 | 81 | // 等待发送完成 82 | while (!recved) { 83 | uv_run(conf.ev_loop, UV_RUN_ONCE); 84 | 85 | // 定期执行proc函数,用于处理内部定时器 86 | // 第一个参数是Unix时间戳(秒),第二个参数是微秒 87 | node1->proc(time(nullptr), 0); 88 | node2->proc(time(nullptr), 0); 89 | } 90 | 91 | // 析构时会自动关闭所持有的资源 92 | } 93 | 94 | // 关闭libuv事件分发器 95 | while (UV_EBUSY == uv_loop_close(&ev_loop)) { 96 | uv_run(&ev_loop, UV_RUN_ONCE); 97 | } 98 | #else 99 | std::cout << "lambda not supported, ignore this sample" << std::endl; 100 | #endif 101 | return 0; 102 | } -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | echowithcolor(COLOR GREEN "-- Configure ${CMAKE_CURRENT_LIST_DIR}") 2 | 3 | file(RELATIVE_PATH PROJECT_ROOT_RELINC_DIR ${CMAKE_CURRENT_LIST_DIR} ${PROJECT_LIBATBUS_ROOT_INC_DIR}) 4 | 5 | set(PROJECT_LIB_SRC_LIST 6 | "${PROJECT_LIBATBUS_ROOT_INC_DIR}/detail/buffer.h" 7 | "${PROJECT_LIBATBUS_ROOT_INC_DIR}/detail/libatbus_adapter_libuv.h" 8 | "${PROJECT_LIBATBUS_ROOT_INC_DIR}/detail/libatbus_channel_export.h" 9 | "${PROJECT_LIBATBUS_ROOT_INC_DIR}/detail/libatbus_channel_types.h" 10 | "${PROJECT_LIBATBUS_ROOT_INC_DIR}/detail/libatbus_error.h" 11 | "${PROJECT_LIBATBUS_ROOT_INC_DIR}/atbus_connection.h" 12 | "${PROJECT_LIBATBUS_ROOT_INC_DIR}/atbus_endpoint.h" 13 | "${PROJECT_LIBATBUS_ROOT_INC_DIR}/atbus_msg_handler.h" 14 | "${PROJECT_LIBATBUS_ROOT_INC_DIR}/atbus_node.h" 15 | "${PROJECT_LIBATBUS_ROOT_INC_DIR}/libatbus.h" 16 | "${PROJECT_LIBATBUS_ROOT_INC_DIR}/libatbus_protocol.h" 17 | "${PROJECT_LIBATBUS_ROOT_SRC_DIR}/detail/buffer.cpp" 18 | "${PROJECT_LIBATBUS_ROOT_SRC_DIR}/atbus_connection.cpp" 19 | "${PROJECT_LIBATBUS_ROOT_SRC_DIR}/atbus_endpoint.cpp" 20 | "${PROJECT_LIBATBUS_ROOT_SRC_DIR}/atbus_msg_handler.cpp" 21 | "${PROJECT_LIBATBUS_ROOT_SRC_DIR}/atbus_node.cpp" 22 | "${PROJECT_LIBATBUS_ROOT_SRC_DIR}/channel_io_stream.cpp" 23 | "${PROJECT_LIBATBUS_ROOT_SRC_DIR}/channel_mem.cpp" 24 | "${PROJECT_LIBATBUS_ROOT_SRC_DIR}/channel_shm.cpp" 25 | "${PROJECT_LIBATBUS_ROOT_SRC_DIR}/channel_utility.cpp") 26 | 27 | source_group(TREE "${PROJECT_SOURCE_DIR}" FILES ${PROJECT_LIB_SRC_LIST}) 28 | 29 | list(APPEND PROJECT_LIB_SRC_LIST "${PROJECT_LIBATBUS_GENERATED_DIR}/include/detail/libatbus_config.h") 30 | source_group(TREE "${PROJECT_LIBATBUS_GENERATED_DIR}" 31 | FILES "${PROJECT_LIBATBUS_GENERATED_DIR}/include/detail/libatbus_config.h") 32 | 33 | set(PROJECT_LIB_PROTOCOL_SRC_LIST "${PROJECT_LIBATBUS_GENERATED_DIR}/include/libatbus_protocol.pb.h" 34 | "${PROJECT_LIBATBUS_GENERATED_DIR}/src/libatbus_protocol.pb.cc") 35 | 36 | set_source_files_properties("${PROJECT_LIBATBUS_GENERATED_DIR}/include/libatbus_protocol.pb.h" 37 | "${PROJECT_LIBATBUS_GENERATED_DIR}/src/libatbus_protocol.pb.cc" PROPERTIES GENERATED TRUE) 38 | 39 | # ============ libatbus - src ============ 40 | if(NOT DEFINED ATBUS_MACRO_PROTOCOL_USE_DYNAMIC_LIBRARY) 41 | if(BUILD_SHARED_LIBS OR ATFRAMEWORK_USE_DYNAMIC_LIBRARY) 42 | if(DEFINED ATFRAMEWORK_CMAKE_TOOLSET_THIRD_PARTY_PROTOBUF_ALLOW_SHARED_LIBS) 43 | set(ATBUS_MACRO_PROTOCOL_USE_DYNAMIC_LIBRARY ${ATFRAMEWORK_CMAKE_TOOLSET_THIRD_PARTY_PROTOBUF_ALLOW_SHARED_LIBS}) 44 | else() 45 | set(ATBUS_MACRO_PROTOCOL_USE_DYNAMIC_LIBRARY TRUE) 46 | endif() 47 | else() 48 | set(ATBUS_MACRO_PROTOCOL_USE_DYNAMIC_LIBRARY FALSE) 49 | endif() 50 | endif() 51 | 52 | if(ATBUS_MACRO_PROTOCOL_USE_DYNAMIC_LIBRARY) 53 | add_library("${PROJECT_LIBATBUS_LIB_LINK}-protocol" SHARED ${PROJECT_LIB_PROTOCOL_SRC_LIST}) 54 | project_build_tools_set_shared_library_declaration(ATBUS_MACRO_PROTOCOL_API "${PROJECT_LIBATBUS_LIB_LINK}-protocol") 55 | else() 56 | add_library("${PROJECT_LIBATBUS_LIB_LINK}-protocol" STATIC ${PROJECT_LIB_PROTOCOL_SRC_LIST}) 57 | if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang|Intel|XL|XLClang") 58 | target_compile_definitions("${PROJECT_LIBATBUS_LIB_LINK}-protocol" 59 | PUBLIC "ATBUS_MACRO_PROTOCOL_API=__attribute__((visibility(\"default\")))") 60 | else() 61 | target_compile_definitions("${PROJECT_LIBATBUS_LIB_LINK}-protocol" PUBLIC "ATBUS_MACRO_PROTOCOL_API=") 62 | endif() 63 | endif() 64 | if(NOT APPLE) 65 | set_target_properties("${PROJECT_LIBATBUS_LIB_LINK}-protocol" PROPERTIES C_VISIBILITY_PRESET "hidden" 66 | CXX_VISIBILITY_PRESET "hidden") 67 | endif() 68 | set_target_properties("${PROJECT_LIBATBUS_LIB_LINK}-protocol" PROPERTIES VERSION ${LIBATBUS_VERSION}) 69 | target_link_libraries("${PROJECT_LIBATBUS_LIB_LINK}-protocol" 70 | PUBLIC ${ATFRAMEWORK_CMAKE_TOOLSET_THIRD_PARTY_PROTOBUF_LINK_NAME}) 71 | target_include_directories( 72 | "${PROJECT_LIBATBUS_LIB_LINK}-protocol" 73 | PRIVATE "$" 74 | PUBLIC "$" "$") 75 | 76 | set(PROJECT_LIBATBUS_PROTOCOL_SOURCE_COMPILE_OPTIONS ${PROJECT_COMMON_PRIVATE_COMPILE_OPTIONS} 77 | ${PROJECT_BUILD_TOOLS_PATCH_PROTOBUF_SOURCES_OPTIONS}) 78 | if(PROJECT_BUILD_TOOLS_PATCH_PROTOBUF_SOURCES_REMOVE_OPTIONS) 79 | list(REMOVE_ITEM PROJECT_LIBATBUS_PROTOCOL_SOURCE_COMPILE_OPTIONS 80 | ${PROJECT_BUILD_TOOLS_PATCH_PROTOBUF_SOURCES_REMOVE_OPTIONS}) 81 | endif() 82 | 83 | if(PROJECT_LIBATBUS_PROTOCOL_SOURCE_COMPILE_OPTIONS) 84 | target_compile_options("${PROJECT_LIBATBUS_LIB_LINK}-protocol" 85 | PRIVATE ${PROJECT_LIBATBUS_PROTOCOL_SOURCE_COMPILE_OPTIONS}) 86 | endif() 87 | 88 | list(PREPEND PROJECT_LIBATBUS_PUBLIC_LINK_NAMES "${PROJECT_LIBATBUS_LIB_LINK}-protocol") 89 | add_dependencies("${PROJECT_LIBATBUS_LIB_LINK}-protocol" "atbus-generate-protocol") 90 | 91 | if(BUILD_SHARED_LIBS OR ATFRAMEWORK_USE_DYNAMIC_LIBRARY) 92 | add_library(${PROJECT_LIBATBUS_LIB_LINK} SHARED ${PROJECT_LIB_SRC_LIST}) 93 | set_target_properties( 94 | ${PROJECT_LIBATBUS_LIB_LINK} 95 | PROPERTIES C_VISIBILITY_PRESET "hidden" 96 | CXX_VISIBILITY_PRESET "hidden" 97 | VERSION ${LIBATBUS_VERSION} 98 | SOVERSION ${LIBATBUS_VERSION} 99 | INTERFACE_COMPILE_DEFINITIONS ATBUS_MACRO_API_DLL=1) 100 | target_compile_definitions(${PROJECT_LIBATBUS_LIB_LINK} PRIVATE ATBUS_MACRO_API_NATIVE=1 ATBUS_MACRO_API_DLL=1) 101 | else() 102 | add_library(${PROJECT_LIBATBUS_LIB_LINK} STATIC ${PROJECT_LIB_SRC_LIST}) 103 | set_target_properties( 104 | ${PROJECT_LIBATBUS_LIB_LINK} 105 | PROPERTIES C_VISIBILITY_PRESET "hidden" 106 | CXX_VISIBILITY_PRESET "hidden" 107 | VERSION ${LIBATBUS_VERSION}) 108 | target_compile_definitions(${PROJECT_LIBATBUS_LIB_LINK} PRIVATE ATBUS_MACRO_API_NATIVE=1) 109 | endif() 110 | 111 | add_dependencies(${PROJECT_LIBATBUS_LIB_LINK} "atbus-generate-protocol") 112 | 113 | target_include_directories( 114 | ${PROJECT_LIBATBUS_LIB_LINK} 115 | PUBLIC "$" 116 | "$" "$" 117 | PRIVATE "$") 118 | 119 | target_compile_definitions(${PROJECT_LIBATBUS_LIB_LINK} PRIVATE ATBUS_MACRO_BUILD_API=1) 120 | target_compile_options(${PROJECT_LIBATBUS_LIB_LINK} PRIVATE ${PROJECT_LIBATBUS_PRIVATE_COMPILE_OPTIONS}) 121 | target_link_libraries(${PROJECT_LIBATBUS_LIB_LINK} PUBLIC ${PROJECT_LIBATBUS_PUBLIC_LINK_NAMES}) 122 | 123 | set_property(TARGET ${PROJECT_LIBATBUS_LIB_LINK} PROPERTY FOLDER "atframework/atbus") 124 | set_property(TARGET "${PROJECT_LIBATBUS_LIB_LINK}-protocol" PROPERTY FOLDER "atframework/atbus") 125 | 126 | set(PROJECT_LIBATBUS_EXPORT_TARGETS "${PROJECT_LIBATBUS_LIB_LINK}" "${PROJECT_LIBATBUS_LIB_LINK}-protocol") 127 | add_library("atframework::${PROJECT_LIBATBUS_LIB_LINK}-protocol" ALIAS "${PROJECT_LIBATBUS_LIB_LINK}-protocol") 128 | add_library("atframework::${PROJECT_LIBATBUS_LIB_LINK}" ALIAS "${PROJECT_LIBATBUS_LIB_LINK}") 129 | 130 | install( 131 | TARGETS ${PROJECT_LIBATBUS_EXPORT_TARGETS} 132 | EXPORT ${PROJECT_LIBATBUS_EXPORT_NAME} 133 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 134 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 135 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) 136 | 137 | install( 138 | DIRECTORY ${PROJECT_LIBATBUS_ROOT_INC_DIR} 139 | DESTINATION . 140 | FILES_MATCHING 141 | REGEX ".+\\.h(pp)?$" 142 | PATTERN ".svn" EXCLUDE 143 | PATTERN ".git" EXCLUDE) 144 | 145 | install(FILES "${PROJECT_LIBATBUS_GENERATED_DIR}/include/detail/libatbus_config.h" 146 | DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/detail/") 147 | 148 | install(FILES "${PROJECT_LIBATBUS_GENERATED_DIR}/include/libatbus_protocol.pb.h" 149 | DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") 150 | -------------------------------------------------------------------------------- /src/channel_utility.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @brief 所有channel文件的模式均为 c + channel
3 | * 使用c的模式是为了简单、结构清晰并且避免异常
4 | * 附带c++的部分是为了避免命名空间污染并且c++的跨平台适配更加简单 5 | */ 6 | 7 | #include 8 | 9 | #include "common/string_oprs.h" 10 | 11 | #include "detail/libatbus_channel_export.h" 12 | 13 | namespace atbus { 14 | namespace channel { 15 | ATBUS_MACRO_API bool make_address(const char *in, channel_address_t &addr) { 16 | addr.address = in; 17 | 18 | // 获取协议 19 | size_t scheme_end = addr.address.find_first_of("://"); 20 | if (addr.address.npos == scheme_end) { 21 | return false; 22 | } 23 | 24 | addr.scheme = addr.address.substr(0, scheme_end); 25 | size_t port_end = addr.address.find_last_of(":"); 26 | addr.port = 0; 27 | if (addr.address.npos != port_end && port_end >= scheme_end + 3) { 28 | UTIL_STRFUNC_SSCANF(addr.address.c_str() + port_end + 1, "%d", &addr.port); 29 | } 30 | 31 | // 截取域名 32 | addr.host = 33 | addr.address.substr(scheme_end + 3, (port_end == addr.address.npos) ? port_end : port_end - scheme_end - 3); 34 | 35 | return true; 36 | } 37 | 38 | ATBUS_MACRO_API void make_address(const char *scheme, const char *host, int port, channel_address_t &addr) { 39 | addr.scheme = scheme; 40 | addr.host = host; 41 | addr.port = port; 42 | addr.address.reserve(addr.scheme.size() + addr.host.size() + 4 + 8); 43 | addr.address = addr.scheme + "://" + addr.host; 44 | 45 | if (port > 0) { 46 | char port_str[16] = {0}; 47 | UTIL_STRFUNC_SNPRINTF(port_str, sizeof(port_str), "%d", port); 48 | addr.address += ":"; 49 | addr.address += &port_str[0]; 50 | } 51 | } 52 | 53 | ATBUS_MACRO_API bool is_duplex_address(const char *in) { 54 | if (nullptr == in || !(*in)) { 55 | return false; 56 | } 57 | 58 | return false == is_simplex_address(in); 59 | } 60 | 61 | ATBUS_MACRO_API bool is_simplex_address(const char *in) { 62 | if (nullptr == in || !(*in)) { 63 | return false; 64 | } 65 | 66 | if (0 == UTIL_STRFUNC_STRNCASE_CMP("mem:", in, 4)) { 67 | return true; 68 | } 69 | 70 | if (0 == UTIL_STRFUNC_STRNCASE_CMP("shm:", in, 4)) { 71 | return true; 72 | } 73 | 74 | return false; 75 | } 76 | 77 | ATBUS_MACRO_API bool is_local_host_address(const char *in) { 78 | if (nullptr == in || !(*in)) { 79 | return false; 80 | } 81 | 82 | if (is_local_process_address(in)) { 83 | return true; 84 | } 85 | 86 | if (0 == UTIL_STRFUNC_STRNCASE_CMP("shm:", in, 4)) { 87 | return true; 88 | } 89 | 90 | if (0 == UTIL_STRFUNC_STRNCASE_CMP("unix:", in, 5)) { 91 | return true; 92 | } 93 | 94 | return false; 95 | } 96 | 97 | ATBUS_MACRO_API bool is_local_process_address(const char *in) { 98 | if (nullptr == in || !(*in)) { 99 | return false; 100 | } 101 | 102 | if (0 == UTIL_STRFUNC_STRNCASE_CMP("mem:", in, 4)) { 103 | return true; 104 | } 105 | 106 | return false; 107 | } 108 | } // namespace channel 109 | } // namespace atbus 110 | -------------------------------------------------------------------------------- /src/libatbus.macro.cmake: -------------------------------------------------------------------------------- 1 | # =========== libatbus/src =========== 2 | set(PROJECT_LIBATBUS_ROOT_SRC_DIR ${CMAKE_CURRENT_LIST_DIR}) 3 | 4 | set(PROJECT_LIBATBUS_LIB_LINK "atbus") 5 | set(PROJECT_LIBATBUS_EXPORT_NAME ${PROJECT_NAME}-target) 6 | 7 | # include("${PROJECT_LIBATBUS_ROOT_SRC_DIR}/XXX.cmake") 8 | 9 | add_custom_command( 10 | OUTPUT "${PROJECT_LIBATBUS_GENERATED_DIR}/include/libatbus_protocol.pb.h" 11 | "${PROJECT_LIBATBUS_GENERATED_DIR}/src/libatbus_protocol.pb.cc" 12 | "${PROJECT_LIBATBUS_GENERATED_DIR}/libatbus_protocol.pb" 13 | COMMAND 14 | ${ATFRAMEWORK_CMAKE_TOOLSET_THIRD_PARTY_PROTOBUF_BIN_PROTOC} --proto_path ${PROJECT_LIBATBUS_ROOT_INC_DIR} -o 15 | "${PROJECT_LIBATBUS_GENERATED_DIR}/temp/libatbus_protocol.pb" 16 | "--cpp_out=dllexport_decl=ATBUS_MACRO_PROTOCOL_API:${PROJECT_LIBATBUS_GENERATED_DIR}/temp/" 17 | "${PROJECT_LIBATBUS_ROOT_INC_DIR}/libatbus_protocol.proto" 18 | COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${PROJECT_LIBATBUS_GENERATED_DIR}/temp/libatbus_protocol.pb.cc" 19 | "${PROJECT_LIBATBUS_GENERATED_DIR}/src/libatbus_protocol.pb.cc" 20 | COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${PROJECT_LIBATBUS_GENERATED_DIR}/temp/libatbus_protocol.pb.h" 21 | "${PROJECT_LIBATBUS_GENERATED_DIR}/include/libatbus_protocol.pb.h" 22 | COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${PROJECT_LIBATBUS_GENERATED_DIR}/temp/libatbus_protocol.pb" 23 | "${PROJECT_LIBATBUS_GENERATED_DIR}/libatbus_protocol.pb" 24 | DEPENDS "${PROJECT_LIBATBUS_ROOT_INC_DIR}/libatbus_protocol.proto" 25 | "${ATFRAMEWORK_CMAKE_TOOLSET_THIRD_PARTY_PROTOBUF_BIN_PROTOC}" 26 | COMMENT 27 | "Generate ${PROJECT_LIBATBUS_GENERATED_DIR}/include/libatbus_protocol.pb.h, ${PROJECT_LIBATBUS_GENERATED_DIR}/src/libatbus_protocol.pb.cc and ${PROJECT_LIBATBUS_GENERATED_DIR}/libatbus_protocol.pb" 28 | ) 29 | 30 | add_custom_target("atbus-generate-protocol" SOURCES "${PROJECT_LIBATBUS_GENERATED_DIR}/include/libatbus_protocol.pb.h" 31 | "${PROJECT_LIBATBUS_GENERATED_DIR}/src/libatbus_protocol.pb.cc") 32 | 33 | set_property(TARGET "atbus-generate-protocol" PROPERTY FOLDER "atframework/atbus") 34 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | echowithcolor(COLOR GREEN "-- Configure Unit Test ${CMAKE_CURRENT_LIST_DIR}") 2 | 3 | include("${PROJECT_TEST_BAS_DIR}/test.build_bin.cmake") 4 | 5 | file( 6 | GLOB_RECURSE 7 | PROJECT_TEST_SRC_LIST 8 | ${PROJECT_TEST_SRC_DIR}/app/*.cpp 9 | ${PROJECT_TEST_SRC_DIR}/frame/*.h 10 | ${PROJECT_TEST_SRC_DIR}/frame/*.cpp 11 | ${CMAKE_CURRENT_LIST_DIR}/*.hpp 12 | ${CMAKE_CURRENT_LIST_DIR}/*.h 13 | ${CMAKE_CURRENT_LIST_DIR}/*.c 14 | ${CMAKE_CURRENT_LIST_DIR}/*.cpp 15 | ${CMAKE_CURRENT_LIST_DIR}/*.cc 16 | ${CMAKE_CURRENT_LIST_DIR}/*.cxx) 17 | source_group_by_dir(PROJECT_TEST_SRC_LIST) 18 | 19 | # ============ test - coroutine test frame ============ 20 | set(CMAKE_BUILD_RPATH "${CMAKE_INSTALL_RPATH}") 21 | if(NOT (WIN32 AND BUILD_SHARED_LIBS)) 22 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/test") 23 | endif() 24 | 25 | atframe_add_test_executable(atbus_unit_test ${PROJECT_TEST_SRC_LIST}) 26 | 27 | target_compile_options(atbus_unit_test PRIVATE ${PROJECT_LIBATBUS_PRIVATE_COMPILE_OPTIONS}) 28 | target_link_libraries(atbus_unit_test atframework::atbus) 29 | 30 | target_include_directories(atbus_unit_test PRIVATE "$") 31 | 32 | add_test(NAME "libatbus.unit_test" COMMAND "$") 33 | set_tests_properties("libatbus.unit_test" PROPERTIES LABELS "libatbus;libatbus.unit_test") 34 | -------------------------------------------------------------------------------- /test/case/atbus_node_nodesync_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "common/string_oprs.h" 8 | 9 | #ifdef max 10 | # undef max 11 | #endif 12 | 13 | #ifdef min 14 | # undef min 15 | #endif 16 | 17 | #include 18 | #include 19 | 20 | #include "frame/test_macros.h" 21 | 22 | #include 23 | 24 | #if 0 25 | static void node_nodesync_test_on_debug(const char* file_path, size_t line, const atbus::node& n, const atbus::endpoint* ep, const atbus::connection* conn, const char* fmt, ...) { 26 | size_t offset = 0; 27 | for (size_t i = 0; file_path[i]; ++i) { 28 | if ('/' == file_path[i] || '\\' == file_path[i]) { 29 | offset = i + 1; 30 | } 31 | } 32 | file_path += offset; 33 | 34 | std::streamsize w = std::cout.width(); 35 | CASE_MSG_INFO() << "[Log Debug][" << std::setw(24) << file_path << ":" << std::setw(4) << line << "] node=0x" << 36 | std::setfill('0')<< std::hex<< std::setw(8)<< n.get_id() << 37 | ", ep=0x" << std::setw(8)<< (nullptr == ep ? 0 : ep->get_id()) << 38 | ", c=" << conn<< std::setfill(' ')<< std::setw(w)<< std::dec<< 39 | "\t"; 40 | 41 | va_list ap; 42 | va_start(ap, fmt); 43 | 44 | vprintf(fmt, ap); 45 | 46 | va_end(ap); 47 | 48 | puts(""); 49 | } 50 | 51 | struct node_nodesync_test_recv_msg_record_t { 52 | const atbus::node* n; 53 | const atbus::endpoint* ep; 54 | const atbus::connection* conn; 55 | std::string data; 56 | int status; 57 | int count; 58 | 59 | node_nodesync_test_recv_msg_record_t(): n(nullptr), ep(nullptr), conn(nullptr), status(0), count(0) {} 60 | }; 61 | 62 | static node_nodesync_test_recv_msg_record_t recv_msg_history; 63 | 64 | static int node_nodesync_test_recv_msg_test_record_fn(const atbus::node& n, const atbus::endpoint& ep, const atbus::connection& conn, 65 | int status, const void* buffer, size_t len) { 66 | recv_msg_history.n = &n; 67 | recv_msg_history.ep = &ep; 68 | recv_msg_history.conn = &conn; 69 | recv_msg_history.status = status; 70 | ++recv_msg_history.count; 71 | 72 | if (nullptr != buffer && len > 0) { 73 | recv_msg_history.data.assign(reinterpret_cast(buffer), len); 74 | } else { 75 | recv_msg_history.data.clear(); 76 | } 77 | 78 | return 0; 79 | } 80 | 81 | // TODO 全量表第一次拉取测试 82 | // TODO 全量表通知给父节点和子节点测试 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /test/case/atbus_node_relationship_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "common/string_oprs.h" 8 | 9 | #ifdef max 10 | # undef max 11 | #endif 12 | 13 | #ifdef min 14 | # undef min 15 | #endif 16 | 17 | #include 18 | #include 19 | 20 | #include "frame/test_macros.h" 21 | 22 | #if 0 // Unit Test for flatbuffers implements 23 | CASE_TEST(atbus_node_rela, basic_test) { 24 | std::vector packed_buffer; 25 | char test_buffer[] = "hello world!"; 26 | 27 | { 28 | ::flatbuffers::FlatBufferBuilder fbb; 29 | 30 | uint64_t self_id = 0x12345678; 31 | uint32_t flags = 0; 32 | flags |= atbus::protocol::ATBUS_FORWARD_DATA_FLAG_TYPE_REQUIRE_RSP; 33 | 34 | fbb.Finish(::atbus::protocol::Createmsg(fbb, 35 | ::atbus::protocol::Createmsg_head(fbb, ::atbus::protocol::ATBUS_PROTOCOL_CONST_ATBUS_PROTOCOL_VERSION, 36 | 123, 0, 9876543210, self_id), 37 | ::atbus::protocol::msg_body_data_transform_req, 38 | ::atbus::protocol::Createforward_data(fbb, 0x123456789, 0x987654321, fbb.CreateVector(&self_id, 1), 39 | fbb.CreateVector(reinterpret_cast(test_buffer), sizeof(test_buffer)), 40 | flags) 41 | .Union()) 42 | 43 | ); 44 | packed_buffer.assign(reinterpret_cast(fbb.GetBufferPointer()), 45 | reinterpret_cast(fbb.GetBufferPointer()) + fbb.GetSize()); 46 | std::stringstream so; 47 | atfw::util::string::serialization(packed_buffer.data(), packed_buffer.size(), so); 48 | CASE_MSG_INFO() << "flatbuffers encoded(size=" << packed_buffer.size() << "): " << so.str() << std::endl; 49 | } 50 | 51 | { 52 | ::flatbuffers::Verifier msg_verify(reinterpret_cast(&packed_buffer[0]), packed_buffer.size()); 53 | CASE_EXPECT_TRUE(::atbus::protocol::VerifymsgBuffer(msg_verify)); 54 | const ::atbus::protocol::msg* m = ::atbus::protocol::Getmsg(&packed_buffer[0]); 55 | 56 | CASE_EXPECT_EQ(::atbus::protocol::msg_body_data_transform_req, m->body_type()); 57 | CASE_EXPECT_EQ(123, m->head()->type()); 58 | CASE_EXPECT_EQ(0, m->head()->ret()); 59 | CASE_EXPECT_EQ(9876543210, m->head()->sequence()); 60 | CASE_EXPECT_EQ(0x12345678, m->head()->src_bus_id()); 61 | 62 | CASE_EXPECT_EQ(0x123456789, m->body_as_data_transform_req()->from()); 63 | CASE_EXPECT_EQ(0x987654321, m->body_as_data_transform_req()->to()); 64 | CASE_EXPECT_EQ(0x12345678, m->body_as_data_transform_req()->router()->Get(0)); 65 | CASE_EXPECT_EQ( 66 | 0, UTIL_STRFUNC_STRNCMP(test_buffer, reinterpret_cast(m->body_as_data_transform_req()->content()->data()), sizeof(test_buffer))); 67 | } 68 | } 69 | #endif 70 | 71 | CASE_TEST(atbus_node_rela, copy_conf) { 72 | atbus::node::conf_t c1; 73 | atbus::node::conf_t c2(c1); 74 | 75 | atbus::node::default_conf((atbus::node::conf_t*)nullptr); 76 | atbus::node::default_conf((atbus::node::start_conf_t*)nullptr); 77 | } 78 | 79 | CASE_TEST(atbus_node_rela, child_endpoint_opr) { 80 | atbus::node::conf_t conf; 81 | atbus::node::default_conf(&conf); 82 | conf.subnets.push_back(atbus::endpoint_subnet_conf(0, 16)); 83 | conf.subnets.push_back(atbus::endpoint_subnet_conf(0x22345679, 16)); 84 | 85 | atbus::node::ptr_t node = atbus::node::create(); 86 | node->init(0x12345678, &conf); 87 | 88 | std::vector ep_subnets; 89 | ep_subnets.push_back(atbus::endpoint_subnet_conf(0, 8)); 90 | atbus::endpoint::ptr_t ep = 91 | atbus::endpoint::create(node.get(), 0x12345679, ep_subnets, node->get_pid(), node->get_hostname()); 92 | // 插入到末尾 93 | CASE_EXPECT_EQ(0, node->add_endpoint(ep)); 94 | CASE_EXPECT_EQ(1, node->get_routes().size()); 95 | 96 | // 插入到中间 97 | ep = atbus::endpoint::create(node.get(), 0x12345589, ep_subnets, node->get_pid(), node->get_hostname()); 98 | CASE_EXPECT_EQ(0, node->add_endpoint(ep)); 99 | CASE_EXPECT_EQ(2, node->get_routes().size()); 100 | 101 | // 新端点子域冲突-父子关系 102 | ep_subnets.clear(); 103 | ep_subnets.push_back(atbus::endpoint_subnet_conf(0, 4)); 104 | ep = atbus::endpoint::create(node.get(), 0x12345680, ep_subnets, node->get_pid(), node->get_hostname()); 105 | CASE_EXPECT_EQ(EN_ATBUS_ERR_PARAMS, node->add_endpoint(atbus::endpoint::ptr_t())); 106 | CASE_EXPECT_EQ(EN_ATBUS_ERR_ATNODE_MASK_CONFLICT, node->add_endpoint(ep)); 107 | 108 | // 新端点子域冲突-子父关系 109 | ep_subnets.clear(); 110 | ep_subnets.push_back(atbus::endpoint_subnet_conf(0, 12)); 111 | ep = atbus::endpoint::create(node.get(), 0x12345780, ep_subnets, node->get_pid(), node->get_hostname()); 112 | CASE_EXPECT_EQ(EN_ATBUS_ERR_ATNODE_MASK_CONFLICT, node->add_endpoint(ep)); 113 | ep = atbus::endpoint::create(node.get(), 0x12345480, ep_subnets, node->get_pid(), node->get_hostname()); 114 | CASE_EXPECT_EQ(EN_ATBUS_ERR_ATNODE_MASK_CONFLICT, node->add_endpoint(ep)); 115 | 116 | // 新端点子域冲突-ID不同子域相同 117 | ep_subnets.clear(); 118 | ep_subnets.push_back(atbus::endpoint_subnet_conf(0, 8)); 119 | ep = atbus::endpoint::create(node.get(), 0x12345680, ep_subnets, node->get_pid(), node->get_hostname()); 120 | CASE_EXPECT_EQ(EN_ATBUS_ERR_ATNODE_MASK_CONFLICT, node->add_endpoint(ep)); 121 | 122 | // 跨域添加节点 - 成功 123 | ep = atbus::endpoint::create(node.get(), 0x22345679, ep_subnets, node->get_pid(), node->get_hostname()); 124 | CASE_EXPECT_EQ(0, node->add_endpoint(ep)); 125 | 126 | // 跨域添加节点 - 范围不完全覆盖 127 | ep_subnets.push_back(atbus::endpoint_subnet_conf(0x32345680, 8)); 128 | ep = atbus::endpoint::create(node.get(), 0x22345680, ep_subnets, node->get_pid(), node->get_hostname()); 129 | CASE_EXPECT_EQ(EN_ATBUS_ERR_ATNODE_MASK_CONFLICT, node->add_endpoint(ep)); 130 | 131 | CASE_EXPECT_EQ(3, node->get_routes().size()); 132 | 133 | // 移除失败-找不到 134 | CASE_EXPECT_EQ(EN_ATBUS_ERR_ATNODE_NOT_FOUND, node->remove_endpoint(0x12345680)); 135 | // 移除成功 136 | CASE_EXPECT_EQ(EN_ATBUS_ERR_SUCCESS, node->remove_endpoint(0x12345589)); 137 | CASE_EXPECT_EQ(EN_ATBUS_ERR_SUCCESS, node->remove_endpoint(0x22345679)); 138 | } 139 | -------------------------------------------------------------------------------- /test/case/atbus_node_setup_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | #include "atbus_test_utils.h" 20 | #include "frame/test_macros.h" 21 | 22 | #include 23 | 24 | #ifdef CRYPTO_CIPHER_ENABLED 25 | CASE_TEST_EVENT_ON_START(unit_test_event_on_start_setup_openssl) { 26 | atfw::util::crypto::cipher::init_global_algorithm(); 27 | } 28 | 29 | CASE_TEST_EVENT_ON_EXIT(unit_test_event_on_exit_close_openssl) { 30 | atfw::util::crypto::cipher::cleanup_global_algorithm(); 31 | } 32 | #endif 33 | 34 | CASE_TEST_EVENT_ON_START(unit_test_event_on_start_ignore_sigpipe) { 35 | #ifndef WIN32 36 | signal(SIGPIPE, SIG_IGN); // close stdin, stdout or stderr 37 | signal(SIGTSTP, SIG_IGN); // close tty 38 | signal(SIGTTIN, SIG_IGN); // tty input 39 | signal(SIGTTOU, SIG_IGN); // tty output 40 | #endif 41 | } 42 | 43 | CASE_TEST_EVENT_ON_EXIT(unit_test_event_on_exit_shutdown_protobuf) { 44 | ATBUS_MACRO_PROTOBUF_NAMESPACE_ID::ShutdownProtobufLibrary(); 45 | } 46 | 47 | CASE_TEST_EVENT_ON_EXIT(unit_test_event_on_exit_close_libuv) { 48 | int finish_event = 2048; 49 | while (0 != uv_loop_alive(uv_default_loop()) && finish_event-- > 0) { 50 | uv_run(uv_default_loop(), UV_RUN_NOWAIT); 51 | } 52 | uv_loop_close(uv_default_loop()); 53 | } 54 | 55 | #ifndef _WIN32 56 | static int node_setup_test_on_error(const atbus::node &n, const atbus::endpoint *ep, const atbus::connection *conn, 57 | int status, int errcode) { 58 | if ((0 == status && 0 == errcode) || UV_EOF == errcode || UV_ECONNRESET == errcode) { 59 | return 0; 60 | } 61 | 62 | std::streamsize w = std::cout.width(); 63 | CASE_MSG_INFO() << "[Log Error] node=0x" << std::setfill('0') << std::hex << std::setw(8) << n.get_id() << ", ep=0x" 64 | << std::setw(8) << (nullptr == ep ? 0 : ep->get_id()) << ", c=" << conn << std::setfill(' ') 65 | << std::setw(static_cast(w)) << std::dec << "=> status: " << status << ", errcode: " << errcode 66 | << std::endl; 67 | return 0; 68 | } 69 | 70 | static int node_setup_test_on_info_log(const atbus::node &n, const atbus::endpoint *ep, const atbus::connection *conn, 71 | const char *msg) { 72 | std::streamsize w = std::cout.width(); 73 | CASE_MSG_INFO() << "[Log Info] node=0x" << std::setfill('0') << std::hex << std::setw(8) << n.get_id() << ", ep=0x" 74 | << std::setw(8) << (nullptr == ep ? 0 : ep->get_id()) << ", c=" << conn << std::setfill(' ') 75 | << std::setw(static_cast(w)) << std::dec << "=> message: " << (nullptr == msg ? "" : msg) 76 | << std::endl; 77 | 78 | return 0; 79 | } 80 | 81 | // 主动reset流程测试 82 | // 正常首发数据测试 83 | CASE_TEST(atbus_node_setup, override_listen_path) { 84 | atbus::node::conf_t conf; 85 | atbus::node::default_conf(&conf); 86 | conf.overwrite_listen_path = false; 87 | 88 | uv_loop_t ev_loop; 89 | uv_loop_init(&ev_loop); 90 | 91 | conf.ev_loop = &ev_loop; 92 | 93 | { 94 | atbus::node::ptr_t node1 = atbus::node::create(); 95 | atbus::node::ptr_t node2 = atbus::node::create(); 96 | atbus::node::ptr_t node3 = atbus::node::create(); 97 | node1->set_on_error_handle(node_setup_test_on_error); 98 | node2->set_on_error_handle(node_setup_test_on_error); 99 | node3->set_on_error_handle(node_setup_test_on_error); 100 | node1->set_on_info_log_handle(node_setup_test_on_info_log); 101 | node2->set_on_info_log_handle(node_setup_test_on_info_log); 102 | node3->set_on_info_log_handle(node_setup_test_on_info_log); 103 | 104 | CASE_EXPECT_EQ(EN_ATBUS_ERR_NOT_INITED, node1->start()); 105 | CASE_EXPECT_EQ(EN_ATBUS_ERR_NOT_INITED, node2->start()); 106 | CASE_EXPECT_EQ(EN_ATBUS_ERR_NOT_INITED, node3->start()); 107 | 108 | node1->init(0x12345678, &conf); 109 | node2->init(0x12356789, &conf); 110 | conf.overwrite_listen_path = true; 111 | node3->init(0x12367890, &conf); 112 | 113 | CASE_EXPECT_EQ(EN_ATBUS_ERR_SUCCESS, node1->listen("unix:///tmp/atbus-unit-test-overwrite-unix.sock")); 114 | CASE_EXPECT_EQ(EN_ATBUS_ERR_PIPE_LOCK_PATH_FAILED, 115 | node2->listen("unix:///tmp/atbus-unit-test-overwrite-unix.sock")); 116 | CASE_EXPECT_EQ(EN_ATBUS_ERR_SUCCESS, node3->listen("unix:///tmp/atbus-unit-test-overwrite-unix.sock")); 117 | } 118 | 119 | unit_test_setup_exit(&ev_loop); 120 | } 121 | #endif 122 | -------------------------------------------------------------------------------- /test/case/atbus_test_utils.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "atbus_test_utils.h" 3 | #include "frame/test_macros.h" 4 | 5 | void unit_test_tick_handle(uv_timer_t *handle) { uv_stop(handle->loop); } 6 | 7 | void unit_test_timeout_handle(uv_timer_t *handle) { 8 | uv_stop(handle->loop); 9 | 10 | unit_test_libuv_wait_manager *mgr = reinterpret_cast(handle->data); 11 | if (nullptr == mgr || mgr->print_error_) { 12 | CASE_MSG_ERROR() << CASE_MSG_FCOLOR(RED) << "wait timeout." << std::endl; 13 | } 14 | 15 | if (nullptr != mgr) { 16 | mgr->is_timeout_ = true; 17 | } 18 | } 19 | 20 | void unit_test_setup_exit(uv_loop_t *ev, uint64_t timeout_ms) { 21 | size_t left_tick = timeout_ms / 8; 22 | while (left_tick > 0 && UV_EBUSY == uv_loop_close(ev)) { 23 | // loop 8 times 24 | for (int i = 0; i < 8; ++i) { 25 | uv_run(ev, UV_RUN_NOWAIT); 26 | } 27 | CASE_THREAD_SLEEP_MS(8); 28 | 29 | --left_tick; 30 | } 31 | 32 | CASE_EXPECT_NE(left_tick, 0); 33 | } 34 | 35 | static void unit_test_timer_close_handle(uv_handle_t *handle) { 36 | handle->data = nullptr; 37 | uv_stop(handle->loop); 38 | } 39 | 40 | unit_test_libuv_wait_manager::unit_test_libuv_wait_manager(uv_loop_t *ev, uint64_t timeout_ms, uint64_t tick_ms, 41 | bool print_error) 42 | : tick_enabled_(false), print_error_(print_error), is_timeout_(false) { 43 | uv_timer_init(ev, &timeout_timer_); 44 | 45 | if (tick_ms > 0) { 46 | if (0 == uv_timer_init(ev, &tick_timer_)) { 47 | tick_enabled_ = true; 48 | } 49 | } 50 | tick_timer_.data = this; 51 | timeout_timer_.data = this; 52 | 53 | if (0 != uv_timer_start(&timeout_timer_, unit_test_timeout_handle, timeout_ms, 0)) { 54 | timeout_timer_.data = nullptr; 55 | } 56 | 57 | if (tick_enabled_) { 58 | if (0 != uv_timer_start(&tick_timer_, unit_test_tick_handle, tick_ms, tick_ms)) { 59 | timeout_timer_.data = nullptr; 60 | tick_enabled_ = false; 61 | } 62 | } 63 | } 64 | 65 | unit_test_libuv_wait_manager::~unit_test_libuv_wait_manager() { 66 | uv_loop_t *ev = timeout_timer_.loop; 67 | uv_timer_stop(&timeout_timer_); 68 | 69 | uv_close(reinterpret_cast(&timeout_timer_), unit_test_timer_close_handle); 70 | 71 | if (tick_enabled_) { 72 | uv_timer_stop(&tick_timer_); 73 | uv_close(reinterpret_cast(&tick_timer_), unit_test_timer_close_handle); 74 | } else { 75 | tick_timer_.data = nullptr; 76 | } 77 | 78 | while (nullptr != timeout_timer_.data || nullptr != tick_timer_.data) { 79 | uv_run(ev, UV_RUN_DEFAULT); 80 | } 81 | } 82 | 83 | void unit_test_libuv_wait_manager::run(uv_loop_t *ev) { uv_run(ev, UV_RUN_ONCE); } -------------------------------------------------------------------------------- /test/case/atbus_test_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UNITTEST_LIBATBUS_TEST_UTILS_H_ 2 | #define UNITTEST_LIBATBUS_TEST_UTILS_H_ 3 | 4 | #pragma once 5 | 6 | #include "uv.h" 7 | 8 | void unit_test_tick_handle(uv_timer_t *handle); 9 | void unit_test_timeout_handle(uv_timer_t *handle); 10 | void unit_test_setup_exit(uv_loop_t *ev, uint64_t timeout_ms = 30000); 11 | 12 | struct unit_test_libuv_wait_manager { 13 | unit_test_libuv_wait_manager(uv_loop_t *ev, uint64_t timeout_ms, uint64_t tick_ms, bool print_error); 14 | ~unit_test_libuv_wait_manager(); 15 | 16 | void run(uv_loop_t *ev); 17 | 18 | uv_timer_t timeout_timer_; 19 | uv_timer_t tick_timer_; 20 | bool tick_enabled_; 21 | bool print_error_; 22 | bool is_timeout_; 23 | }; 24 | 25 | #define UNITTEST_WAIT_UNTIL(ev, conndition, timeout_ms, tick_ms) \ 26 | for (unit_test_libuv_wait_manager libuv_wait_mgr(ev, timeout_ms, tick_ms, true); \ 27 | !libuv_wait_mgr.is_timeout_ && !(conndition); libuv_wait_mgr.run(ev)) \ 28 | if (!libuv_wait_mgr.is_timeout_) 29 | 30 | #define UNITTEST_WAIT_IF(ev, conndition, timeout_ms, tick_ms) \ 31 | for (unit_test_libuv_wait_manager libuv_wait_mgr(ev, timeout_ms, tick_ms, true); \ 32 | !libuv_wait_mgr.is_timeout_ && (conndition); libuv_wait_mgr.run(ev)) \ 33 | if (!libuv_wait_mgr.is_timeout_) 34 | 35 | #define UNITTEST_WAIT_MS(ev, timeout_ms, tick_ms) \ 36 | for (unit_test_libuv_wait_manager libuv_wait_mgr(ev, timeout_ms, tick_ms, false); !libuv_wait_mgr.is_timeout_; \ 37 | libuv_wait_mgr.run(ev)) \ 38 | if (!libuv_wait_mgr.is_timeout_) 39 | 40 | #endif -------------------------------------------------------------------------------- /test/case/channel_shm_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "config/compiler_features.h" 14 | 15 | #include 16 | #include "detail/libatbus_channel_export.h" 17 | #include "lock/atomic_int_type.h" 18 | 19 | #include "frame/test_macros.h" 20 | 21 | #if defined(ATBUS_CHANNEL_SHM) 22 | 23 | CASE_TEST(channel, shm_attach_with_invalid_magic) { 24 | using namespace atbus::channel; 25 | const char *shm_path = "/atbus-channel-test"; 26 | const size_t buffer_len = 2 * 1024 * 1024; // 2MB 27 | 28 | shm_channel *channel = nullptr; 29 | # ifdef _WIN32 30 | // Win32 may need administrator permission to use shared memory 31 | if (0 != shm_init(shm_path, buffer_len, &channel, nullptr)) { 32 | return; 33 | } 34 | if (nullptr == channel) { 35 | return; 36 | } 37 | # else 38 | CASE_EXPECT_EQ(0, shm_init(shm_path, buffer_len, &channel, nullptr)); 39 | CASE_EXPECT_NE(nullptr, channel); 40 | # endif 41 | 42 | memset(reinterpret_cast(channel) + 4, 0, 4); 43 | CASE_EXPECT_EQ(EN_ATBUS_ERR_CHANNEL_BUFFER_INVALID, shm_attach(shm_path, buffer_len, &channel, nullptr)); 44 | } 45 | 46 | CASE_TEST(channel, shm_attach_with_invalid_version) { 47 | using namespace atbus::channel; 48 | const char *shm_path = "/atbus-channel-test"; 49 | const size_t buffer_len = 2 * 1024 * 1024; // 2MB 50 | 51 | shm_channel *channel = nullptr; 52 | # ifdef _WIN32 53 | // Win32 may need administrator permission to use shared memory 54 | if (0 != shm_init(shm_path, buffer_len, &channel, nullptr)) { 55 | return; 56 | } 57 | if (nullptr == channel) { 58 | return; 59 | } 60 | # else 61 | CASE_EXPECT_EQ(0, shm_init(shm_path, buffer_len, &channel, nullptr)); 62 | CASE_EXPECT_NE(nullptr, channel); 63 | # endif 64 | 65 | CASE_EXPECT_EQ(2, shm_info_get_version(channel)); 66 | CASE_EXPECT_EQ(0, shm_info_get_version(nullptr)); 67 | 68 | (*reinterpret_cast(reinterpret_cast(channel) + 16)) = 1; 69 | CASE_EXPECT_EQ(EN_ATBUS_ERR_CHANNEL_UNSUPPORTED_VERSION, shm_attach(shm_path, buffer_len, &channel, nullptr)); 70 | } 71 | 72 | CASE_TEST(channel, shm_attach_with_invalid_align_size) { 73 | using namespace atbus::channel; 74 | const char *shm_path = "/atbus-channel-test"; 75 | const size_t buffer_len = 2 * 1024 * 1024; // 2MB 76 | 77 | shm_channel *channel = nullptr; 78 | # ifdef _WIN32 79 | // Win32 may need administrator permission to use shared memory 80 | if (0 != shm_init(shm_path, buffer_len, &channel, nullptr)) { 81 | return; 82 | } 83 | if (nullptr == channel) { 84 | return; 85 | } 86 | # else 87 | CASE_EXPECT_EQ(0, shm_init(shm_path, buffer_len, &channel, nullptr)); 88 | CASE_EXPECT_NE(nullptr, channel); 89 | # endif 90 | 91 | CASE_EXPECT_EQ(ATBUS_MACRO_DATA_ALIGN_SIZE, shm_info_get_align_size(channel)); 92 | CASE_EXPECT_EQ(0, shm_info_get_align_size(nullptr)); 93 | 94 | (*reinterpret_cast(reinterpret_cast(channel) + 18)) = ATBUS_MACRO_DATA_ALIGN_SIZE / 2; 95 | CASE_EXPECT_EQ(EN_ATBUS_ERR_CHANNEL_ALIGN_SIZE_MISMATCH, shm_attach(shm_path, buffer_len, &channel, nullptr)); 96 | } 97 | 98 | CASE_TEST(channel, shm_attach_with_invalid_host_size) { 99 | using namespace atbus::channel; 100 | const size_t buffer_len = 2 * 1024 * 1024; // 2MB 101 | const char *shm_path = "/atbus-channel-test"; 102 | 103 | shm_channel *channel = nullptr; 104 | # ifdef _WIN32 105 | // Win32 may need administrator permission to use shared memory 106 | if (0 != shm_init(shm_path, buffer_len, &channel, nullptr)) { 107 | return; 108 | } 109 | if (nullptr == channel) { 110 | return; 111 | } 112 | # else 113 | CASE_EXPECT_EQ(0, shm_init(shm_path, buffer_len, &channel, nullptr)); 114 | CASE_EXPECT_NE(nullptr, channel); 115 | # endif 116 | 117 | CASE_EXPECT_EQ(sizeof(size_t), shm_info_get_host_size(channel)); 118 | CASE_EXPECT_EQ(0, shm_info_get_host_size(nullptr)); 119 | 120 | (*reinterpret_cast(reinterpret_cast(channel) + 20)) = 121 | static_cast(sizeof(size_t) / 2); 122 | CASE_EXPECT_EQ(EN_ATBUS_ERR_CHANNEL_ARCH_SIZE_T_MISMATCH, shm_attach(shm_path, buffer_len, &channel, nullptr)); 123 | } 124 | 125 | CASE_TEST(channel, shm_show_channel) { 126 | using namespace atbus::channel; 127 | const char *shm_path = "/atbus-channel-test"; 128 | const size_t buffer_len = 2 * 1024 * 1024; // 2MB 129 | 130 | shm_channel *channel = nullptr; 131 | # ifdef _WIN32 132 | // Win32 may need administrator permission to use shared memory 133 | if (0 != shm_init(shm_path, buffer_len, &channel, nullptr)) { 134 | return; 135 | } 136 | if (nullptr == channel) { 137 | return; 138 | } 139 | # else 140 | CASE_EXPECT_EQ(0, shm_init(shm_path, buffer_len, &channel, nullptr)); 141 | CASE_EXPECT_NE(nullptr, channel); 142 | # endif 143 | shm_show_channel(channel, CASE_MSG_INFO(), true, 8); 144 | } 145 | 146 | CASE_TEST(channel, shm_siso) { 147 | using namespace atbus::channel; 148 | const char *shm_path = "/atbus-channel-test"; 149 | const size_t buffer_len = 2 * 1024 * 1024; // 2MB 150 | 151 | shm_channel *channel = nullptr; 152 | 153 | # ifdef _WIN32 154 | // Win32 may need administrator permission to use shared memory 155 | if (0 != shm_init(shm_path, buffer_len, &channel, nullptr)) { 156 | return; 157 | } 158 | if (nullptr == channel) { 159 | return; 160 | } 161 | # else 162 | CASE_EXPECT_EQ(0, shm_init(shm_path, buffer_len, &channel, nullptr)); 163 | CASE_EXPECT_NE(nullptr, channel); 164 | # endif 165 | // 4KB header 166 | 167 | // 数据初始化 168 | char buf_group1[2][32] = {{0}}; 169 | char buf_group2[2][45] = {{0}}; 170 | char buf_group3[2][133] = {{0}}; 171 | char buf_group4[2][605] = {{0}}; 172 | char buf_group5[2][1024] = {{0}}; 173 | size_t len_group[] = {32, 45, 133, 605, 1024}; 174 | size_t group_num = sizeof(len_group) / sizeof(size_t); 175 | char *buf_group[] = {buf_group1[0], buf_group2[0], buf_group3[0], buf_group4[0], buf_group5[0]}; 176 | char *buf_rgroup[] = {buf_group1[1], buf_group2[1], buf_group3[1], buf_group4[1], buf_group5[1]}; 177 | 178 | { 179 | size_t i = 0; 180 | char j = 1; 181 | 182 | for (; i < group_num; ++i, ++j) 183 | for (size_t k = 0; k < len_group[i]; ++k) buf_group[i][k] = j; 184 | } 185 | 186 | size_t send_sum_len; 187 | size_t try_left = 3; 188 | srand(static_cast(time(nullptr))); 189 | size_t first_break = (size_t)rand() % (512 * 1024); 190 | 191 | while (try_left-- > 0) { 192 | // 单进程写压力 193 | { 194 | size_t sum_len = 0, times = 0; 195 | int res = 0; 196 | size_t i = 0; 197 | clock_t bt = clock(); 198 | while (0 == res) { 199 | if (first_break && 0 == --first_break) { 200 | res = EN_ATBUS_ERR_BUFF_LIMIT; 201 | continue; 202 | } 203 | 204 | res = shm_send(channel, buf_group[i], len_group[i]); 205 | if (!res) { 206 | sum_len += len_group[i]; 207 | ++times; 208 | } 209 | 210 | i = (i + 1) % group_num; 211 | } 212 | clock_t et = clock(); 213 | 214 | CASE_EXPECT_EQ(EN_ATBUS_ERR_BUFF_LIMIT, res); 215 | 216 | CASE_MSG_INFO() << "send " << sum_len << " bytes(" << times << " times) in " 217 | << ((et - bt) / (CLOCKS_PER_SEC / 1000)) << "ms" << std::endl; 218 | send_sum_len = sum_len; 219 | } 220 | 221 | size_t recv_sum_len; 222 | // 单进程读压力 223 | { 224 | size_t sum_len = 0, times = 0; 225 | int res = 0; 226 | size_t i = 0; 227 | clock_t bt = clock(); 228 | while (0 == res) { 229 | size_t len; 230 | res = shm_recv(channel, buf_rgroup[i], len_group[i], &len); 231 | if (0 == res) { 232 | CASE_EXPECT_EQ(len, len_group[i]); 233 | sum_len += len_group[i]; 234 | ++times; 235 | } 236 | 237 | i = (i + 1) % group_num; 238 | } 239 | clock_t et = clock(); 240 | 241 | CASE_EXPECT_EQ(EN_ATBUS_ERR_NO_DATA, res); 242 | CASE_MSG_INFO() << "recv " << sum_len << " bytes(" << times << " times) in " 243 | << ((et - bt) / (CLOCKS_PER_SEC / 1000)) << "ms" << std::endl; 244 | recv_sum_len = sum_len; 245 | } 246 | 247 | // 简单数据校验 248 | { 249 | for (size_t i = 0; i < group_num; ++i) { 250 | CASE_EXPECT_EQ(0, memcmp(buf_group[i], buf_rgroup[i], len_group[i])); 251 | } 252 | } 253 | 254 | CASE_EXPECT_EQ(recv_sum_len, send_sum_len); 255 | } 256 | } 257 | 258 | #endif 259 | -------------------------------------------------------------------------------- /third_party/Repository.cmake: -------------------------------------------------------------------------------- 1 | project_third_party_include_port("compression/import.cmake") 2 | project_third_party_include_port("libuv/libuv.cmake") 3 | project_third_party_include_port("fmtlib/fmtlib.cmake") 4 | project_third_party_include_port("abseil-cpp/abseil-cpp.cmake") 5 | project_third_party_include_port("protobuf/protobuf.cmake") 6 | -------------------------------------------------------------------------------- /tools/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | echowithcolor(COLOR GREEN "-- Configure Tools ${CMAKE_CURRENT_LIST_DIR}") 2 | 3 | # ============ TOOLS - [...] ============ 4 | file(GLOB TOOLS_SRC_LIST ${PROJECT_TOOLS_SRC_DIR}/*.cpp ${PROJECT_TOOLS_SRC_DIR}/*.cc ${PROJECT_TOOLS_SRC_DIR}/*.c 5 | ${PROJECT_TOOLS_SRC_DIR}/*.cxx) 6 | 7 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/tools") 8 | 9 | foreach(TOOLS_SRC_FILE IN LISTS TOOLS_SRC_LIST) 10 | get_filename_component(TOOLS_SRC_BIN_NAME "${TOOLS_SRC_FILE}" NAME_WE) 11 | 12 | add_executable("${TOOLS_SRC_BIN_NAME}" ${TOOLS_SRC_FILE}) 13 | target_link_libraries("${TOOLS_SRC_BIN_NAME}" atframework::atbus) 14 | target_include_directories("${TOOLS_SRC_BIN_NAME}" PRIVATE "$") 15 | 16 | set_property(TARGET "${TOOLS_SRC_BIN_NAME}" PROPERTY FOLDER "atframework/tools/atbus") 17 | 18 | install( 19 | TARGETS "${TOOLS_SRC_BIN_NAME}" 20 | RUNTIME DESTINATION tools 21 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 22 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) 23 | 24 | endforeach() 25 | -------------------------------------------------------------------------------- /tools/benchmark_io_stream_channel_recv.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | #include "detail/libatbus_channel_export.h" 13 | 14 | struct run_config { 15 | size_t max_n; 16 | size_t limit_size; 17 | size_t limit_static_num; 18 | 19 | // stats 20 | 21 | size_t sum_recv_len; 22 | size_t sum_recv_times; 23 | size_t sum_recv_full; 24 | size_t sum_recv_err; 25 | }; 26 | 27 | run_config conf; 28 | 29 | static void recv_callback(atbus::channel::io_stream_channel *channel, // 事件触发的channel 30 | atbus::channel::io_stream_connection *connection, // 事件触发的连接 31 | int status, // libuv传入的转态码 32 | void *buff, // 额外参数(不同事件不同含义) 33 | size_t s // 额外参数长度 34 | ) { 35 | assert(channel); 36 | assert(connection); 37 | 38 | if (0 != status) { 39 | fprintf(stderr, "recv callback error, ret code: %d. %s: %s\n", status, uv_err_name(channel->error_code), 40 | uv_strerror(channel->error_code)); 41 | 42 | ++conf.sum_recv_err; 43 | return; 44 | } 45 | 46 | size_t checked = 0; 47 | // check value 48 | if (s > 0) { 49 | size_t len = s / sizeof(size_t); 50 | bool passed = true; 51 | size_t *data_arr = reinterpret_cast(buff); 52 | checked = data_arr[0]; 53 | for (size_t i = 1; passed && i < len; ++i) { 54 | passed = data_arr[i] == checked; 55 | } 56 | 57 | if (passed && 0 != reinterpret_cast(connection->data)) { 58 | passed = checked == reinterpret_cast(connection->data); 59 | } 60 | 61 | if (!passed) { 62 | ++conf.sum_recv_err; 63 | std::cerr << "recv callback check error" << std::endl; 64 | } else { 65 | ++conf.sum_recv_times; 66 | conf.sum_recv_len += s; 67 | } 68 | 69 | ++checked; 70 | } 71 | 72 | const_cast(connection)->data = reinterpret_cast(checked); 73 | } 74 | 75 | static void stat_callback(uv_timer_t * /*handle*/) { 76 | static int secs = 0; 77 | static char unit_desc[][4] = {"B", "KB", "MB", "GB"}; 78 | static size_t unit_devi[] = {1UL, 1UL << 10, 1UL << 20, 1UL << 30}; 79 | static size_t unit_index = 0; 80 | 81 | ++secs; 82 | 83 | while (conf.sum_recv_len / unit_devi[unit_index] > 1024 && unit_index < sizeof(unit_devi) / sizeof(size_t) - 1) 84 | ++unit_index; 85 | 86 | while (conf.sum_recv_len / unit_devi[unit_index] <= 1024 && unit_index > 0) --unit_index; 87 | 88 | std::cout << "[ RUNNING ] NO." << secs << " m" << std::endl 89 | << "[ RUNNING ] recv(" << conf.sum_recv_times << " times, " << (conf.sum_recv_len / unit_devi[unit_index]) 90 | << " " << unit_desc[unit_index] << ") " << "full " << conf.sum_recv_full << " times, err " 91 | << conf.sum_recv_err << " times" << std::endl 92 | << std::endl; 93 | 94 | std::cout.flush(); 95 | std::cerr.flush(); 96 | } 97 | 98 | static void closed_callback(EXPLICIT_UNUSED_ATTR atbus::channel::io_stream_channel *channel, // 事件触发的channel 99 | EXPLICIT_UNUSED_ATTR atbus::channel::io_stream_connection *connection, // 事件触发的连接 100 | int /*status*/, // libuv传入的转态码 101 | void *, // 额外参数(不同事件不同含义) 102 | size_t // 额外参数长度 103 | ) { 104 | assert(channel); 105 | assert(connection); 106 | 107 | // 除listen外的最后一个连接 108 | if (channel->conn_pool.size() <= 2) uv_stop(channel->ev_loop); 109 | } 110 | 111 | int main(int argc, char *argv[]) { 112 | if (argc < 2) { 113 | printf("usage: %s
[max unit size] [limit number]\n", argv[0]); 114 | return 0; 115 | } 116 | 117 | using namespace atbus::channel; 118 | 119 | if (argc > 2) 120 | conf.max_n = (size_t)strtol(argv[2], nullptr, 10); 121 | else 122 | conf.max_n = 1024; 123 | 124 | conf.limit_size = sizeof(size_t) * conf.max_n; // 64KB 125 | 126 | if (argc > 3) 127 | conf.limit_static_num = (size_t)strtol(argv[3], nullptr, 10); 128 | else 129 | conf.limit_static_num = 2; // default 130 | 131 | conf.sum_recv_len = 0; 132 | conf.sum_recv_times = 0; 133 | conf.sum_recv_full = 0; 134 | conf.sum_recv_err = 0; 135 | 136 | io_stream_conf cfg; 137 | io_stream_init_configure(&cfg); 138 | cfg.recv_buffer_max_size = 139 | conf.limit_size + atbus::detail::buffer_block::full_size(cfg.recv_buffer_limit_size) * conf.limit_static_num + 140 | atbus::detail::buffer_block::padding_size(1); // 预留一个对齐单位的空区域 141 | cfg.recv_buffer_static = conf.limit_static_num; 142 | 143 | io_stream_channel channel; 144 | io_stream_init(&channel, uv_default_loop(), &cfg); 145 | channel.evt.callbacks[io_stream_callback_evt_t::EN_FN_RECVED] = recv_callback; 146 | channel.evt.callbacks[io_stream_callback_evt_t::EN_FN_DISCONNECTED] = closed_callback; 147 | 148 | channel_address_t addr; 149 | make_address(argv[1], addr); 150 | 151 | if (io_stream_listen(&channel, addr, nullptr, nullptr, 0) < 0) { 152 | std::cerr << "listen to " << argv[1] << " failed." << uv_err_name(channel.error_code) << ":" 153 | << uv_strerror(channel.error_code) << std::endl; 154 | io_stream_close(&channel); 155 | return -1; 156 | } 157 | 158 | uv_timer_t stat; 159 | uv_timer_init(uv_default_loop(), &stat); 160 | uv_timer_start(&stat, stat_callback, 60000, 60000); 161 | 162 | int ret = uv_run(uv_default_loop(), UV_RUN_DEFAULT); 163 | io_stream_close(&channel); 164 | return ret; 165 | } 166 | -------------------------------------------------------------------------------- /tools/benchmark_io_stream_channel_send.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | #include "detail/libatbus_channel_export.h" 13 | 14 | struct run_config { 15 | size_t max_n; 16 | size_t limit_size; 17 | size_t limit_static_num; 18 | size_t *buff_pool; 19 | 20 | // stats 21 | size_t pending_send; 22 | size_t sum_send_len; 23 | size_t sum_send_times; 24 | size_t sum_send_full; 25 | size_t sum_send_err; 26 | size_t sum_seq; 27 | }; 28 | 29 | run_config conf; 30 | 31 | static void send_data(atbus::channel::io_stream_connection *connection); 32 | 33 | static void connect_callback(atbus::channel::io_stream_channel *channel, // 事件触发的channel 34 | atbus::channel::io_stream_connection *connection, // 事件触发的连接 35 | int status, // libuv传入的转态码 36 | void *, // 额外参数(不同事件不同含义) 37 | size_t // 额外参数长度 38 | ) { 39 | if (0 != status) { 40 | std::cerr << "connect failed, statue: " << status << std::endl; 41 | std::cerr << uv_err_name(channel->error_code) << ":" << uv_strerror(channel->error_code) << std::endl; 42 | uv_stop(channel->ev_loop); 43 | return; 44 | } 45 | assert(connection); 46 | send_data(const_cast(connection)); 47 | } 48 | 49 | static void sended_callback(atbus::channel::io_stream_channel *channel, // 事件触发的channel 50 | atbus::channel::io_stream_connection *connection, // 事件触发的连接 51 | int status, // libuv传入的转态码 52 | void *, // 额外参数(不同事件不同含义) 53 | size_t s // 额外参数长度 54 | ) { 55 | assert(channel); 56 | assert(connection); 57 | 58 | --conf.pending_send; 59 | 60 | if (0 != status) { 61 | fprintf(stderr, "io_stream_send callback error, ret code: %d. %s: %s\n", status, uv_err_name(channel->error_code), 62 | uv_strerror(channel->error_code)); 63 | 64 | ++conf.sum_send_err; 65 | return; 66 | } 67 | 68 | ++conf.sum_send_times; 69 | conf.sum_send_len += s; 70 | send_data(const_cast(connection)); 71 | } 72 | 73 | static void closed_callback(EXPLICIT_UNUSED_ATTR atbus::channel::io_stream_channel *channel, // 事件触发的channel 74 | EXPLICIT_UNUSED_ATTR atbus::channel::io_stream_connection *connection, // 事件触发的连接 75 | int /*status*/, // libuv传入的转态码 76 | void *, // 额外参数(不同事件不同含义) 77 | size_t // 额外参数长度 78 | ) { 79 | assert(channel); 80 | assert(connection); 81 | 82 | uv_stop(channel->ev_loop); 83 | } 84 | 85 | static void stat_callback(uv_timer_t * /*handle*/) { 86 | static int secs = 0; 87 | static char unit_desc[][4] = {"B", "KB", "MB", "GB"}; 88 | static size_t unit_devi[] = {1UL, 1UL << 10, 1UL << 20, 1UL << 30}; 89 | static size_t unit_index = 0; 90 | 91 | ++secs; 92 | 93 | while (conf.sum_send_len / unit_devi[unit_index] > 1024 && unit_index < sizeof(unit_devi) / sizeof(size_t) - 1) 94 | ++unit_index; 95 | 96 | while (conf.sum_send_len / unit_devi[unit_index] <= 1024 && unit_index > 0) --unit_index; 97 | 98 | std::cout << "[ RUNNING ] NO." << secs << " m" << std::endl 99 | << "[ RUNNING ] send(" << conf.sum_send_times << " times, " << (conf.sum_send_len / unit_devi[unit_index]) 100 | << " " << unit_desc[unit_index] << ") " << "full " << conf.sum_send_full << " times, err " 101 | << conf.sum_send_err << " times" << std::endl 102 | << std::endl; 103 | 104 | std::cout.flush(); 105 | std::cerr.flush(); 106 | } 107 | 108 | int main(int argc, char *argv[]) { 109 | if (argc < 2) { 110 | printf("usage: %s
[max unit size] [limit size] [limit number]\n", argv[0]); 111 | return 0; 112 | } 113 | 114 | using namespace atbus::channel; 115 | 116 | if (argc > 2) 117 | conf.max_n = (size_t)strtol(argv[2], nullptr, 10); 118 | else 119 | conf.max_n = 1024; 120 | 121 | conf.buff_pool = new size_t[conf.max_n]; 122 | assert(conf.buff_pool); 123 | 124 | if (argc > 3) 125 | conf.limit_size = (size_t)strtol(argv[3], nullptr, 10); 126 | else 127 | conf.limit_size = 64 * 1024; // 64KB 128 | 129 | if (argc > 4) 130 | conf.limit_static_num = (size_t)strtol(argv[4], nullptr, 10); 131 | else 132 | conf.limit_static_num = 0; // dynamic 133 | 134 | srand(static_cast(time(nullptr))); 135 | conf.pending_send = 0; 136 | conf.sum_send_len = 0; 137 | conf.sum_send_times = 0; 138 | conf.sum_send_full = 0; 139 | conf.sum_send_err = 0; 140 | conf.sum_seq = ((size_t)rand() << (sizeof(size_t) * 4)); 141 | 142 | io_stream_conf cfg; 143 | io_stream_init_configure(&cfg); 144 | cfg.send_buffer_max_size = conf.limit_size; 145 | cfg.send_buffer_static = conf.limit_static_num; 146 | 147 | io_stream_channel channel; 148 | io_stream_init(&channel, uv_default_loop(), &cfg); 149 | channel.evt.callbacks[io_stream_callback_evt_t::EN_FN_WRITEN] = sended_callback; 150 | channel.evt.callbacks[io_stream_callback_evt_t::EN_FN_DISCONNECTED] = closed_callback; 151 | 152 | channel_address_t addr; 153 | make_address(argv[1], addr); 154 | 155 | if (io_stream_connect(&channel, addr, connect_callback, nullptr, 0) < 0) { 156 | std::cerr << "connect to " << argv[1] << " failed." << uv_err_name(channel.error_code) << ":" 157 | << uv_strerror(channel.error_code) << std::endl; 158 | io_stream_close(&channel); 159 | delete[] conf.buff_pool; 160 | return -1; 161 | } 162 | 163 | uv_timer_t stat; 164 | uv_timer_init(uv_default_loop(), &stat); 165 | uv_timer_start(&stat, stat_callback, 60000, 60000); 166 | 167 | int ret = uv_run(uv_default_loop(), UV_RUN_DEFAULT); 168 | io_stream_close(&channel); 169 | 170 | delete[] conf.buff_pool; 171 | return ret; 172 | } 173 | 174 | static void send_data(atbus::channel::io_stream_connection *connection) { 175 | using namespace atbus::channel; 176 | 177 | assert(connection); 178 | // 尝试5次,逐渐填满数据 179 | for (int try_times = 0; try_times < 2; ++try_times) { 180 | size_t n = rand() % conf.max_n; // 最大 4K-8K的包 181 | if (0 == n) n = 1; // 保证一定有数据包,保证收发次数一致 182 | 183 | for (size_t i = 0; i < n; ++i) { 184 | conf.buff_pool[i] = conf.sum_seq; 185 | } 186 | 187 | int res = io_stream_send(connection, conf.buff_pool, n * sizeof(size_t)); 188 | if (res) { 189 | if (EN_ATBUS_ERR_BUFF_LIMIT == res) { 190 | ++conf.sum_send_full; 191 | break; 192 | } else { 193 | ++conf.sum_send_err; 194 | fprintf(stderr, "io_stream_send error, ret code: %d. %s: %s\n", res, 195 | uv_err_name(connection->channel->error_code), uv_strerror(connection->channel->error_code)); 196 | } 197 | } else { 198 | ++conf.pending_send; 199 | ++conf.sum_seq; 200 | } 201 | } 202 | } -------------------------------------------------------------------------------- /tools/benchmark_shm_channel_recv.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include "config/compiler_features.h" 16 | 17 | #include "common/string_oprs.h" 18 | 19 | #if defined(UTIL_CONFIG_COMPILER_CXX_LAMBDAS) && UTIL_CONFIG_COMPILER_CXX_LAMBDAS && defined(ATBUS_CHANNEL_SHM) 20 | 21 | static inline char *get_pid_cur(int pid) { 22 | static std::vector > res; 23 | for (size_t i = 0; i < res.size(); ++i) { 24 | if (res[i].first == pid) { 25 | return &res[i].second; 26 | } 27 | } 28 | 29 | res.push_back(std::pair(pid, 0)); 30 | return &res.back().second; 31 | } 32 | 33 | int main(int argc, char *argv[]) { 34 | if (argc < 2) { 35 | printf("usage: %s [max unit size] [shm size]\n", argv[0]); 36 | return 0; 37 | } 38 | 39 | using namespace atbus::channel; 40 | size_t max_n = 1024; 41 | if (argc > 2) max_n = (size_t)strtol(argv[2], nullptr, 10); 42 | 43 | size_t buffer_len = 64 * 1024 * 1024; // 64MB 44 | if (argc > 3) buffer_len = (size_t)strtol(argv[3], nullptr, 10); 45 | 46 | shm_channel *channel = nullptr; 47 | 48 | int res = shm_init(argv[1], buffer_len, &channel, nullptr); 49 | if (res < 0) { 50 | fprintf(stderr, "shm_init failed, ret: %d\n", res); 51 | return res; 52 | } 53 | 54 | srand(static_cast(time(nullptr))); 55 | 56 | size_t sum_recv_len = 0; 57 | size_t sum_recv_times = 0; 58 | size_t sum_recv_err = 0; 59 | size_t sum_data_err = 0; 60 | 61 | // 创建读线程 62 | std::thread *read_threads = 63 | new std::thread([&sum_recv_len, &sum_recv_times, &sum_recv_err, &sum_data_err, max_n, channel] { 64 | char *buf_pool = new char[max_n * sizeof(size_t)]; 65 | char *buf_check = new char[max_n * sizeof(size_t)]; 66 | 67 | bool is_last_tick_faild = false; 68 | while (true) { 69 | size_t n = 0; // 最大 4K-8K的包 70 | int res = shm_recv(channel, buf_pool, sizeof(size_t) * max_n, &n); 71 | 72 | if (res) { 73 | if (EN_ATBUS_ERR_NO_DATA != res) { 74 | std::pair last_action = shm_last_action(); 75 | fprintf(stderr, "shm_recv error, ret code: %d. start: %d, end: %d\n", res, (int)last_action.first, 76 | (int)last_action.second); 77 | ++sum_recv_err; 78 | 79 | if (!is_last_tick_faild) { 80 | shm_show_channel(channel, std::cout, true, 24); 81 | } 82 | is_last_tick_faild = true; 83 | } else { 84 | std::this_thread::sleep_for(std::chrono::milliseconds(128)); 85 | } 86 | } else { 87 | ++sum_recv_times; 88 | sum_recv_len += n; 89 | 90 | int pid = *((int *)buf_pool); 91 | char *val_check = get_pid_cur(pid); 92 | 93 | if (0 == *val_check) { 94 | *val_check = *(buf_pool + sizeof(int)); 95 | } else { 96 | ++(*val_check); 97 | if (0 == *val_check) { 98 | ++(*val_check); 99 | } 100 | } 101 | 102 | memset(buf_check + sizeof(int), (int)*val_check, n - sizeof(int)); 103 | int cmp_res = memcmp(buf_pool + sizeof(int), buf_check + sizeof(int), n - sizeof(int)); 104 | if (0 == cmp_res) { 105 | is_last_tick_faild = false; 106 | } else { 107 | std::cerr << "pid: " << pid << " expected data is "; 108 | atfw::util::string::dumphex(val_check, 1, std::cerr); 109 | std::cerr << ", but real is "; 110 | atfw::util::string::dumphex(buf_pool + sizeof(int), 1, std::cerr); 111 | std::cerr << std::endl; 112 | *val_check = *(buf_pool + sizeof(int)); 113 | 114 | ++sum_data_err; 115 | 116 | if (!is_last_tick_faild) { 117 | shm_show_channel(channel, std::cout, true, 24); 118 | } 119 | is_last_tick_faild = true; 120 | } 121 | } 122 | } 123 | 124 | delete[] buf_pool; 125 | delete[] buf_check; 126 | }); 127 | 128 | // 检查状态 129 | int secs = 0; 130 | char unit_desc[][4] = {"B", "KB", "MB", "GB"}; 131 | size_t unit_devi[] = {1UL, 1UL << 10, 1UL << 20, 1UL << 30}; 132 | size_t unit_index = 0; 133 | 134 | while (true) { 135 | ++secs; 136 | std::this_thread::sleep_for(std::chrono::milliseconds(60000)); 137 | 138 | while (sum_recv_len / unit_devi[unit_index] > 1024 && unit_index < sizeof(unit_devi) / sizeof(size_t) - 1) 139 | ++unit_index; 140 | 141 | while (sum_recv_len / unit_devi[unit_index] <= 1024 && unit_index > 0) --unit_index; 142 | 143 | std::cout << "[ RUNNING ] NO." << secs << " m" << std::endl 144 | << "[ RUNNING ] recv(" << sum_recv_times << " times, " << (sum_recv_len / unit_devi[unit_index]) << " " 145 | << unit_desc[unit_index] << ") " << "recv err " << sum_recv_err << " times, data valid failed " 146 | << sum_data_err << " times" << std::endl 147 | << std::endl; 148 | 149 | shm_show_channel(channel, std::cout, false, 0); 150 | } 151 | 152 | read_threads->join(); 153 | delete read_threads; 154 | 155 | return 0; 156 | } 157 | 158 | #else 159 | 160 | int main() { 161 | std::cerr << "this benckmark code require your compiler support lambda and c++11/thread" << std::endl; 162 | return 0; 163 | } 164 | 165 | #endif 166 | -------------------------------------------------------------------------------- /tools/benchmark_shm_channel_send.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #ifndef _MSC_VER 15 | 16 | # include 17 | # include 18 | 19 | #else 20 | # pragma comment(lib, "Ws2_32.lib") 21 | #endif 22 | 23 | #include 24 | #include "config/compiler_features.h" 25 | #include "detail/libatbus_channel_export.h" 26 | 27 | #ifdef max 28 | # undef max 29 | #endif 30 | 31 | #if defined(UTIL_CONFIG_COMPILER_CXX_LAMBDAS) && UTIL_CONFIG_COMPILER_CXX_LAMBDAS && defined(ATBUS_CHANNEL_SHM) 32 | 33 | static int test_get_pid() { 34 | # ifdef _MSC_VER 35 | return _getpid(); 36 | # else 37 | return getpid(); 38 | # endif 39 | } 40 | 41 | int main(int argc, char *argv[]) { 42 | if (argc < 2) { 43 | printf("usage: %s [max unit size] [shm size]\n", argv[0]); 44 | return 0; 45 | } 46 | 47 | using namespace atbus::channel; 48 | size_t max_n = 1024; 49 | if (argc > 2) max_n = (size_t)strtol(argv[2], nullptr, 10); 50 | 51 | size_t buffer_len = 64 * 1024 * 1024; // 64MB 52 | if (argc > 3) buffer_len = (size_t)strtol(argv[3], nullptr, 10); 53 | 54 | shm_channel *channel = nullptr; 55 | 56 | int res = shm_attach(argv[1], buffer_len, &channel, nullptr); 57 | if (res < 0) { 58 | fprintf(stderr, "shm_attach failed, ret: %d\n", res); 59 | return res; 60 | } 61 | 62 | srand(static_cast(time(nullptr))); 63 | 64 | size_t sum_send_len = 0; 65 | size_t sum_send_times = 0; 66 | size_t sum_send_full = 0; 67 | size_t sum_send_err = 0; 68 | char sum_seq = (char)rand() + 1; 69 | int pid = test_get_pid(); 70 | 71 | if (!sum_seq) { 72 | ++sum_seq; 73 | } 74 | // 创建写线程 75 | std::thread *write_threads = 76 | new std::thread([&sum_send_len, &sum_send_times, &sum_send_full, &sum_send_err, &sum_seq, pid, max_n, channel] { 77 | char *buf_pool = new char[max_n * sizeof(size_t)]; 78 | int sleep_msec = 8; 79 | 80 | while (true) { 81 | size_t n = rand() % max_n; // 最大 4K-8K的包 82 | if (0 == n) n = 1; // 保证一定有数据包,保证收发次数一致 83 | 84 | *((int *)buf_pool) = pid; 85 | memset(buf_pool + sizeof(int), (int)sum_seq, n * sizeof(size_t) - sizeof(int)); 86 | int res = shm_send(channel, buf_pool, n * sizeof(size_t)); 87 | 88 | if (res) { 89 | if (EN_ATBUS_ERR_BUFF_LIMIT == res) { 90 | ++sum_send_full; 91 | } else { 92 | ++sum_send_err; 93 | 94 | std::pair last_action = shm_last_action(); 95 | fprintf(stderr, "shm_send error, ret code: %d. start: %d, end: %d\n", res, (int)last_action.first, 96 | (int)last_action.second); 97 | } 98 | 99 | std::this_thread::sleep_for(std::chrono::milliseconds(sleep_msec)); 100 | if (sleep_msec < 32) { 101 | sleep_msec *= 2; 102 | } 103 | 104 | } else { 105 | ++sum_send_times; 106 | sum_send_len += n * sizeof(size_t); 107 | 108 | ++sum_seq; 109 | if (!sum_seq) { 110 | ++sum_seq; 111 | } 112 | 113 | if (sleep_msec > 8) sleep_msec /= 2; 114 | } 115 | } 116 | 117 | delete[] buf_pool; 118 | }); 119 | 120 | // 检查状态 121 | int secs = 0; 122 | char unit_desc[][4] = {"B", "KB", "MB", "GB"}; 123 | size_t unit_devi[] = {1UL, 1UL << 10, 1UL << 20, 1UL << 30}; 124 | size_t unit_index = 0; 125 | 126 | while (true) { 127 | ++secs; 128 | // std::chrono::seconds dura(60); 129 | std::this_thread::sleep_for(std::chrono::milliseconds(60000)); 130 | 131 | while (sum_send_len / unit_devi[unit_index] > 1024 && unit_index < sizeof(unit_devi) / sizeof(size_t) - 1) 132 | ++unit_index; 133 | 134 | while (sum_send_len / unit_devi[unit_index] <= 1024 && unit_index > 0) --unit_index; 135 | 136 | std::cout << "[ RUNNING ] NO." << secs << " m" << std::endl 137 | << "[ RUNNING ] send(" << sum_send_times << " times, " << (sum_send_len / unit_devi[unit_index]) << " " 138 | << unit_desc[unit_index] << ") " << "full " << sum_send_full << " times, err " << sum_send_err << " times" 139 | << std::endl 140 | << std::endl; 141 | } 142 | 143 | write_threads->join(); 144 | delete write_threads; 145 | 146 | return 0; 147 | } 148 | 149 | #else 150 | 151 | int main() { 152 | std::cerr << "this benckmark code require your compiler support lambda and c++11/thread" << std::endl; 153 | return 0; 154 | } 155 | 156 | #endif -------------------------------------------------------------------------------- /tools/script/cppcheck.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | SCRIPT_DIR="$( cd "$( dirname "$0" )" && pwd )"; 4 | SCRIPT_DIR="$( readlink -f $SCRIPT_DIR )"; 5 | 6 | PROJECT_DIR="$( cd "$SCRIPT_DIR/../.." && pwd )"; 7 | 8 | WORK_DIR="$PWD"; 9 | 10 | cd "$PROJECT_DIR"; 11 | 12 | cppcheck . --enable=all --xml --xml-version=2 --inconclusive --std=c11 --std=c++14 --std=posix -I "$PROJECT_DIR/third_party/atframe_utils/repo/include" -I "$PROJECT_DIR/third_party/protobuf/prebuilt/"*"/include" $@ 2>"$WORK_DIR/cppcheck.xml"; 13 | 14 | which cppcheck-htmlreport; 15 | if [ 0 -eq $? ]; then 16 | mkdir -p "$WORK_DIR/cppcheck.html"; 17 | cppcheck-htmlreport --title=libatbus.cppcheck --file="$WORK_DIR/cppcheck.xml" --report-dir="$WORK_DIR/cppcheck.html" --source-dir=. --source-encoding=utf-8 ; 18 | fi 19 | -------------------------------------------------------------------------------- /tools/script/startup_benchmark_io_stream.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ADDRESS="ipv6://::1:16389"; 4 | UNIT_SIZE=1024 ; 5 | LIMIT_SIZE=4194304 ; 6 | STATIC_LIMIT_NUM=1024 ; 7 | 8 | if [ $# -ge 1 ]; then 9 | ADDRESS="$1"; 10 | fi 11 | 12 | if [ $# -ge 2 ]; then 13 | UNIT_SIZE=$2 ; 14 | fi 15 | 16 | if [ $# -ge 3 ]; then 17 | LIMIT_SIZE=$3 ; 18 | fi 19 | 20 | if [ $# -ge 4 ]; then 21 | STATIC_LIMIT_NUM=$4 ; 22 | fi 23 | 24 | ./benchmark_io_stream_channel_recv "$ADDRESS" $UNIT_SIZE > recv-ios.log 2>&1 & 25 | 26 | sleep 2; 27 | 28 | for ((i=1;i<=16;++i)); do 29 | ./benchmark_io_stream_channel_send "$ADDRESS" $UNIT_SIZE $LIMIT_SIZE $STATIC_LIMIT_NUM > send-ios-$i.log 2>&1 & 30 | done 31 | 32 | -------------------------------------------------------------------------------- /tools/script/startup_benchmark_shm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ADDRESS=12345679 ; 4 | UNIT_SIZE=1024 ; 5 | SHM_SIZE=16777216 ; # 16MB 6 | 7 | if [ $# -ge 1 ]; then 8 | ADDRESS="$1"; 9 | fi 10 | 11 | if [ $# -ge 2 ]; then 12 | UNIT_SIZE=$2 ; 13 | fi 14 | 15 | ./benchmark_shm_channel_recv $ADDRESS $UNIT_SIZE $SHM_SIZE > recv-shm.log 2>&1 & 16 | 17 | sleep 2; 18 | 19 | for ((i=1;i<=16;++i)); do 20 | ./benchmark_shm_channel_send $ADDRESS $UNIT_SIZE $SHM_SIZE > send-shm-$i.log 2>&1 & 21 | done 22 | 23 | -------------------------------------------------------------------------------- /tools/script/valgrind_memcheck.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # valgrind --vgdb=full --vgdb-error=0 --leak-check=full --tool=memcheck --show-leak-kinds=all --log-file=memcheck.log --malloc-fill=0x5E "$@"; 4 | # valgrind --vgdb=yes --vgdb-error=0 --leak-check=full --tool=memcheck --show-leak-kinds=all --log-file=memcheck.log --malloc-fill=0x5E "$@"; 5 | # then, run: gdb [executable-file] --eval-command="target remote | vgdb" 6 | valgrind --vgdb=yes --leak-check=full --tool=memcheck --show-leak-kinds=all --log-file=memcheck.log "$@"; -------------------------------------------------------------------------------- /tools/show_shm_channel.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include "config/compiler_features.h" 16 | #include "detail/libatbus_channel_export.h" 17 | 18 | #if defined(ATBUS_CHANNEL_SHM) 19 | int main(int argc, char *argv[]) { 20 | if (argc < 2) { 21 | printf("usage: %s [need node info: 0 or 1] [node data size]\n", argv[0]); 22 | return 0; 23 | } 24 | 25 | using namespace atbus::channel; 26 | shm_channel *channel = nullptr; 27 | long need_node_info = 0; 28 | size_t need_node_data = 0; 29 | 30 | if (argc > 2) { 31 | need_node_info = strtol(argv[2], nullptr, 10); 32 | } 33 | 34 | if (argc > 3) { 35 | need_node_data = (size_t)strtol(argv[3], nullptr, 10); 36 | } 37 | 38 | int res = shm_attach(argv[1], 0, &channel, nullptr); 39 | if (res < 0) { 40 | fprintf(stderr, "shm_attach for %s failed, ret: %d\n", argv[1], res); 41 | return res; 42 | } 43 | 44 | shm_show_channel(channel, std::cout, !!need_node_info, need_node_data); 45 | return 0; 46 | } 47 | #else 48 | int main() { 49 | puts("shm channel disabled"); 50 | return 0; 51 | } 52 | #endif -------------------------------------------------------------------------------- /tools/tools.macro.cmake: -------------------------------------------------------------------------------- 1 | # =========== tools =========== 2 | set(PROJECT_TOOLS_BAS_DIR ${CMAKE_CURRENT_LIST_DIR}) 3 | set(PROJECT_TOOLS_INC_DIR ${PROJECT_TOOLS_BAS_DIR}) 4 | set(PROJECT_TOOLS_SRC_DIR ${PROJECT_TOOLS_BAS_DIR}) 5 | --------------------------------------------------------------------------------