├── .gitignore ├── LICENSE ├── README.md ├── azure-pipelines.yml ├── client ├── .dockerignore ├── CMakeLists.txt ├── Dockerfile ├── src │ ├── App.cpp │ ├── AppComponent.hpp │ ├── ClientSocketListener.cpp │ ├── ClientSocketListener.hpp │ ├── Logger.cpp │ ├── Logger.hpp │ └── Meter.hpp ├── test │ └── tests.cpp └── utility │ └── install-oatpp-modules.sh ├── prepare.sh ├── server ├── .dockerignore ├── CMakeLists.txt ├── Dockerfile ├── src │ ├── App.cpp │ ├── AppComponent.hpp │ ├── Logger.cpp │ ├── Logger.hpp │ ├── Meter.hpp │ └── controller │ │ ├── MyController.hpp │ │ ├── WebSocketListener.cpp │ │ └── WebSocketListener.hpp ├── test │ ├── WebSocketTest.cpp │ ├── WebSocketTest.hpp │ └── tests.cpp └── utility │ └── install-oatpp-modules.sh ├── sock-config-4m.sh ├── sock-config-5m.sh └── sock-config.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # custom build 35 | build/ 36 | 37 | # idea 38 | .idea/ 39 | cmake-build-debug/ 40 | */cmake-build-debug/ 41 | 42 | # tmp 43 | 44 | tmp/ 45 | 46 | # MAC 47 | 48 | **/.DS_Store 49 | 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # benchmark-websocket [![Build Status](https://dev.azure.com/lganzzzo/lganzzzo/_apis/build/status/oatpp.benchmark-websocket?branchName=master)](https://dev.azure.com/lganzzzo/lganzzzo/_build/latest?definitionId=19&branchName=master) 2 | 3 | About recent results read here: [5 Million WebSockets](https://oatpp.io/benchmark/websocket/5-million/) 4 | 5 | See also: 6 | 7 | - [Oat++ Website](https://oatpp.io/) 8 | - [Oat++ Github Repository](https://github.com/oatpp/oatpp) 9 | - [oatpp-websocket Repository](https://github.com/oatpp/oatpp-websocket) 10 | 11 | ## Overview 12 | 13 | This repo contains both server and client used in oatpp-websocket-benchmarks. 14 | Both server and client are implemented based on oatpp Async API and [oatpp-coroutines](https://oatpp.io/docs/oatpp-coroutines/) 15 | 16 | ### Repo structure 17 | 18 | ``` 19 | |- client/ 20 | | |- src/ // client source code 21 | | |- CMakeLists.txt // client CMakeLists.txt 22 | | 23 | |- server/ 24 | | |- src/ // server source code 25 | | |- CMakeLists.txt // server CMakeLists.txt 26 | | 27 | |- prepare.sh // prepare script - will clone oatpp and oatpp-websocket. build and install. 28 | |- sock-config.sh // configure required sysctl(s) 29 | ``` 30 | 31 | ## Reproduce latest benchmark 32 | 33 | Create two `n1-highmem-16 (16 vCPUs, 104 GB memory) - Debian GNU/Linux 9` instances in same VPC on Google Cloud. 34 | 35 | ### Execute the following commands for both instances (SSH). 36 | 37 | - Install git 38 | 39 | ```bash 40 | $ sudo su 41 | $ apt-get update 42 | ... 43 | $ apt-get install -y git 44 | ... 45 | ``` 46 | 47 | - Clone [benchmark-websocket repo](https://github.com/oatpp/benchmark-websocket) and `cd` to repo folder 48 | 49 | ```bash 50 | $ git clone https://github.com/oatpp/benchmark-websocket 51 | ... 52 | $ cd benchmark-websocket 53 | ``` 54 | 55 | - Install `oatpp` and `oatpp-websocket` modules (run ./prepare.sh script). 56 | 57 | ```bash 58 | $ ./prepare.sh 59 | ``` 60 | 61 | - Configure environment (run ./sock-config-5m.sh script) 62 | 63 | ```bash 64 | $ ./sock-config-5m.sh 65 | $ ulimit -n 6000000 66 | ``` 67 | 68 | ### Build and Run Server 69 | 70 | Commands for server instance only: 71 | 72 | - Build server 73 | 74 | ```bash 75 | $ cd server/build/ 76 | $ cmake .. 77 | $ make 78 | ``` 79 | 80 | - Run server 81 | 82 | ```bash 83 | $ ./wsb-server-exe --tp 16 --tio 8 --pc 500 84 | ``` 85 | where: 86 | `--tp` - number of data-processing threads. 87 | `--tio` - number of I/O workers. 88 | `--pc` - number of ports to listen to. 89 | 90 | ### Build and Run Client 91 | 92 | Commands for client instance only: 93 | 94 | - Build client 95 | 96 | ```bash 97 | $ cd client/build/ 98 | $ cmake .. 99 | $ make 100 | ``` 101 | 102 | - Run client 103 | 104 | ```bash 105 | $ ./wsb-client-exe --tp 16 --tio 8 -h --socks-max 5000000 --socks-port 10000 --si 1000 --sf 30 --pc 500 106 | ``` 107 | where: 108 | `--tp` - number of data-processing threads. 109 | `--tio` - number of I/O workers. 110 | `-h ` - substitute **private-ip** of server instance here. 111 | `--socks-max` - how many client connections to establish. 112 | `--socks-port` - how many client connections per port. 113 | `--si 1000 --sf 30` - control how fast clients will connect to server. Here - each `1000` iterations sleep for `30` milliseconds. 114 | `--pc` - number of available server ports to connect to. 115 | 116 | **Note** - clients will not start load until all clients are connected. 117 | **Note** - client app will fail with assertion if any of clients has failed. 118 | 119 | ## Links 120 | 121 | - [Latest Benchmark](https://oatpp.io/benchmark/websocket/5-million/) 122 | - [Oat++ Github Repository](https://github.com/oatpp/oatpp) 123 | - [oatpp-websocket Repository](https://github.com/oatpp/oatpp-websocket) 124 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | - job: ubuntu_20_04 3 | displayName: 'Build - Ubuntu 20.04' 4 | continueOnError: false 5 | pool: 6 | vmImage: 'ubuntu-20.04' 7 | workspace: 8 | clean: all 9 | steps: 10 | - script: | 11 | sudo ./prepare.sh 12 | displayName: 'prepare.sh' 13 | - script: | 14 | sudo cmake .. 15 | sudo make 16 | make test ARGS="-V" 17 | workingDirectory: server/build 18 | displayName: 'build server' 19 | - script: | 20 | sudo cmake .. 21 | sudo make 22 | make test ARGS="-V" 23 | workingDirectory: client/build 24 | displayName: 'build client' 25 | -------------------------------------------------------------------------------- /client/.dockerignore: -------------------------------------------------------------------------------- 1 | build/ -------------------------------------------------------------------------------- /client/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | 3 | set(project_name wsb-client) ## rename your project here 4 | 5 | project(${project_name}) 6 | 7 | set(CMAKE_CXX_STANDARD 17) 8 | 9 | include_directories(src) 10 | 11 | add_library(${project_name}-lib 12 | src/AppComponent.hpp 13 | src/Logger.hpp 14 | src/Logger.cpp 15 | src/Meter.hpp 16 | src/ClientSocketListener.cpp 17 | src/ClientSocketListener.hpp) 18 | 19 | ## link libs 20 | 21 | find_package(oatpp 1.4.0 REQUIRED) 22 | find_package(oatpp-websocket 1.4.0 REQUIRED) 23 | 24 | target_link_libraries(${project_name}-lib 25 | PUBLIC oatpp::oatpp 26 | PUBLIC oatpp::oatpp-test 27 | PUBLIC oatpp::oatpp-websocket 28 | ) 29 | 30 | ## add executables 31 | 32 | add_executable(${project_name}-exe 33 | src/App.cpp 34 | ) 35 | 36 | target_link_libraries(${project_name}-exe ${project_name}-lib) 37 | add_dependencies(${project_name}-exe ${project_name}-lib) 38 | 39 | add_executable(${project_name}-test 40 | test/tests.cpp 41 | ) 42 | 43 | target_link_libraries(${project_name}-test ${project_name}-lib) 44 | add_dependencies(${project_name}-test ${project_name}-lib) 45 | 46 | set_target_properties(${project_name}-lib ${project_name}-exe ${project_name}-test PROPERTIES 47 | CXX_STANDARD 17 48 | CXX_EXTENSIONS OFF 49 | CXX_STANDARD_REQUIRED ON 50 | LINKER_LANGUAGE CXX 51 | ) 52 | 53 | enable_testing() 54 | add_test(tests ${project_name}-test) 55 | -------------------------------------------------------------------------------- /client/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM lganzzzo/alpine-cmake:latest 2 | 3 | ADD . /service 4 | 5 | WORKDIR /service/utility 6 | 7 | RUN ./install-oatpp-modules.sh 8 | 9 | WORKDIR /service/build 10 | 11 | RUN cmake .. 12 | RUN make 13 | 14 | EXPOSE 8000 8000 15 | 16 | ENTRYPOINT ["./wsb-client-exe"] 17 | -------------------------------------------------------------------------------- /client/src/App.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // main.cpp 3 | // web-starter-project 4 | // 5 | // Created by Leonid on 2/12/18. 6 | // Copyright © 2018 oatpp. All rights reserved. 7 | // 8 | 9 | #include "./ClientSocketListener.hpp" 10 | #include "./AppComponent.hpp" 11 | #include "./Logger.hpp" 12 | #include "./Meter.hpp" 13 | 14 | #include 15 | #include 16 | 17 | /** 18 | * Print Stats. 19 | */ 20 | void printStats() { 21 | 22 | OATPP_LOGd("Status", "\n\n\n\n\n"); 23 | 24 | Meter framesMeter(60 * 2); 25 | Meter messagesMeter(60 * 2); 26 | 27 | while(true) { 28 | 29 | v_int64 tickCount = oatpp::Environment::getMicroTickCount(); 30 | framesMeter.addPoint(tickCount, ClientSocketListener::FRAMES.load()); 31 | messagesMeter.addPoint(tickCount, ClientSocketListener::MESSAGES.load()); 32 | 33 | OATPP_LOGd("\33[2K\r\033[A\033[A\033[A\033[A\033[A" 34 | "SOCKETS", " {} ", ClientCoroutine::SOCKETS.load()); 35 | OATPP_LOGd("FRAMES_TOTAL", " {} ", ClientSocketListener::FRAMES.load()); 36 | OATPP_LOGd("MESSAGES_TOTAL", " {} ", ClientSocketListener::MESSAGES.load()); 37 | OATPP_LOGd("FRAMES_PER_MIN", " {} ", framesMeter.perMinute()); 38 | OATPP_LOGd("MESSAGES_PER_MIN", " {} ", messagesMeter.perMinute()); 39 | std::this_thread::sleep_for(std::chrono::milliseconds(500)); 40 | } 41 | 42 | }; 43 | 44 | void run(const oatpp::base::CommandLineArguments& args) { 45 | 46 | AppComponent components(args); // Create scope Environment components 47 | 48 | /* Get list of connection providers */ 49 | OATPP_COMPONENT(std::shared_ptr>>, connectionProviders); 50 | 51 | /* Get AsyncExecutor */ 52 | OATPP_COMPONENT(std::shared_ptr, executor); 53 | 54 | v_int32 maxSocketsNumber = oatpp::utils::Conversion::strToInt32(args.getNamedArgumentValue("--socks-max", "1000")); 55 | v_int32 maxSocketsPerPort = oatpp::utils::Conversion::strToInt32(args.getNamedArgumentValue("--socks-port", "10000")); 56 | v_int32 sleepIteration = oatpp::utils::Conversion::strToInt32(args.getNamedArgumentValue("--si", "5")); 57 | v_int32 sleepFor = oatpp::utils::Conversion::strToInt32(args.getNamedArgumentValue("--sf", "5")); 58 | 59 | v_int32 clientsCounter = 0; 60 | 61 | for(auto& provider : *connectionProviders) { 62 | 63 | OATPP_LOGd("Client", "add clients for port {}", provider->getProperty("port").toString()); 64 | 65 | auto connector = oatpp::websocket::Connector::createShared(provider); 66 | 67 | v_int32 clientsToAdd = maxSocketsNumber - clientsCounter; 68 | if(clientsToAdd > maxSocketsPerPort) { 69 | clientsToAdd = maxSocketsPerPort; 70 | } 71 | 72 | for(v_int32 i = 0; i < clientsToAdd; i++) { 73 | executor->execute(connector); 74 | if(i % sleepIteration == 0) { 75 | std::this_thread::sleep_for(std::chrono::milliseconds(sleepFor)); 76 | } 77 | } 78 | 79 | clientsCounter += clientsToAdd; 80 | 81 | if(clientsCounter >= maxSocketsNumber) { 82 | break; 83 | } 84 | 85 | } 86 | 87 | OATPP_LOGd("Client", "Waiting clients to connect..."); 88 | 89 | std::thread statThread([]{ 90 | printStats(); 91 | }); 92 | 93 | /* Wait all clients to connect */ 94 | /* Do not start load until all clients are connected */ 95 | while(ClientCoroutine::SOCKETS < maxSocketsNumber) { 96 | std::this_thread::sleep_for(std::chrono::milliseconds(200)); 97 | } 98 | 99 | 100 | /* Once all clients are connected - start load */ 101 | 102 | oatpp::websocket::Config config; 103 | 104 | config.maskOutgoingMessages = true; 105 | config.readBufferSize = 64; 106 | 107 | for(auto& socket : ClientCoroutine::SOCKETS_LIST) { 108 | 109 | socket->setConfig(config); 110 | executor->execute(socket); 111 | 112 | } 113 | 114 | executor->join(); 115 | statThread.join(); 116 | 117 | } 118 | 119 | /** 120 | * main 121 | */ 122 | int main(int argc, const char * argv[]) { 123 | 124 | oatpp::Environment::init(); 125 | 126 | run(oatpp::base::CommandLineArguments(argc, argv)); 127 | 128 | /* Print how much objects were created during app running, and what have left-probably leaked */ 129 | /* Disable object counting for release builds using '-D OATPP_DISABLE_ENV_OBJECT_COUNTERS' flag for better performance */ 130 | std::cout << "\nEnvironment:\n"; 131 | std::cout << "objectsCount = " << oatpp::Environment::getObjectsCount() << "\n"; 132 | std::cout << "objectsCreated = " << oatpp::Environment::getObjectsCreated() << "\n\n"; 133 | 134 | oatpp::Environment::destroy(); 135 | 136 | return 0; 137 | } 138 | -------------------------------------------------------------------------------- /client/src/AppComponent.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // AppComponent.hpp 3 | // oatpp-web-starter 4 | // 5 | // Created by Leonid on 3/2/18. 6 | // Copyright © 2018 lganzzzo. All rights reserved. 7 | // 8 | 9 | #ifndef AppComponent_hpp 10 | #define AppComponent_hpp 11 | 12 | #include "oatpp/async/Executor.hpp" 13 | 14 | #include "oatpp/network/tcp/client/ConnectionProvider.hpp" 15 | #include "oatpp/macro/component.hpp" 16 | 17 | #include "oatpp/base/CommandLineArguments.hpp" 18 | #include "oatpp/utils/Conversion.hpp" 19 | 20 | #include 21 | 22 | /** 23 | * Class which creates and holds Application components and registers components in oatpp::Environment 24 | * Order of components initialization is from top to bottom 25 | */ 26 | class AppComponent { 27 | private: 28 | oatpp::base::CommandLineArguments m_cmdArgs; 29 | public: 30 | AppComponent(const oatpp::base::CommandLineArguments& cmdArgs) 31 | : m_cmdArgs(cmdArgs) 32 | {} 33 | public: 34 | 35 | /** 36 | * Create AsyncExecutor for WebSocket Asynchronous processing. 37 | */ 38 | OATPP_CREATE_COMPONENT(std::shared_ptr, executor)([this] { 39 | 40 | v_int32 threadsProc = oatpp::utils::Conversion::strToInt32(m_cmdArgs.getNamedArgumentValue("--tp", "8")); 41 | v_int32 threadsIO = oatpp::utils::Conversion::strToInt32(m_cmdArgs.getNamedArgumentValue("--tio", "2")); 42 | v_int32 threadsTimer = oatpp::utils::Conversion::strToInt32(m_cmdArgs.getNamedArgumentValue("--tt", "1")); 43 | 44 | return std::make_shared(threadsProc, threadsIO, threadsTimer); 45 | 46 | }()); 47 | 48 | /** 49 | * Create list of TCP Connection Providers. Each provider connects to its specific port. 50 | */ 51 | OATPP_CREATE_COMPONENT(std::shared_ptr>>, connectionProviders)([this] { 52 | 53 | auto providers = std::make_shared>>(); 54 | 55 | const char* host = m_cmdArgs.getNamedArgumentValue("-h", "127.0.0.1"); 56 | v_uint16 basePort = oatpp::utils::Conversion::strToInt32(m_cmdArgs.getNamedArgumentValue("--bp", "8000")); 57 | v_uint16 portsCount = oatpp::utils::Conversion::strToInt32(m_cmdArgs.getNamedArgumentValue("--pc", "100")); 58 | 59 | for(v_uint16 i = 0; i < portsCount; i++) { 60 | auto provider = oatpp::network::tcp::client::ConnectionProvider::createShared({host, (v_uint16)(basePort + i)}); 61 | providers->push_back(provider); 62 | } 63 | 64 | return providers; 65 | 66 | }()); 67 | 68 | 69 | }; 70 | 71 | #endif /* AppComponent_hpp */ 72 | -------------------------------------------------------------------------------- /client/src/ClientSocketListener.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Leonid on 2019-03-28. 3 | // 4 | 5 | #include "ClientSocketListener.hpp" 6 | 7 | std::atomic ClientSocketListener::MESSAGES(0); 8 | std::atomic ClientSocketListener::FRAMES(0); 9 | 10 | std::atomic ClientCoroutine::SOCKETS(0); 11 | 12 | std::list> ClientCoroutine::SOCKETS_LIST; 13 | std::mutex ClientCoroutine::SOCKETS_LIST_MUTEX; -------------------------------------------------------------------------------- /client/src/ClientSocketListener.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Leonid on 2019-03-28. 3 | // 4 | 5 | #ifndef ClientSocketListener_hpp 6 | #define ClientSocketListener_hpp 7 | 8 | #include "oatpp/async/Executor.hpp" 9 | 10 | #include "oatpp-websocket/Connector.hpp" 11 | #include "oatpp-websocket/AsyncWebSocket.hpp" 12 | 13 | #include "oatpp/macro/component.hpp" 14 | #include "oatpp/base/Log.hpp" 15 | 16 | #include 17 | 18 | /** 19 | * WebSocket listener listens on incoming WebSocket events. 20 | */ 21 | class ClientSocketListener : public oatpp::websocket::AsyncWebSocket::Listener{ 22 | public: 23 | /** 24 | * Counter for received messages - counts complete messages only. 25 | */ 26 | static std::atomic MESSAGES; 27 | 28 | /** 29 | * Counter for received frames. 30 | */ 31 | static std::atomic FRAMES; 32 | private: 33 | 34 | /** 35 | * Buffer for messages. Needed for multi-frame messages. 36 | */ 37 | oatpp::data::stream::BufferOutputStream m_messageBuffer; 38 | public: 39 | 40 | /** 41 | * Called on "ping" frame. 42 | */ 43 | CoroutineStarter onPing(const std::shared_ptr& socket, const oatpp::String& message) override { 44 | ++ FRAMES; 45 | return socket->sendPongAsync(message); 46 | } 47 | 48 | /** 49 | * Called on "pong" frame 50 | */ 51 | CoroutineStarter onPong(const std::shared_ptr& socket, const oatpp::String& message) override { 52 | ++ FRAMES; 53 | return nullptr; // do nothing 54 | } 55 | 56 | /** 57 | * Called on "close" frame 58 | */ 59 | CoroutineStarter onClose(const std::shared_ptr& socket, v_uint16 code, const oatpp::String& message) override { 60 | ++ FRAMES; 61 | return nullptr; // do nothing 62 | } 63 | 64 | /** 65 | * Called on each message frame. After the last message will be called once-again with size == 0 to designate end of the message. 66 | */ 67 | CoroutineStarter readMessage(const std::shared_ptr& socket, v_uint8 opcode, p_char8 data, oatpp::v_io_size size) override { 68 | 69 | if(size == 0) { // message transfer finished 70 | 71 | auto wholeMessage = m_messageBuffer.toString(); 72 | // TODO do something with message 73 | m_messageBuffer.setCurrentPosition(0); 74 | ++ MESSAGES; 75 | 76 | } else if(size > 0) { // message frame received 77 | ++ FRAMES; 78 | m_messageBuffer.writeSimple(data, size); 79 | } 80 | 81 | return nullptr; // do nothing 82 | 83 | } 84 | 85 | }; 86 | 87 | /** 88 | * Coroutine which generates load. 89 | */ 90 | class ClientSenderCoroutine : public oatpp::async::Coroutine { 91 | private: 92 | /** 93 | * WebSocket connection to load. 94 | */ 95 | std::shared_ptr m_socket; 96 | public: 97 | 98 | ClientSenderCoroutine(const std::shared_ptr& socket) 99 | : m_socket(socket) 100 | {} 101 | 102 | Action act() override { 103 | /* Send "hello!" message. Once message sent, send another one. */ 104 | return m_socket->sendOneFrameTextAsync("hello!").next(yieldTo(&ClientSenderCoroutine::act)); 105 | } 106 | 107 | }; 108 | 109 | /** 110 | * Establish WebSocket connection and listen on WebSocket. 111 | */ 112 | class ClientCoroutine : public oatpp::async::Coroutine { 113 | public: 114 | /** 115 | * Counter for established WebSocket connections. 116 | */ 117 | static std::atomic SOCKETS; 118 | 119 | /** 120 | * List of established WebSocket connections. 121 | */ 122 | static std::list> SOCKETS_LIST; 123 | private: 124 | static std::mutex SOCKETS_LIST_MUTEX; 125 | private: 126 | /** 127 | * WebSocket connector. Used to connect on server/ws endpoint and upgrade connection to WebSocket. 128 | */ 129 | std::shared_ptr m_connector; 130 | 131 | /** 132 | * Established WebSocket connection. 133 | */ 134 | std::shared_ptr m_socket; 135 | public: 136 | 137 | ClientCoroutine(const std::shared_ptr& connector) 138 | : m_connector(connector) 139 | , m_socket(nullptr) 140 | {} 141 | 142 | ~ClientCoroutine() { 143 | if(m_socket) { 144 | -- SOCKETS; 145 | } 146 | } 147 | 148 | Action act() override { 149 | /* Establish WebSocket connection */ 150 | return m_connector->connectAsync("ws").callbackTo(&ClientCoroutine::onConnected); 151 | } 152 | 153 | 154 | Action onConnected(const oatpp::provider::ResourceHandle& connection) { 155 | ++ SOCKETS; 156 | m_socket = oatpp::websocket::AsyncWebSocket::createShared(connection, true /* maskOutgoingMessages for clients always true */); 157 | 158 | /* In this particular case we create one WebSocketListener per each connection */ 159 | /* Which may be redundant in many cases */ 160 | m_socket->setListener(std::make_shared()); 161 | 162 | { 163 | std::lock_guard guard(SOCKETS_LIST_MUTEX); 164 | SOCKETS_LIST.push_back(m_socket); 165 | } 166 | 167 | /* Listen on WebSocket. */ 168 | /* When WebSocket is closed - call onFinishListen() */ 169 | return m_socket->listenAsync().next(yieldTo(&ClientCoroutine::onFinishListen)); 170 | } 171 | 172 | Action onFinishListen() { 173 | OATPP_ASSERT(false && "onFinishListen - closed WebSocket considered to be an error in this benchmark"); 174 | return finish(); 175 | } 176 | 177 | Action handleError(Error* error) override { 178 | if(error) { 179 | OATPP_LOGd("ClientCoroutine", "Error. {}", error->what()); 180 | } 181 | 182 | OATPP_ASSERT(false && "handleError - any error in WebSocket communication is considered to be fatal in this benchmark"); 183 | return error; 184 | } 185 | 186 | }; 187 | 188 | 189 | #endif //ClientSocketListener_hpp 190 | -------------------------------------------------------------------------------- /client/src/Logger.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Logger.hpp 3 | // oatpp-web-starter 4 | // 5 | // Created by Leonid on 3/2/18. 6 | // Copyright © 2018 lganzzzo. All rights reserved. 7 | // 8 | 9 | #include "Logger.hpp" 10 | 11 | #include 12 | 13 | void Logger::log(v_uint32 priority, const std::string& tag, const std::string& message) { 14 | std::lock_guard lock(m_lock); 15 | std::cout << tag << ":" << message << "\n"; 16 | } -------------------------------------------------------------------------------- /client/src/Logger.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Logger.hpp 3 | // oatpp-web-starter 4 | // 5 | // Created by Leonid on 3/2/18. 6 | // Copyright © 2018 lganzzzo. All rights reserved. 7 | // 8 | 9 | #ifndef Logger_hpp 10 | #define Logger_hpp 11 | 12 | #include "oatpp/concurrency/SpinLock.hpp" 13 | #include "oatpp/Environment.hpp" 14 | 15 | /** 16 | * Environment logger. 17 | * All logs from OATPP_LOGV(...), OATPP_LOGD(...), OATPP_LOGE(...) go here 18 | * You may ignore or redirect them here 19 | */ 20 | class Logger : public oatpp::Logger { 21 | private: 22 | oatpp::concurrency::SpinLock m_lock; 23 | public: 24 | 25 | void log(v_uint32 priority, const std::string& tag, const std::string& message) override; 26 | 27 | }; 28 | 29 | #endif /* Logger_hpp */ 30 | -------------------------------------------------------------------------------- /client/src/Meter.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Leonid on 2019-03-28. 3 | // 4 | 5 | #ifndef Meter_hpp 6 | #define Meter_hpp 7 | 8 | #include "oatpp/Environment.hpp" 9 | 10 | #include 11 | 12 | /** 13 | * Class to calculate stats. 14 | */ 15 | class Meter { 16 | private: 17 | std::queue m_ticks; // in micro 18 | std::queue m_values; 19 | v_int32 m_maxPoints; 20 | public: 21 | 22 | Meter(v_int32 maxPoints) 23 | : m_maxPoints(maxPoints) 24 | {} 25 | 26 | void addPoint(v_int64 tick, v_int64 value) { 27 | m_ticks.push(tick); 28 | m_values.push(value); 29 | if(m_ticks.size() > m_maxPoints) { 30 | m_ticks.pop(); 31 | m_values.pop(); 32 | } 33 | } 34 | 35 | v_float64 getRatio() { 36 | if(m_ticks.size() > 1) { 37 | v_float64 ticksDiff = m_ticks.back() - m_ticks.front(); 38 | v_float64 valueDiff = m_values.back() - m_values.front(); 39 | return valueDiff / ticksDiff; 40 | } 41 | return 0; 42 | } 43 | 44 | v_float64 perSecond() { 45 | return getRatio() * 1000 * 1000; 46 | } 47 | 48 | v_float64 perMinute() { 49 | return getRatio() * 60 * 1000 * 1000; 50 | } 51 | 52 | 53 | }; 54 | 55 | 56 | #endif //Meter_hpp 57 | -------------------------------------------------------------------------------- /client/test/tests.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Logger.hpp" 3 | 4 | #include "oatpp-test/UnitTest.hpp" 5 | #include 6 | 7 | namespace { 8 | 9 | void runTests() { 10 | 11 | } 12 | 13 | } 14 | 15 | int main() { 16 | 17 | oatpp::Environment::init(); 18 | 19 | runTests(); 20 | 21 | /* Print how much objects were created during app running, and what have left-probably leaked */ 22 | /* Disable object counting for release builds using '-D OATPP_DISABLE_ENV_OBJECT_COUNTERS' flag for better performance */ 23 | std::cout << "\nEnvironment:\n"; 24 | std::cout << "objectsCount = " << oatpp::Environment::getObjectsCount() << "\n"; 25 | std::cout << "objectsCreated = " << oatpp::Environment::getObjectsCreated() << "\n\n"; 26 | 27 | OATPP_ASSERT(oatpp::Environment::getObjectsCount() == 0); 28 | 29 | oatpp::Environment::destroy(); 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /client/utility/install-oatpp-modules.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -rf tmp 4 | 5 | mkdir tmp 6 | cd tmp 7 | 8 | ########################################################## 9 | ## install oatpp 10 | 11 | MODULE_NAME="oatpp" 12 | 13 | git clone --depth=1 https://github.com/oatpp/$MODULE_NAME 14 | 15 | cd $MODULE_NAME 16 | mkdir build 17 | cd build 18 | 19 | cmake .. 20 | make install 21 | 22 | cd ../../ 23 | 24 | ########################################################## 25 | ## install oatpp-websocket 26 | 27 | MODULE_NAME="oatpp-websocket" 28 | 29 | git clone --depth=1 https://github.com/oatpp/$MODULE_NAME 30 | 31 | cd $MODULE_NAME 32 | mkdir build 33 | cd build 34 | 35 | cmake .. 36 | make install 37 | 38 | cd ../../ 39 | 40 | ########################################################## 41 | 42 | cd ../ 43 | 44 | rm -rf tmp -------------------------------------------------------------------------------- /prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | apt-get install -y cmake 4 | apt-get install -y build-essential 5 | 6 | mkdir -p ./client/build 7 | mkdir -p ./server/build 8 | 9 | mkdir ./tmp 10 | 11 | cd tmp 12 | 13 | ######################################## 14 | # oatpp 15 | 16 | git clone -b master https://github.com/oatpp/oatpp 17 | 18 | cd oatpp 19 | mkdir build && cd $_ 20 | cmake -DOATPP_DISABLE_POOL_ALLOCATIONS=ON -DOATPP_DISABLE_ENV_OBJECT_COUNTERS=ON -DOATPP_THREAD_DISTRIBUTED_MEM_POOL_SHARDS_COUNT=1 -DCMAKE_BUILD_TYPE=Release .. 21 | 22 | make 23 | make install 24 | 25 | cd ../../ 26 | 27 | ######################################## 28 | # oatpp-websocket 29 | 30 | git clone -b master https://github.com/oatpp/oatpp-websocket 31 | 32 | cd oatpp-websocket 33 | mkdir build && cd $_ 34 | cmake .. 35 | 36 | make 37 | make install 38 | 39 | cd ../../ 40 | 41 | ######################################## 42 | 43 | cd ../ 44 | -------------------------------------------------------------------------------- /server/.dockerignore: -------------------------------------------------------------------------------- 1 | build/ -------------------------------------------------------------------------------- /server/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | 3 | set(project_name wsb-server) ## rename your project here 4 | 5 | project(${project_name}) 6 | 7 | set(CMAKE_CXX_STANDARD 17) 8 | 9 | include_directories(src) 10 | 11 | add_library(${project_name}-lib 12 | src/AppComponent.hpp 13 | src/Logger.hpp 14 | src/Logger.cpp 15 | src/controller/MyController.hpp 16 | src/controller/WebSocketListener.cpp 17 | src/controller/WebSocketListener.hpp 18 | ) 19 | 20 | ## link libs 21 | 22 | find_package(oatpp 1.4.0 REQUIRED) 23 | find_package(oatpp-websocket 1.4.0 REQUIRED) 24 | 25 | target_link_libraries(${project_name}-lib 26 | PUBLIC oatpp::oatpp 27 | PUBLIC oatpp::oatpp-test 28 | PUBLIC oatpp::oatpp-websocket 29 | ) 30 | 31 | ## add executables 32 | 33 | add_executable(${project_name}-exe 34 | src/App.cpp 35 | ) 36 | target_link_libraries(${project_name}-exe ${project_name}-lib) 37 | add_dependencies(${project_name}-exe ${project_name}-lib) 38 | 39 | add_executable(${project_name}-test 40 | test/tests.cpp 41 | test/WebSocketTest.cpp 42 | test/WebSocketTest.hpp 43 | ) 44 | 45 | target_link_libraries(${project_name}-test ${project_name}-lib) 46 | add_dependencies(${project_name}-test ${project_name}-lib) 47 | 48 | set_target_properties(${project_name}-lib ${project_name}-exe ${project_name}-test PROPERTIES 49 | CXX_STANDARD 17 50 | CXX_EXTENSIONS OFF 51 | CXX_STANDARD_REQUIRED ON 52 | LINKER_LANGUAGE CXX 53 | ) 54 | 55 | enable_testing() 56 | add_test(tests ${project_name}-test) 57 | -------------------------------------------------------------------------------- /server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM lganzzzo/alpine-cmake:latest 2 | 3 | ADD . /service 4 | 5 | WORKDIR /service/utility 6 | 7 | RUN ./install-oatpp-modules.sh 8 | 9 | WORKDIR /service/build 10 | 11 | RUN cmake .. 12 | RUN make 13 | 14 | EXPOSE 8000 8000 15 | 16 | ENTRYPOINT ["./wsb-server-exe"] 17 | -------------------------------------------------------------------------------- /server/src/App.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // main.cpp 3 | // web-starter-project 4 | // 5 | // Created by Leonid on 2/12/18. 6 | // Copyright © 2018 oatpp. All rights reserved. 7 | // 8 | 9 | #include "./controller/WebSocketListener.hpp" 10 | #include "./controller/MyController.hpp" 11 | #include "./AppComponent.hpp" 12 | #include "./Logger.hpp" 13 | #include "./Meter.hpp" 14 | 15 | #include "oatpp/network/Server.hpp" 16 | 17 | #include 18 | #include 19 | 20 | /** 21 | * Print Stats. 22 | */ 23 | void printStats() { 24 | 25 | OATPP_LOGd("Status", "\n\n\n\n\n"); 26 | 27 | v_int64 lastTickCount = oatpp::Environment::getMicroTickCount(); 28 | 29 | Meter framesMeter(60 * 2); 30 | Meter messagesMeter(60 * 2); 31 | 32 | while(true) { 33 | 34 | v_int64 tickCount = oatpp::Environment::getMicroTickCount(); 35 | framesMeter.addPoint(tickCount, WebSocketListener::FRAMES.load()); 36 | messagesMeter.addPoint(tickCount, WebSocketListener::MESSAGES.load()); 37 | 38 | OATPP_LOGd("\33[2K\r\033[A\033[A\033[A\033[A\033[A" 39 | "SOCKETS", " {} ", WebSocketInstanceListener::SOCKETS.load()); 40 | OATPP_LOGd("FRAMES_TOTAL", " {} ", WebSocketListener::FRAMES.load()); 41 | OATPP_LOGd("MESSAGES_TOTAL", " {} ", WebSocketListener::MESSAGES.load()); 42 | OATPP_LOGd("FRAMES_PER_MIN", " {} ", framesMeter.perMinute()); 43 | OATPP_LOGd("MESSAGES_PER_MIN", " {} ", messagesMeter.perMinute()); 44 | std::this_thread::sleep_for(std::chrono::milliseconds(500)); 45 | 46 | } 47 | 48 | }; 49 | 50 | void run(const oatpp::base::CommandLineArguments& args) { 51 | 52 | AppComponent components(args); // Create scope Environment components 53 | 54 | /* create ApiControllers and add endpoints to router */ 55 | auto router = components.httpRouter.getObject(); 56 | 57 | router->addController(MyController::createShared()); 58 | 59 | /* create servers */ 60 | OATPP_COMPONENT(std::shared_ptr>>, connectionProviders); 61 | 62 | std::list threads; 63 | 64 | for(auto& provider : *connectionProviders) { 65 | threads.push_back(std::thread([provider]{ 66 | OATPP_COMPONENT(std::shared_ptr, handler); 67 | oatpp::network::Server server(provider, handler); 68 | server.run(); 69 | })); 70 | } 71 | 72 | std::thread statThread([]{ 73 | printStats(); 74 | }); 75 | 76 | for(auto& thread : threads) { 77 | thread.join(); 78 | } 79 | 80 | statThread.join(); 81 | 82 | } 83 | 84 | /** 85 | * main 86 | */ 87 | int main(int argc, const char * argv[]) { 88 | 89 | oatpp::Environment::init(); 90 | 91 | run(oatpp::base::CommandLineArguments(argc, argv)); 92 | 93 | /* Print how much objects were created during app running, and what have left-probably leaked */ 94 | /* Disable object counting for release builds using '-D OATPP_DISABLE_ENV_OBJECT_COUNTERS' flag for better performance */ 95 | std::cout << "\nEnvironment:\n"; 96 | std::cout << "objectsCount = " << oatpp::Environment::getObjectsCount() << "\n"; 97 | std::cout << "objectsCreated = " << oatpp::Environment::getObjectsCreated() << "\n\n"; 98 | 99 | oatpp::Environment::destroy(); 100 | 101 | return 0; 102 | } 103 | -------------------------------------------------------------------------------- /server/src/AppComponent.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // AppComponent.hpp 3 | // oatpp-web-starter 4 | // 5 | // Created by Leonid on 3/2/18. 6 | // Copyright © 2018 lganzzzo. All rights reserved. 7 | // 8 | 9 | #ifndef AppComponent_hpp 10 | #define AppComponent_hpp 11 | 12 | #include "controller/WebSocketListener.hpp" 13 | 14 | #include "oatpp-websocket/AsyncConnectionHandler.hpp" 15 | 16 | #include "oatpp/web/server/AsyncHttpConnectionHandler.hpp" 17 | #include "oatpp/web/server/HttpRouter.hpp" 18 | #include "oatpp/network/tcp/server/ConnectionProvider.hpp" 19 | 20 | #include "oatpp/json/ObjectMapper.hpp" 21 | 22 | #include "oatpp/macro/component.hpp" 23 | 24 | #include "oatpp/base/CommandLineArguments.hpp" 25 | #include "oatpp/utils/Conversion.hpp" 26 | 27 | #include 28 | 29 | /** 30 | * Class which creates and holds Application components and registers components in oatpp::Environment 31 | * Order of components initialization is from top to bottom 32 | */ 33 | class AppComponent { 34 | private: 35 | oatpp::base::CommandLineArguments m_cmdArgs; 36 | public: 37 | AppComponent(const oatpp::base::CommandLineArguments& cmdArgs) 38 | : m_cmdArgs(cmdArgs) 39 | {} 40 | public: 41 | 42 | /** 43 | * Create List of 100 Connection Providers listening on ports from 8000..8099 44 | */ 45 | OATPP_CREATE_COMPONENT(std::shared_ptr>>, connectionProviders)([this] { 46 | auto providers = std::make_shared>>(); 47 | v_uint16 basePort = oatpp::utils::Conversion::strToInt32(m_cmdArgs.getNamedArgumentValue("--bp", "8000")); 48 | v_uint16 portsCount = oatpp::utils::Conversion::strToInt32(m_cmdArgs.getNamedArgumentValue("--pc", "100")); 49 | for(v_uint16 i = 0; i < portsCount; i++) { 50 | OATPP_LOGd("AppComponent", "Connection Provider for port: {}", basePort + i); 51 | auto provider = oatpp::network::tcp::server::ConnectionProvider::createShared({"0.0.0.0", (v_uint16)(basePort + i)}); 52 | providers->push_back(provider); 53 | } 54 | return providers; 55 | }()); 56 | 57 | /** 58 | * Create Router component 59 | */ 60 | OATPP_CREATE_COMPONENT(std::shared_ptr, httpRouter)([] { 61 | return oatpp::web::server::HttpRouter::createShared(); 62 | }()); 63 | 64 | /** 65 | * Create HTTP ConnectionHandler component which uses Router component to route requests 66 | */ 67 | OATPP_CREATE_COMPONENT(std::shared_ptr, serverConnectionHandler)([] { 68 | OATPP_COMPONENT(std::shared_ptr, router); // get Router component 69 | return oatpp::web::server::AsyncHttpConnectionHandler::createShared(router, 4); 70 | }()); 71 | 72 | /** 73 | * Create ObjectMapper component to serialize/deserialize DTOs in Contoller's API 74 | */ 75 | OATPP_CREATE_COMPONENT(std::shared_ptr, apiObjectMapper)([] { 76 | return std::make_shared(); 77 | }()); 78 | 79 | /** 80 | * Create AsyncExecutor for WebSocket Asynchronous Connection Handler 81 | */ 82 | OATPP_CREATE_COMPONENT(std::shared_ptr, executor)([this] { 83 | v_int32 threadsProc = oatpp::utils::Conversion::strToInt32(m_cmdArgs.getNamedArgumentValue("--tp", "8")); 84 | v_int32 threadsIO = oatpp::utils::Conversion::strToInt32(m_cmdArgs.getNamedArgumentValue("--tio", "2")); 85 | v_int32 threadsTimer = oatpp::utils::Conversion::strToInt32(m_cmdArgs.getNamedArgumentValue("--tt", "1")); 86 | OATPP_LOGd("Server", "Executor: tp={}, tio={}, tt={}", threadsProc, threadsIO, threadsTimer); 87 | return std::make_shared(threadsProc, threadsIO, threadsTimer); 88 | }()); 89 | 90 | /** 91 | * Create websocket connection handler 92 | */ 93 | OATPP_CREATE_COMPONENT(std::shared_ptr, websocketConnectionHandler)([] { 94 | OATPP_COMPONENT(std::shared_ptr, executor); 95 | auto connectionHandler = oatpp::websocket::AsyncConnectionHandler::createShared(executor); 96 | connectionHandler->setSocketInstanceListener(std::make_shared()); 97 | return connectionHandler; 98 | }()); 99 | 100 | }; 101 | 102 | #endif /* AppComponent_hpp */ 103 | -------------------------------------------------------------------------------- /server/src/Logger.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Logger.hpp 3 | // oatpp-web-starter 4 | // 5 | // Created by Leonid on 3/2/18. 6 | // Copyright © 2018 lganzzzo. All rights reserved. 7 | // 8 | 9 | #include "Logger.hpp" 10 | 11 | #include 12 | 13 | void Logger::log(v_uint32 priority, const std::string& tag, const std::string& message) { 14 | std::lock_guard lock(m_lock); 15 | std::cout << tag << ":" << message << "\n"; 16 | } -------------------------------------------------------------------------------- /server/src/Logger.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Logger.hpp 3 | // oatpp-web-starter 4 | // 5 | // Created by Leonid on 3/2/18. 6 | // Copyright © 2018 lganzzzo. All rights reserved. 7 | // 8 | 9 | #ifndef Logger_hpp 10 | #define Logger_hpp 11 | 12 | #include "oatpp/concurrency/SpinLock.hpp" 13 | #include "oatpp/Environment.hpp" 14 | 15 | /** 16 | * Environment logger. 17 | * All logs from OATPP_LOGV(...), OATPP_LOGD(...), OATPP_LOGE(...) go here 18 | * You may ignore or redirect them here 19 | */ 20 | class Logger : public oatpp::Logger { 21 | private: 22 | oatpp::concurrency::SpinLock m_lock; 23 | public: 24 | 25 | void log(v_uint32 priority, const std::string& tag, const std::string& message) override; 26 | 27 | }; 28 | 29 | #endif /* Logger_hpp */ 30 | -------------------------------------------------------------------------------- /server/src/Meter.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Leonid on 2019-03-28. 3 | // 4 | 5 | #ifndef Meter_hpp 6 | #define Meter_hpp 7 | 8 | #include "oatpp/Environment.hpp" 9 | 10 | #include 11 | 12 | /** 13 | * Class to calculate stats. 14 | */ 15 | class Meter { 16 | private: 17 | std::queue m_ticks; // in micro 18 | std::queue m_values; 19 | v_int32 m_maxPoints; 20 | public: 21 | 22 | Meter(v_int32 maxPoints) 23 | : m_maxPoints(maxPoints) 24 | {} 25 | 26 | void addPoint(v_int64 tick, v_int64 value) { 27 | m_ticks.push(tick); 28 | m_values.push(value); 29 | if(m_ticks.size() > m_maxPoints) { 30 | m_ticks.pop(); 31 | m_values.pop(); 32 | } 33 | } 34 | 35 | v_float64 getRatio() { 36 | if(m_ticks.size() > 1) { 37 | v_float64 ticksDiff = m_ticks.back() - m_ticks.front(); 38 | v_float64 valueDiff = m_values.back() - m_values.front(); 39 | return valueDiff / ticksDiff; 40 | } 41 | return 0; 42 | } 43 | 44 | v_float64 perSecond() { 45 | return getRatio() * 1000 * 1000; 46 | } 47 | 48 | v_float64 perMinute() { 49 | return getRatio() * 60 * 1000 * 1000; 50 | } 51 | 52 | 53 | }; 54 | 55 | 56 | #endif //Meter_hpp 57 | -------------------------------------------------------------------------------- /server/src/controller/MyController.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // MyController.hpp 3 | // web-starter-project 4 | // 5 | // Created by Leonid on 2/12/18. 6 | // Copyright © 2018 oatpp. All rights reserved. 7 | // 8 | 9 | #ifndef MyController_hpp 10 | #define MyController_hpp 11 | 12 | #include "oatpp-websocket/Handshaker.hpp" 13 | #include "oatpp-websocket/AsyncConnectionHandler.hpp" 14 | 15 | #include "oatpp/web/server/api/ApiController.hpp" 16 | #include "oatpp/json/ObjectMapper.hpp" 17 | #include "oatpp/macro/codegen.hpp" 18 | #include "oatpp/macro/component.hpp" 19 | 20 | 21 | #include OATPP_CODEGEN_BEGIN(ApiController) //<-- codegen begin 22 | 23 | /** 24 | * Controller with WebSocket-connect endpoint. 25 | */ 26 | class MyController : public oatpp::web::server::api::ApiController { 27 | private: 28 | typedef MyController __ControllerType; 29 | private: 30 | OATPP_COMPONENT(std::shared_ptr, websocketConnectionHandler); 31 | protected: 32 | MyController(const std::shared_ptr& objectMapper) 33 | : oatpp::web::server::api::ApiController(objectMapper) 34 | {} 35 | public: 36 | 37 | /** 38 | * Inject @objectMapper component here as default parameter 39 | * Do not return bare Controllable* object! use shared_ptr! 40 | */ 41 | static std::shared_ptr createShared(OATPP_COMPONENT(std::shared_ptr, 42 | objectMapper)){ 43 | return std::shared_ptr(new MyController(objectMapper)); 44 | } 45 | 46 | 47 | ENDPOINT_ASYNC("GET", "/", Root) { 48 | 49 | ENDPOINT_ASYNC_INIT(Root) 50 | 51 | const char* pageTemplate = 52 | "" 53 | "" 54 | "" 55 | "" 56 | "" 57 | "

Hello oatpp WebSocket benchmark!

" 58 | "

" 59 | "You may connect WebSocket client on '<host>:<port>/ws'" 60 | "

" 61 | "" 62 | ""; 63 | 64 | Action act() override { 65 | return _return(controller->createResponse(Status::CODE_200, pageTemplate)); 66 | } 67 | 68 | }; 69 | 70 | ENDPOINT_ASYNC("GET", "ws", WS) { 71 | 72 | ENDPOINT_ASYNC_INIT(WS) 73 | 74 | Action act() override { 75 | auto response = oatpp::websocket::Handshaker::serversideHandshake(request->getHeaders(), controller->websocketConnectionHandler); 76 | return _return(response); 77 | } 78 | 79 | }; 80 | 81 | // TODO Insert Your endpoints here !!! 82 | 83 | }; 84 | 85 | #include OATPP_CODEGEN_END(ApiController) //<-- codegen end 86 | 87 | #endif /* MyController_hpp */ 88 | -------------------------------------------------------------------------------- /server/src/controller/WebSocketListener.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Leonid on 2019-03-25. 3 | // 4 | 5 | #include "WebSocketListener.hpp" 6 | 7 | std::atomic WebSocketListener::MESSAGES(0); 8 | std::atomic WebSocketListener::FRAMES(0); 9 | 10 | std::atomic WebSocketInstanceListener::SOCKETS(0); -------------------------------------------------------------------------------- /server/src/controller/WebSocketListener.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Leonid on 2019-03-25. 3 | // 4 | 5 | #ifndef MY_PROJECT_WEBSOCKETLISTENER_HPP 6 | #define MY_PROJECT_WEBSOCKETLISTENER_HPP 7 | 8 | #include "oatpp-websocket/AsyncConnectionHandler.hpp" 9 | #include "oatpp-websocket/AsyncWebSocket.hpp" 10 | 11 | /** 12 | * WebSocket listener listens on incoming WebSocket events. 13 | */ 14 | class WebSocketListener : public oatpp::websocket::AsyncWebSocket::Listener { 15 | public: 16 | /** 17 | * Counter for received messages - counts complete messages only. 18 | */ 19 | static std::atomic MESSAGES; 20 | 21 | /** 22 | * Counter for received frames. 23 | */ 24 | static std::atomic FRAMES; 25 | private: 26 | 27 | /** 28 | * Buffer for messages. Needed for multi-frame messages. 29 | */ 30 | oatpp::data::stream::BufferOutputStream m_messageBuffer; 31 | public: 32 | 33 | /** 34 | * Called on "ping" frame. 35 | */ 36 | CoroutineStarter onPing(const std::shared_ptr& socket, const oatpp::String& message) override { 37 | ++ FRAMES; 38 | return socket->sendPongAsync(message); 39 | } 40 | 41 | /** 42 | * Called on "pong" frame 43 | */ 44 | CoroutineStarter onPong(const std::shared_ptr& socket, const oatpp::String& message) override { 45 | ++ FRAMES; 46 | return nullptr; // do nothing 47 | } 48 | 49 | /** 50 | * Called on "close" frame 51 | */ 52 | CoroutineStarter onClose(const std::shared_ptr& socket, v_uint16 code, const oatpp::String& message) override { 53 | ++ FRAMES; 54 | return nullptr; // do nothing 55 | } 56 | 57 | /** 58 | * Called on each message frame. After the last message will be called once-again with size == 0 to designate end of the message. 59 | */ 60 | CoroutineStarter readMessage(const std::shared_ptr& socket, v_uint8 opcode, p_char8 data, oatpp::v_io_size size) override { 61 | 62 | if(size == 0) { // message transfer finished 63 | 64 | auto wholeMessage = m_messageBuffer.toString(); 65 | m_messageBuffer.setCurrentPosition(0); 66 | ++ MESSAGES; 67 | 68 | /* Send message in reply */ 69 | return socket->sendOneFrameTextAsync( "Hello from oatpp!: " + wholeMessage); 70 | 71 | } else if(size > 0) { // message frame received 72 | ++ FRAMES; 73 | m_messageBuffer.writeSimple(data, size); 74 | } 75 | 76 | return nullptr; // do nothing 77 | 78 | } 79 | 80 | }; 81 | 82 | /** 83 | * Listener on new WebSocket connections. 84 | */ 85 | class WebSocketInstanceListener : public oatpp::websocket::AsyncConnectionHandler::SocketInstanceListener { 86 | public: 87 | /** 88 | * Counter for connected clients. 89 | */ 90 | static std::atomic SOCKETS; 91 | public: 92 | 93 | /** 94 | * Called when socket is created 95 | */ 96 | void onAfterCreate_NonBlocking(const std::shared_ptr& socket, const std::shared_ptr& params) override { 97 | ++ SOCKETS; 98 | 99 | oatpp::websocket::Config config; 100 | config.readBufferSize = 64; 101 | 102 | socket->setConfig(config); 103 | 104 | /* In this particular case we create one WebSocketListener per each connection */ 105 | /* Which may be redundant in many cases */ 106 | socket->setListener(std::make_shared()); 107 | } 108 | 109 | /** 110 | * Called before socket instance is destroyed. 111 | */ 112 | void onBeforeDestroy_NonBlocking(const std::shared_ptr& socket) override { 113 | -- SOCKETS; 114 | } 115 | 116 | }; 117 | 118 | 119 | #endif //MY_PROJECT_WEBSOCKETLISTENER_HPP 120 | -------------------------------------------------------------------------------- /server/test/WebSocketTest.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Leonid on 2019-03-25. 3 | // 4 | 5 | #include "WebSocketTest.hpp" 6 | 7 | #include "controller/MyController.hpp" 8 | #include "controller/WebSocketListener.hpp" 9 | 10 | #include "oatpp-websocket/Connector.hpp" 11 | #include "oatpp-websocket/AsyncConnectionHandler.hpp" 12 | 13 | #include "oatpp/web/server/AsyncHttpConnectionHandler.hpp" 14 | 15 | #include "oatpp/network/virtual_/client/ConnectionProvider.hpp" 16 | #include "oatpp/network/virtual_/server/ConnectionProvider.hpp" 17 | #include "oatpp/network/virtual_/Interface.hpp" 18 | 19 | #include "oatpp-test/web/ClientServerTestRunner.hpp" 20 | 21 | #include "oatpp/macro/component.hpp" 22 | 23 | namespace { 24 | 25 | class TestComponent { 26 | public: 27 | 28 | OATPP_CREATE_COMPONENT(std::shared_ptr, executor)([] { 29 | return std::make_shared(2); 30 | }()); 31 | 32 | OATPP_CREATE_COMPONENT(std::shared_ptr, virtualInterface)([] { 33 | return oatpp::network::virtual_::Interface::obtainShared("virtualhost"); 34 | }()); 35 | 36 | OATPP_CREATE_COMPONENT(std::shared_ptr, serverConnectionProvider)([] { 37 | #ifdef OATPP_TEST_USE_PORT 38 | return oatpp::network::server::SimpleTCPConnectionProvider::createShared(OATPP_TEST_USE_PORT); 39 | #else 40 | OATPP_COMPONENT(std::shared_ptr, interface); 41 | return oatpp::network::virtual_::server::ConnectionProvider::createShared(interface); 42 | #endif 43 | }()); 44 | 45 | /** 46 | * Create Router component 47 | */ 48 | OATPP_CREATE_COMPONENT(std::shared_ptr, httpRouter)([] { 49 | return oatpp::web::server::HttpRouter::createShared(); 50 | }()); 51 | 52 | /** 53 | * Create ConnectionHandler component which uses Router component to route requests 54 | */ 55 | OATPP_CREATE_COMPONENT(std::shared_ptr, serverConnectionHandler)([] { 56 | OATPP_COMPONENT(std::shared_ptr, router); // get Router component 57 | OATPP_COMPONENT(std::shared_ptr, executor); 58 | return oatpp::web::server::AsyncHttpConnectionHandler::createShared(router, executor); 59 | }()); 60 | 61 | /** 62 | * Create ObjectMapper component to serialize/deserialize DTOs in Contoller's API 63 | */ 64 | OATPP_CREATE_COMPONENT(std::shared_ptr, apiObjectMapper)([] { 65 | auto mapper = std::make_shared(); 66 | mapper->deserializerConfig().mapper.allowUnknownFields = false; 67 | return mapper; 68 | }()); 69 | 70 | /** 71 | * Create websocket connection handler 72 | */ 73 | OATPP_CREATE_COMPONENT(std::shared_ptr, websocketConnectionHandler)([] { 74 | auto connectionHandler = oatpp::websocket::AsyncConnectionHandler::createShared(); 75 | connectionHandler->setSocketInstanceListener(std::make_shared()); 76 | return connectionHandler; 77 | }()); 78 | 79 | OATPP_CREATE_COMPONENT(std::shared_ptr, clientConnectionProvider)([this] { 80 | #ifdef OATPP_TEST_USE_PORT 81 | return oatpp::network::tcp::client::ConnectionProvider::createShared("127.0.0.1", OATPP_TEST_USE_PORT); 82 | #else 83 | OATPP_COMPONENT(std::shared_ptr, interface); 84 | return oatpp::network::virtual_::client::ConnectionProvider::createShared(interface); 85 | #endif 86 | }()); 87 | 88 | OATPP_CREATE_COMPONENT(std::shared_ptr, connector)([] { 89 | OATPP_COMPONENT(std::shared_ptr, clientConnectionProvider); 90 | return oatpp::websocket::Connector::createShared(clientConnectionProvider); 91 | }()); 92 | 93 | }; 94 | 95 | class ClientSocketListener : public oatpp::websocket::AsyncWebSocket::Listener{ 96 | private: 97 | oatpp::data::stream::BufferOutputStream m_messageBuffer; 98 | public: 99 | 100 | CoroutineStarter onPing(const std::shared_ptr& socket, const oatpp::String& message) override { 101 | return socket->sendPongAsync(message); 102 | } 103 | 104 | CoroutineStarter onPong(const std::shared_ptr& socket, const oatpp::String& message) override { 105 | return nullptr; 106 | } 107 | 108 | CoroutineStarter onClose(const std::shared_ptr& socket, v_uint16 code, const oatpp::String& message) override { 109 | return nullptr; 110 | } 111 | 112 | CoroutineStarter readMessage(const std::shared_ptr& socket, v_uint8 opcode, p_char8 data, oatpp::v_io_size size) override { 113 | if(size == 0) { 114 | auto wholeMessage = m_messageBuffer.toString(); 115 | m_messageBuffer.setCurrentPosition(0); 116 | OATPP_LOGd("client", "received {}", wholeMessage); 117 | } else if(size > 0) { 118 | m_messageBuffer.writeSimple(data, size); 119 | } 120 | return nullptr; 121 | } 122 | 123 | }; 124 | 125 | class ClientSenderCoroutine : public oatpp::async::Coroutine { 126 | private: 127 | std::shared_ptr m_socket; 128 | public: 129 | 130 | ClientSenderCoroutine(const std::shared_ptr& socket) 131 | : m_socket(socket) 132 | {} 133 | 134 | Action act() override { 135 | return waitRepeat(std::chrono::milliseconds(100)); 136 | //return m_socket->sendOneFrameTextAsync(this, waitRetry(), "hello!"); 137 | } 138 | 139 | }; 140 | 141 | class ClientCoroutine : public oatpp::async::Coroutine { 142 | private: 143 | OATPP_COMPONENT(std::shared_ptr, executor); 144 | OATPP_COMPONENT(std::shared_ptr, connector); 145 | std::shared_ptr socket; 146 | public: 147 | 148 | Action act() override { 149 | return connector->connectAsync("ws").callbackTo(&ClientCoroutine::onConnected); 150 | } 151 | 152 | Action onConnected(const oatpp::provider::ResourceHandle& connection) { 153 | socket = oatpp::websocket::AsyncWebSocket::createShared(connection, true); 154 | socket->setListener(std::make_shared()); 155 | executor->execute(socket); 156 | return socket->listenAsync().next(finish()); 157 | } 158 | 159 | }; 160 | 161 | } 162 | 163 | void WebSocketTest::onRun() { 164 | 165 | // TestComponent component; 166 | // 167 | // OATPP_COMPONENT(std::shared_ptr, executor); 168 | // 169 | // oatpp::test::web::ClientServerTestRunner runner; 170 | // 171 | // runner.addController(MyController::createShared()); 172 | // 173 | // runner.run([] { 174 | // 175 | // OATPP_COMPONENT(std::shared_ptr, executor); 176 | // 177 | // executor->execute(); 178 | // 179 | // executor->join(); 180 | // 181 | // 182 | // }, std::chrono::minutes(10)); 183 | 184 | OATPP_LOGd(TAG, "TODO - write tests"); 185 | 186 | } -------------------------------------------------------------------------------- /server/test/WebSocketTest.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Leonid on 2019-03-25. 3 | // 4 | 5 | #ifndef MY_PROJECT_WEBSOCKETTEST_HPP 6 | #define MY_PROJECT_WEBSOCKETTEST_HPP 7 | 8 | 9 | #include "oatpp-test/UnitTest.hpp" 10 | 11 | class WebSocketTest : public oatpp::test::UnitTest { 12 | public: 13 | 14 | WebSocketTest():UnitTest("TEST[WebSocketTest]"){} 15 | void onRun() override; 16 | 17 | }; 18 | 19 | 20 | #endif //MY_PROJECT_WEBSOCKETTEST_HPP 21 | -------------------------------------------------------------------------------- /server/test/tests.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Logger.hpp" 3 | 4 | #include "WebSocketTest.hpp" 5 | 6 | #include "oatpp-test/UnitTest.hpp" 7 | #include 8 | 9 | namespace { 10 | 11 | void runTests() { 12 | OATPP_RUN_TEST(WebSocketTest); 13 | } 14 | 15 | } 16 | 17 | int main() { 18 | 19 | oatpp::Environment::init(); 20 | 21 | runTests(); 22 | 23 | /* Print how much objects were created during app running, and what have left-probably leaked */ 24 | /* Disable object counting for release builds using '-D OATPP_DISABLE_ENV_OBJECT_COUNTERS' flag for better performance */ 25 | std::cout << "\nEnvironment:\n"; 26 | std::cout << "objectsCount = " << oatpp::Environment::getObjectsCount() << "\n"; 27 | std::cout << "objectsCreated = " << oatpp::Environment::getObjectsCreated() << "\n\n"; 28 | 29 | OATPP_ASSERT(oatpp::Environment::getObjectsCount() == 0); 30 | 31 | oatpp::Environment::destroy(); 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /server/utility/install-oatpp-modules.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -rf tmp 4 | 5 | mkdir tmp 6 | cd tmp 7 | 8 | ########################################################## 9 | ## install oatpp 10 | 11 | MODULE_NAME="oatpp" 12 | 13 | git clone --depth=1 https://github.com/oatpp/$MODULE_NAME 14 | 15 | cd $MODULE_NAME 16 | mkdir build 17 | cd build 18 | 19 | cmake .. 20 | make install 21 | 22 | cd ../../ 23 | 24 | ########################################################## 25 | ## install oatpp-websocket 26 | 27 | MODULE_NAME="oatpp-websocket" 28 | 29 | git clone --depth=1 https://github.com/oatpp/$MODULE_NAME 30 | 31 | cd $MODULE_NAME 32 | mkdir build 33 | cd build 34 | 35 | cmake .. 36 | make install 37 | 38 | cd ../../ 39 | 40 | ########################################################## 41 | 42 | cd ../ 43 | 44 | rm -rf tmp -------------------------------------------------------------------------------- /sock-config-4m.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sysctl -w fs.file-max=11000000 4 | sysctl -w fs.nr_open=11000000 5 | 6 | sysctl -w net.core.somaxconn=65535 7 | sysctl -w net.ipv4.tcp_max_syn_backlog=65535 8 | 9 | sysctl -w net.ipv4.ip_local_port_range="1025 65535" 10 | 11 | sysctl -w net.ipv4.tcp_mem="100000000 100000000 100000000" 12 | sysctl -w net.ipv4.tcp_rmem='4096 4096 4096' 13 | sysctl -w net.ipv4.tcp_wmem='4096 4096 4096' 14 | 15 | sysctl -w net.core.rmem_default=4096 16 | sysctl -w net.core.wmem_default=4608 17 | 18 | sysctl -w net.core.rmem_max=4096 19 | sysctl -w net.core.wmem_max=4608 20 | -------------------------------------------------------------------------------- /sock-config-5m.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sysctl -w fs.file-max=11000000 4 | sysctl -w fs.nr_open=11000000 5 | 6 | sysctl -w net.core.somaxconn=65535 7 | sysctl -w net.ipv4.tcp_max_syn_backlog=65535 8 | 9 | sysctl -w net.ipv4.ip_local_port_range="1025 65535" 10 | 11 | sysctl -w net.ipv4.tcp_mem="100000000 100000000 100000000" 12 | 13 | sysctl -w net.ipv4.tcp_rmem='2048 2048 2048' 14 | sysctl -w net.ipv4.tcp_wmem='4096 4096 4096' 15 | 16 | sysctl -w net.core.rmem_default=4096 17 | sysctl -w net.core.wmem_default=4608 18 | 19 | sysctl -w net.core.rmem_max=4096 20 | sysctl -w net.core.wmem_max=4608 21 | -------------------------------------------------------------------------------- /sock-config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sysctl -w fs.file-max=11000000 4 | sysctl -w fs.nr_open=11000000 5 | 6 | sysctl -w net.core.somaxconn=65535 7 | sysctl -w net.ipv4.tcp_max_syn_backlog=65535 8 | 9 | sysctl -w net.ipv4.ip_local_port_range="1025 65535" 10 | 11 | sysctl -w net.ipv4.tcp_mem="100000000 100000000 100000000" 12 | sysctl -w net.ipv4.tcp_rmem='4096 4096 4096' 13 | sysctl -w net.ipv4.tcp_wmem='4096 4096 4096' 14 | 15 | sysctl -w net.core.rmem_default=4096 16 | sysctl -w net.core.wmem_default=4608 17 | 18 | sysctl -w net.core.rmem_max=4096 19 | sysctl -w net.core.wmem_max=4608 20 | --------------------------------------------------------------------------------