├── .clang-tidy ├── .gitignore ├── .travis.yml ├── CMakeLists.txt ├── Cppnet.sln ├── Cppnet.vcxproj ├── Cppnet.vcxproj.filters ├── LICENSE ├── README.md ├── README_cn.md ├── TODO.md ├── build.sh ├── common ├── CMakeLists.txt ├── alloter │ ├── alloter_interface.h │ ├── normal_alloter.cpp │ ├── normal_alloter.h │ ├── pool_alloter.cpp │ ├── pool_alloter.h │ ├── pool_block.cpp │ └── pool_block.h ├── buffer │ ├── buffer_block.cpp │ ├── buffer_block.h │ ├── buffer_interface.h │ ├── buffer_queue.cpp │ └── buffer_queue.h ├── log │ ├── base_logger.cpp │ ├── base_logger.h │ ├── file_logger.cpp │ ├── file_logger.h │ ├── log.cpp │ ├── log.h │ ├── log_stream.cpp │ ├── log_stream.h │ ├── logger_interface.h │ ├── stdout_logger.cpp │ └── stdout_logger.h ├── network │ ├── address.cpp │ ├── address.h │ ├── io_handle.h │ ├── posix │ │ ├── io_handle.cpp │ │ └── socket.cpp │ ├── socket.h │ └── win │ │ ├── io_handle.cpp │ │ └── socket.cpp ├── os │ ├── convert.h │ ├── os_info.cpp │ ├── os_info.h │ ├── posix │ │ └── convert.cpp │ └── win │ │ └── convert.cpp ├── structure │ ├── list.h │ ├── list_slot.h │ ├── thread_safe_block_queue.h │ ├── thread_safe_queue.h │ └── thread_safe_unordered_map.h ├── thread │ ├── thread.h │ └── thread_with_queue.h ├── timer │ ├── timer.cpp │ ├── timer.h │ ├── timer_container.cpp │ ├── timer_container.h │ ├── timer_interface.h │ ├── timer_slot.cpp │ └── timer_slot.h └── util │ ├── any.h │ ├── bitmap.cpp │ ├── bitmap.h │ ├── config.cpp │ ├── config.h │ ├── os_return.h │ ├── random.cpp │ ├── random.h │ ├── singleton.h │ ├── time.cpp │ └── time.h ├── cppnet ├── CMakeLists.txt ├── cppnet.cpp ├── cppnet_base.cpp ├── cppnet_base.h ├── cppnet_config.h ├── dispatcher.cpp ├── dispatcher.h ├── event │ ├── action_interface.h │ ├── epoll │ │ ├── epoll_action.cpp │ │ ├── epoll_action.h │ │ └── wepoll │ │ │ ├── README.md │ │ │ ├── wepoll.c │ │ │ └── wepoll.h │ ├── event_interface.cpp │ ├── event_interface.h │ ├── kqueue │ │ ├── kqueue_action.cpp │ │ └── kqueue_action.h │ ├── timer_event.cpp │ └── timer_event.h └── socket │ ├── connect_socket.cpp │ ├── connect_socket.h │ ├── rw_socket.cpp │ ├── rw_socket.h │ ├── socket_interface.cpp │ └── socket_interface.h ├── doc ├── api │ ├── api.md │ └── api_cn.md ├── build │ ├── build.md │ └── build_cn.md ├── efficiency │ ├── apache_ab_bench.md │ └── apache_ab_bench_cn.md ├── image │ ├── cppnet_level.png │ ├── linux_apache_ab_bench.png │ ├── logo.png │ ├── macos_apache_ab_bench.png │ └── windows_apache_ab_bench.png ├── introduction │ └── cppnet.md └── start │ ├── quick_start.md │ └── quick_start_cn.md ├── include ├── cppnet.h ├── cppnet_buffer.h ├── cppnet_socket.h └── cppnet_type.h ├── makefile └── test ├── CMakeLists.txt ├── echo ├── CMakeLists.txt ├── echo_client.cpp ├── echo_client.vcxproj ├── echo_server.cpp ├── echo_server.vcxproj └── makefile ├── http ├── CMakeLists.txt ├── http.vcxproj ├── http.vcxproj.user ├── http_context.cpp ├── http_context.h ├── http_request.h ├── http_response.cpp ├── http_response.h ├── http_server.cpp ├── http_server.h ├── http_server_test.cpp └── makefile ├── multi_port ├── CMakeLists.txt ├── makefile ├── multi_port_client.cpp ├── multi_port_client.filters ├── multi_port_client.vcxproj ├── multi_port_server.cpp ├── multi_port_server.filters └── multi_port_server.vcxproj ├── pingpong ├── CMakeLists.txt ├── client.cpp ├── client.vcxproj ├── client.vcxproj.filters ├── makefile ├── server.cpp ├── server.vcxproj └── server.vcxproj.filters ├── rpc ├── CMakeLists.txt ├── client.cpp ├── common_struct.h ├── func_thread.cpp ├── func_thread.h ├── info_router.cpp ├── info_router.h ├── makefile ├── parse_package.cpp ├── parse_package.h ├── rpc_client.cpp ├── rpc_client.h ├── rpc_client.vcxproj ├── rpc_client.vcxproj.filters ├── rpc_server.cpp ├── rpc_server.h ├── rpc_server.vcxproj ├── rpc_server.vcxproj.filters └── server.cpp ├── sendfile ├── CMakeLists.txt ├── common.h ├── makefile ├── md5.cpp ├── md5.h ├── send_file_cli.vcxproj.vcxproj ├── send_file_client.cpp ├── send_file_ser.vcxproj.vcxproj └── send_file_server.cpp └── simple ├── CMakeLists.txt ├── client.filters ├── client.vcxproj ├── cppnet_client.cpp ├── cppnet_server.cpp ├── makefile ├── server.vcxproj └── server.vcxproj.filters /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore all files without extension. 2 | # If you need to git-add a file without extension, add -f 3 | * 4 | !*.* 5 | !*/ 6 | build/ 7 | *.o 8 | *.a 9 | *.log 10 | *.vs 11 | *64 12 | *32 13 | *.db 14 | *vscode 15 | *DEBUG 16 | *RELEASE 17 | *.pro 18 | *.user 19 | *bug 20 | 21 | # compdb files 22 | .cache/ 23 | compile_commands.json 24 | .clangd/ 25 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | sudo: required 3 | dist: trusty 4 | 5 | compiler: 6 | - gcc 7 | 8 | os: 9 | - linux 10 | 11 | script: 12 | - if [ $TRAVIS_OS_NAME == linux ]; then sh build.sh; fi 13 | 14 | branches: 15 | only: 16 | - master 17 | 18 | notifications: 19 | email: false -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | project(cppnet C CXX) 4 | 5 | set(CMAKE_CXX_STANDARD 11) 6 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 7 | 8 | set(CXX_FLAGS 9 | -O2 10 | -std=c++11 11 | -rdynamic 12 | -lpthread 13 | -fPIC 14 | -lstdc++ 15 | -pipe 16 | ) 17 | 18 | if(CMAKE_BUILD_BITS EQUAL 32) 19 | list(APPEND CXX_FLAGS "-m32") 20 | else() 21 | list(APPEND CXX_FLAGS "-m64") 22 | endif() 23 | 24 | if (WIN32) 25 | add_definitions(-D__win__) 26 | add_definitions(-D__use_iocp__) 27 | endif () 28 | 29 | # output 30 | set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) 31 | set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) 32 | 33 | # include 34 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}) 35 | 36 | add_subdirectory(common) 37 | add_subdirectory(cppnet) 38 | 39 | add_library(${PROJECT_NAME} STATIC ${common_source} ${cppnet_source}) 40 | 41 | add_subdirectory(test) 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, caozhiyi 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

cppnet logo

2 | 3 |

4 | Build Status 5 | Licenses 6 |

7 | 8 | See [chinese](/README_cn.md) 9 | See the details in chinese [wiki](https://github.com/caozhiyi/CppNet/wiki) 10 | ## Introduction 11 | 12 | Cppnet is a proactor mode and multithreaded network with C++11 on tcp. Support Window, Linux and macOS. 13 | - `Simple`: 14 | + Only export a little interfaces, all net io insterface are asynchronous callbacks 15 | + Insterface as much as possible like calling the socket API of the system 16 | + There is only one additional buffer interface for the client 17 | + Support both IPv4 and IPv6 18 | 19 | - `Fast`: 20 | + Use epoll, [wepoll](https://github.com/piscisaureus/wepoll) and kqueue 21 | + Multithreaded threads are handled by the kernel 22 | + Each socket has a single memory pool object. All memory requested from the memory pool is managed by an intelligent pointer 23 | + Using time wheel to realize timer 24 | 25 | - `Clear`: 26 | + Three layers: event-driven layer, session management layer and interface layer 27 | + Upward notification through callbacks between layers. Clear division of responsibilities among modules, pay to Caesar what belongs to Caesar and God what belongs to God 28 | + The interface decoupling module is used to meet the minimum interface principle and dependency inversion principle 29 | 30 | ## Quick Start 31 | Quick use of `cppnet` and precautions, see [quick start](doc/start/quick_start.md). 32 | 33 | ## Interface 34 | 35 | `cppnet` has three types of external interfaces, which are also defined in three header files 36 | - Initialization and global configuration, defined in [cppnet](/include/cppnet.h) 37 | - `socket` operation, defined in [cppnet_socket](/include/cppnet_socket.h) 38 | - `buffer` read, defined in [cppnet_buffer](/include/cppnet_buffer.h) 39 | 40 | For details, see [API](/doc/api/api.md). 41 | 42 | ## Example 43 | 44 | All simples are in [test](/test): 45 | - [simple](/test/simple): Most simple example. 46 | - [echo](/test/echo): Test program of echo with 200 connection. 47 | - [http](/test/http): Simple HTTP server is implemented with reference to muduo. 48 | - [sendfile](/test/sendfile): Example of sending and receiving files. 49 | - [pingpong](/test/pingpong): Pingpong test program. 50 | - [rpc](/test/rpc): Interesting rpc program. 51 | - [multi_port](/test/multi_port): Example of multiple listening ports. 52 | 53 | ## Efficiency 54 | 55 | Apache `ab` is used to pressure test the `http` test service in the [test](/test) directory, and compared with `muduo`. 56 | For details, see [ab benchmark](/doc/efficiency/apache_ab_bench.md)。 57 | 58 | ## Build 59 | 60 | Look at [Build](/doc/build/build.md) 61 | 62 | ## Licenses 63 | 64 | This program is under the terms of the BSD 3-Clause License. For details, see [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause). 65 | -------------------------------------------------------------------------------- /README_cn.md: -------------------------------------------------------------------------------- 1 |

cppnet logo

2 | 3 |

4 | Build Status 5 | Licenses 6 |

7 | 8 | 查看更多细节 [wiki](https://github.com/caozhiyi/CppNet/wiki) 9 | 10 | ## 简介 11 | 12 | Cppnet是一个封装在TCP协议上的proactor模式multi-thread C++11网络库,支持在windows,linux以及macOS上编译使用。 13 | - `简单`: 14 | + 对外暴漏最少接口,所有的网络响应都封装为异步回调的形式 15 | + 接口声明类似系统原生 16 | + 只新增一个buffer接口集 17 | + 支持IPv6和IPv4 18 | 19 | - `快速`: 20 | + 分别采用epoll,[wepoll](https://github.com/piscisaureus/wepoll),kqueue做底层事件驱动 21 | + 多线程惊群交由内核处理 22 | + 参照SGI STL和Nginx实现了内存池,每个连接都独享一个内存池对象,所有从内存池中申请的内存都由智能指针管理 23 | + 用时间轮实现定时器 24 | 25 | - `明了`: 26 | + 结构上分为三层:事件驱动层,会话管理层,接口层,各层之间通过回调向上通知 27 | + 各个模块之间职责分工明确,上帝的事儿归上帝管,凯撒的事儿归凯撒管 28 | + 通过接口解耦模块,符合最小接口原则和依赖倒置原则 29 | 30 | ## 快速开始 31 | 快速使用`cppnet`,以及使用注意事项,请看[快速开始](doc/start/quick_start_cn.md)。 32 | 33 | ## 接口 34 | 35 | `cppnet`对外接口主要包括三种类型,也分别定义在三个头文件中: 36 | - 初始化和全局配置类,定义在[cppnet](/include/cppnet.h) 37 | - `socket`操作类,[cppnet_socket](/include/cppnet_socket.h) 38 | - `buffer`读取类,定义在[cppnet_buffer](/include/cppnet_buffer.h) 39 | 40 | 接口详情请参考[API](/doc/api/api_cn.md)。 41 | 42 | ## 示例 43 | 44 | 所有示例都在 [test](/test) 目录下: 45 | - [simple](/test/simple): 一个简单的使用示例。 46 | - [echo](/test/echo): 实现了200连接量的echo的测试程序。 47 | - [http](/test/http): 参照muduo实现了一个简单的http服务器。 48 | - [sendfile](/test/sendfile): 文件发送和接收示例。 49 | - [pingpong](/test/pingpong): pingpong测试程序。 50 | - [rpc](/test/rpc): 简单的rpc示例。 51 | - [multi_port](/test/multi_port): 多监听端口示例。 52 | 53 | ## 效率 54 | 55 | 目前用Apache `ab` 对[test](/test)目录中的`http`测试服务做了压测,并与`muduo`做了对比。 56 | 详情请看[ab压测](/doc/efficiency/apache_ab_bench_cn.md)。 57 | 58 | ## 编译 59 | 60 | 请看[编译](/doc/build/build_cn.md) 61 | 62 | ## Q&A 63 | 1. 为什么在windows上不使用IOCP? 64 | 请看文章[cppnet网络库](/doc/introduction/cppnet.md)最后一节。 65 | 66 | ## 协议 67 | 68 | CppNet使用BSD 3-Clause使用条款,详情请看[BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause)。 69 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | - [x] IOCP supports multiple accept events 2 | - [x] logger support stream 3 | - [x] support IPV6 4 | - [x] remove default thread number to iocp 5 | - [x] format files name 6 | - [x] restruct event action support iocp 7 | - [x] add thread safe alloter 8 | - [x] valgrind check memory 9 | - [x] ab performance testing 10 | - [x] update document 11 | - [x] client socket add accept socket number 12 | - [x] delete cppnet instance destory lib 13 | - [x] add socket content 14 | - [x] multi listen port example 15 | - [x] pingpong test on windows 16 | - [x] quick start document 17 | - [ ] pingpong performance testing 18 | - [ ] IOCP lost disconnection event 19 | - [ ] windows timer wakeup other thread 20 | - [ ] memory leak check 21 | - [ ] windows use wepoll -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | make -j4 -------------------------------------------------------------------------------- /common/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | project(cppnet CXX) 4 | 5 | aux_source_directory(${PROJECT_SOURCE_DIR}/alloter src_files) 6 | aux_source_directory(${PROJECT_SOURCE_DIR}/buffer src_files) 7 | aux_source_directory(${PROJECT_SOURCE_DIR}/log src_files) 8 | aux_source_directory(${PROJECT_SOURCE_DIR}/os src_files) 9 | aux_source_directory(${PROJECT_SOURCE_DIR}/network src_files) 10 | aux_source_directory(${PROJECT_SOURCE_DIR}/structure src_files) 11 | aux_source_directory(${PROJECT_SOURCE_DIR}/thread src_files) 12 | aux_source_directory(${PROJECT_SOURCE_DIR}/timer src_files) 13 | aux_source_directory(${PROJECT_SOURCE_DIR}/util src_files) 14 | 15 | IF (WIN32) 16 | aux_source_directory(${PROJECT_SOURCE_DIR}/network/win src_files) 17 | aux_source_directory(${PROJECT_SOURCE_DIR}/os/win src_files) 18 | ELSEIF (APPLE) 19 | aux_source_directory(${PROJECT_SOURCE_DIR}/network/posix src_files) 20 | aux_source_directory(${PROJECT_SOURCE_DIR}/os/posix src_files) 21 | ELSEIF (UNIX) 22 | aux_source_directory(${PROJECT_SOURCE_DIR}/network/posix src_files) 23 | aux_source_directory(${PROJECT_SOURCE_DIR}/os/posix src_files) 24 | ENDIF () 25 | 26 | set(common_source ${src_files} PARENT_SCOPE) -------------------------------------------------------------------------------- /common/alloter/alloter_interface.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_ALLOTER_ALLOTER_INTERFACE 7 | #define COMMON_ALLOTER_ALLOTER_INTERFACE 8 | 9 | #include 10 | #include 11 | 12 | namespace cppnet { 13 | 14 | static const uint16_t __align = sizeof(unsigned long); 15 | 16 | class Alloter { 17 | public: 18 | Alloter() {} 19 | virtual ~Alloter() {} 20 | 21 | virtual void* Malloc(uint32_t size) = 0; 22 | virtual void* MallocAlign(uint32_t size) = 0; 23 | virtual void* MallocZero(uint32_t size) = 0; 24 | 25 | virtual void Free(void* &data, uint32_t len = 0) = 0; 26 | 27 | protected: 28 | uint32_t Align(uint32_t size) { 29 | return ((size + __align - 1) & ~(__align - 1)); 30 | } 31 | }; 32 | 33 | class AlloterWrap { 34 | public: 35 | AlloterWrap(std::shared_ptr a) : _alloter(a) {} 36 | ~AlloterWrap() {} 37 | 38 | //for object. invocation of constructors and destructors 39 | template 40 | T* PoolNew(Args&&... args); 41 | template 42 | std::shared_ptr PoolNewSharePtr(Args&&... args); 43 | 44 | template 45 | void PoolDelete(T* &c); 46 | 47 | //for continuous memory 48 | template 49 | T* PoolMalloc(uint32_t size); 50 | template 51 | std::shared_ptr PoolMallocSharePtr(uint32_t size); 52 | 53 | template 54 | void PoolFree(T* &m, uint32_t len); 55 | 56 | private: 57 | std::shared_ptr _alloter; 58 | }; 59 | 60 | template 61 | T* AlloterWrap::PoolNew(Args&&... args) { 62 | uint32_t sz = sizeof(T); 63 | 64 | void* data = _alloter->MallocAlign(sz); 65 | if (!data) { 66 | return nullptr; 67 | } 68 | 69 | T* res = new(data) T(std::forward(args)...); 70 | return res; 71 | } 72 | 73 | template 74 | std::shared_ptr AlloterWrap::PoolNewSharePtr(Args&&... args) { 75 | T* ret = PoolNew(std::forward(args)...); 76 | return std::shared_ptr(ret, [this](T* c) { PoolDelete(c); }); 77 | } 78 | 79 | template 80 | void AlloterWrap::PoolDelete(T* &c) { 81 | if (!c) { 82 | return; 83 | } 84 | 85 | c->~T(); 86 | 87 | uint32_t len = sizeof(T); 88 | void* data = (void*)c; 89 | _alloter->Free(data, len); 90 | c = nullptr; 91 | } 92 | 93 | template 94 | T* AlloterWrap::PoolMalloc(uint32_t sz) { 95 | return (T*)_alloter->MallocAlign(sz); 96 | } 97 | 98 | template 99 | std::shared_ptr AlloterWrap::PoolMallocSharePtr(uint32_t size) { 100 | T* ret = PoolMalloc(size); 101 | return std::shared_ptr(ret, [this, size](T* &c) { PoolFree(c, size); }); 102 | } 103 | 104 | template 105 | void AlloterWrap::PoolFree(T* &m, uint32_t len) { 106 | if (!m) { 107 | return; 108 | } 109 | void* data = (void*)m; 110 | _alloter->Free(data, len); 111 | m = nullptr; 112 | } 113 | 114 | } 115 | 116 | #endif -------------------------------------------------------------------------------- /common/alloter/normal_alloter.cpp: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #include //for memset 7 | #include 8 | #include "common/alloter/normal_alloter.h" 9 | 10 | namespace cppnet { 11 | 12 | NormalAlloter::NormalAlloter() { 13 | 14 | } 15 | 16 | NormalAlloter::~NormalAlloter() { 17 | 18 | } 19 | 20 | void* NormalAlloter::Malloc(uint32_t size) { 21 | void* ret = malloc((size_t)size); 22 | if (!ret) { 23 | throw "not enough memory"; 24 | return nullptr; 25 | } 26 | 27 | return ret; 28 | } 29 | 30 | void* NormalAlloter::MallocAlign(uint32_t size) { 31 | return Malloc(Align(size)); 32 | } 33 | 34 | void* NormalAlloter::MallocZero(uint32_t size) { 35 | void* ret = Malloc(size); 36 | if (ret) { 37 | memset(ret, 0, size); 38 | } 39 | return ret; 40 | } 41 | 42 | void NormalAlloter::Free(void* &data, uint32_t len) { 43 | free(data); 44 | data = nullptr; 45 | } 46 | 47 | std::shared_ptr MakeNormalAlloterPtr() { 48 | return std::make_shared(); 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /common/alloter/normal_alloter.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_ALLOTER_NORMAL_ALLOTER 7 | #define COMMON_ALLOTER_NORMAL_ALLOTER 8 | 9 | #include "common/alloter/alloter_interface.h" 10 | 11 | namespace cppnet { 12 | 13 | class NormalAlloter : public Alloter { 14 | public: 15 | NormalAlloter(); 16 | ~NormalAlloter(); 17 | 18 | void* Malloc(uint32_t size); 19 | void* MallocAlign(uint32_t size); 20 | void* MallocZero(uint32_t size); 21 | 22 | void Free(void* &data, uint32_t len = 0); 23 | }; 24 | 25 | std::shared_ptr MakeNormalAlloterPtr(); 26 | 27 | } 28 | 29 | #endif -------------------------------------------------------------------------------- /common/alloter/pool_alloter.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_ALLOTER_POOL_ALLOTER 7 | #define COMMON_ALLOTER_POOL_ALLOTER 8 | 9 | #ifdef __use_iocp__ 10 | #include 11 | #endif 12 | #include 13 | #include 14 | #include "common/alloter/alloter_interface.h" 15 | 16 | namespace cppnet { 17 | 18 | static const uint32_t __default_max_bytes = 256; 19 | static const uint32_t __default_number_of_free_lists = __default_max_bytes / __align; 20 | static const uint32_t __default_number_add_nodes = 20; 21 | 22 | class PoolAlloter : public Alloter { 23 | public: 24 | PoolAlloter(); 25 | ~PoolAlloter(); 26 | 27 | void* Malloc(uint32_t size); 28 | void* MallocAlign(uint32_t size); 29 | void* MallocZero(uint32_t size); 30 | 31 | void Free(void* &data, uint32_t len); 32 | private: 33 | uint32_t FreeListIndex(uint32_t size, uint32_t align = __align) { 34 | return (size + align - 1) / align - 1; 35 | } 36 | 37 | void* ReFill(uint32_t size, uint32_t num = __default_number_add_nodes); 38 | void* ChunkAlloc(uint32_t size, uint32_t& nums); 39 | 40 | private: 41 | union MemNode { 42 | MemNode* _next; 43 | char _data[1]; 44 | }; 45 | 46 | #ifdef __use_iocp__ 47 | std::mutex _mutex; 48 | #endif 49 | char* _pool_start; 50 | char* _pool_end; 51 | std::vector _free_list; 52 | std::vector _malloc_vec; 53 | std::shared_ptr _alloter; 54 | }; 55 | 56 | std::shared_ptr MakePoolAlloterPtr(); 57 | 58 | } 59 | 60 | #endif -------------------------------------------------------------------------------- /common/alloter/pool_block.cpp: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #include 7 | #include 8 | #include "cppnet/cppnet_config.h" 9 | #include "common/alloter/pool_block.h" 10 | 11 | namespace cppnet { 12 | 13 | 14 | BlockMemoryPool::BlockMemoryPool(uint32_t large_sz, uint32_t add_num) : 15 | _number_large_add_nodes(add_num), 16 | _large_size(large_sz) { 17 | 18 | } 19 | 20 | BlockMemoryPool::~BlockMemoryPool() { 21 | #ifdef __use_iocp__ 22 | std::lock_guard lock(_mutex); 23 | #endif 24 | // free all memory 25 | for (auto iter = _free_mem_vec.begin(); iter != _free_mem_vec.end(); ++iter) { 26 | free(*iter); 27 | } 28 | _free_mem_vec.clear(); 29 | } 30 | 31 | void* BlockMemoryPool::PoolLargeMalloc() { 32 | #ifdef __use_iocp__ 33 | std::lock_guard lock(_mutex); 34 | #endif 35 | if (_free_mem_vec.empty()) { 36 | Expansion(); 37 | } 38 | 39 | void* ret = _free_mem_vec.back(); 40 | _free_mem_vec.pop_back(); 41 | return ret; 42 | } 43 | 44 | void BlockMemoryPool::PoolLargeFree(void* &m) { 45 | bool release = false; 46 | { 47 | #ifdef __use_iocp__ 48 | std::lock_guard lock(_mutex); 49 | #endif 50 | _free_mem_vec.push_back(m); 51 | 52 | if (_free_mem_vec.size() > __max_block_num) { 53 | release = true; 54 | } 55 | } 56 | 57 | // release some block. 58 | if (release) { 59 | ReleaseHalf(); 60 | } 61 | } 62 | 63 | uint32_t BlockMemoryPool::GetSize() { 64 | #ifdef __use_iocp__ 65 | std::lock_guard lock(_mutex); 66 | #endif 67 | return (uint32_t)_free_mem_vec.size(); 68 | } 69 | 70 | uint32_t BlockMemoryPool::GetBlockLength() { 71 | return _large_size; 72 | } 73 | 74 | void BlockMemoryPool::ReleaseHalf() { 75 | #ifdef __use_iocp__ 76 | std::lock_guard lock(_mutex); 77 | #endif 78 | size_t size = _free_mem_vec.size(); 79 | size_t hale = size / 2; 80 | for (auto iter = _free_mem_vec.begin(); iter != _free_mem_vec.end();) { 81 | void* mem = *iter; 82 | 83 | iter = _free_mem_vec.erase(iter); 84 | free(mem); 85 | 86 | size--; 87 | if (iter == _free_mem_vec.end() || size <= hale) { 88 | break; 89 | } 90 | } 91 | } 92 | 93 | void BlockMemoryPool::Expansion(uint32_t num) { 94 | if (num == 0) { 95 | num = _number_large_add_nodes; 96 | } 97 | 98 | for (uint32_t i = 0; i < num; ++i) { 99 | void* mem = malloc(_large_size); 100 | // not memset! 101 | _free_mem_vec.push_back(mem); 102 | } 103 | } 104 | 105 | std::shared_ptr MakeBlockMemoryPoolPtr(uint32_t large_sz, uint32_t add_num) { 106 | return std::make_shared(large_sz, add_num); 107 | } 108 | 109 | } -------------------------------------------------------------------------------- /common/alloter/pool_block.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_ALLOTER_POOL_BLOCK 7 | #define COMMON_ALLOTER_POOL_BLOCK 8 | 9 | #ifdef __use_iocp__ 10 | #include 11 | #endif 12 | #include 13 | #include 14 | #include 15 | 16 | namespace cppnet { 17 | 18 | // all memory must return memory pool before destroy. 19 | class BlockMemoryPool { 20 | public: 21 | // bulk memory size. 22 | // every time add nodes num 23 | BlockMemoryPool(uint32_t large_sz, uint32_t add_num); 24 | virtual ~BlockMemoryPool(); 25 | 26 | // for bulk memory. 27 | // return one bulk memory node 28 | virtual void* PoolLargeMalloc(); 29 | virtual void PoolLargeFree(void* &m); 30 | 31 | // return bulk memory list size 32 | virtual uint32_t GetSize(); 33 | // return length of bulk memory 34 | virtual uint32_t GetBlockLength(); 35 | 36 | // release half memory 37 | virtual void ReleaseHalf(); 38 | virtual void Expansion(uint32_t num = 0); 39 | 40 | private: 41 | #ifdef __use_iocp__ 42 | std::mutex _mutex; 43 | #endif 44 | uint32_t _number_large_add_nodes; //every time add nodes num 45 | uint32_t _large_size; //bulk memory size 46 | std::vector _free_mem_vec; //free bulk memory list 47 | }; 48 | 49 | std::shared_ptr MakeBlockMemoryPoolPtr(uint32_t large_sz, uint32_t add_num); 50 | 51 | } 52 | 53 | #endif -------------------------------------------------------------------------------- /common/buffer/buffer_block.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_BUFFER_BUFFER_BLOCK 7 | #define COMMON_BUFFER_BUFFER_BLOCK 8 | 9 | #include 10 | #include "common/structure/list_slot.h" 11 | #include "common/buffer/buffer_interface.h" 12 | 13 | namespace cppnet { 14 | 15 | class BlockMemoryPool; 16 | class BufferBlock: 17 | public InnerBuffer, 18 | public ListSlot { 19 | 20 | public: 21 | BufferBlock(std::shared_ptr& alloter); 22 | ~BufferBlock(); 23 | 24 | // read to res buf but don't change the read point 25 | // return read size 26 | uint32_t ReadNotMovePt(char* res, uint32_t len); 27 | 28 | uint32_t Read(std::shared_ptr buffer, uint32_t len = 0); 29 | uint32_t Write(std::shared_ptr buffer, uint32_t len = 0); 30 | 31 | uint32_t Read(char* res, uint32_t len); 32 | uint32_t Write(const char* data, uint32_t len); 33 | 34 | // clear all data 35 | void Clear(); 36 | 37 | // move read point 38 | int32_t MoveReadPt(int32_t len); 39 | // move write point 40 | int32_t MoveWritePt(int32_t len); 41 | 42 | // do not read when buffer less than len. 43 | // return len when read otherwise return 0 44 | uint32_t ReadUntil(char* res, uint32_t len); 45 | 46 | // do not read when can't find specified character. 47 | // return read bytes when read otherwise return 0 48 | // when find specified character but res length is too short, 49 | // return 0 and the last param return need length 50 | uint32_t ReadUntil(char* res, uint32_t len, const char* find, uint32_t find_len, uint32_t& need_len); 51 | 52 | uint32_t GetCanWriteLength(); 53 | uint32_t GetCanReadLength(); 54 | 55 | // get free memory block, 56 | // res1: point to memory of start. 57 | // len1: length of memory. 58 | // there may be two blocks 59 | bool GetFreeMemoryBlock(void*& res1, uint32_t& len1, void*& res2, uint32_t& len2); 60 | 61 | // get used memory block, 62 | // res1: point to memory of start. 63 | // len1: length of memory. 64 | // there may be two blocks 65 | bool GetUseMemoryBlock(void*& res1, uint32_t& len1, void*& res2, uint32_t& len2); 66 | 67 | // return can read bytes 68 | uint32_t FindStr(const char* s, uint32_t s_len); 69 | 70 | // return block memory pool 71 | std::shared_ptr GetBlockMemoryPool(); 72 | 73 | private: 74 | //find str in fix length buffer. return the first position if find otherwise return nullptr 75 | const char* _FindStrInMem(const char* buffer, const char* ch, uint32_t buffer_len, uint32_t ch_len) const; 76 | uint32_t _Read(char* res, uint32_t len, bool move_pt); 77 | uint32_t _Write(const char* data, uint32_t len); 78 | 79 | private: 80 | uint32_t _total_size; //total buffer size 81 | char* _read; //read position 82 | char* _write; //write position 83 | char* _buffer_start; 84 | char* _buffer_end; 85 | bool _can_read; //when _read == _write? Is there any data can be read. 86 | std::weak_ptr _alloter; 87 | }; 88 | } 89 | 90 | #endif -------------------------------------------------------------------------------- /common/buffer/buffer_interface.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_BUFFER_BUFFER_INTERFACE 7 | #define COMMON_BUFFER_BUFFER_INTERFACE 8 | 9 | #include 10 | #include "include/cppnet_buffer.h" 11 | 12 | namespace cppnet { 13 | 14 | class BlockMemoryPool; 15 | class InnerBuffer: 16 | public Buffer { 17 | 18 | public: 19 | InnerBuffer() {} 20 | virtual ~InnerBuffer() {} 21 | 22 | // read to res buf but don't change the read point 23 | // return read size 24 | virtual uint32_t ReadNotMovePt(char* res, uint32_t len) = 0; 25 | 26 | virtual uint32_t Read(char* res, uint32_t len) = 0; 27 | virtual uint32_t Write(const char* data, uint32_t len) = 0; 28 | 29 | // clear all data 30 | virtual void Clear() = 0; 31 | 32 | // do not read when buffer less than len. 33 | // return len when read otherwise return 0 34 | virtual uint32_t ReadUntil(char* res, uint32_t len) = 0; 35 | 36 | // do not read when can't find specified character. 37 | // return read bytes when read otherwise return 0 38 | // when find specified character but res length is too short, 39 | // return 0 and the last param return need length 40 | virtual uint32_t ReadUntil(char* res, uint32_t len, const char* find, uint32_t find_len, uint32_t& need_len) = 0; 41 | 42 | virtual uint32_t GetCanWriteLength() = 0; 43 | virtual uint32_t GetCanReadLength() = 0; 44 | 45 | // return can read bytes 46 | virtual uint32_t FindStr(const char* s, uint32_t s_len) = 0; 47 | 48 | virtual uint32_t Read(std::shared_ptr buffer, uint32_t len = 0) = 0; 49 | virtual uint32_t Write(std::shared_ptr buffer, uint32_t len = 0) = 0; 50 | 51 | // move read point 52 | virtual int32_t MoveReadPt(int32_t len) = 0; 53 | // move write point 54 | virtual int32_t MoveWritePt(int32_t len) = 0; 55 | 56 | // return block memory pool 57 | virtual std::shared_ptr GetBlockMemoryPool() = 0; 58 | }; 59 | 60 | } 61 | 62 | #endif -------------------------------------------------------------------------------- /common/buffer/buffer_queue.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_BUFFER_BUFFER_QUEUE 7 | #define COMMON_BUFFER_BUFFER_QUEUE 8 | 9 | #include 10 | #include 11 | #include "common/structure/list.h" 12 | #include "common/network/io_handle.h" 13 | #include "common/buffer/buffer_interface.h" 14 | #include "common/alloter/alloter_interface.h" 15 | 16 | namespace cppnet { 17 | 18 | class AlloterWrap; 19 | class BufferBlock; 20 | class BlockMemoryPool; 21 | class BufferQueue: 22 | public InnerBuffer { 23 | public: 24 | BufferQueue(const std::shared_ptr& block_pool, 25 | const std::shared_ptr& alloter); 26 | virtual ~BufferQueue(); 27 | 28 | // read to res buf but don't change the read point 29 | // return read size 30 | virtual uint32_t ReadNotMovePt(char* res, uint32_t len); 31 | 32 | virtual uint32_t Read(std::shared_ptr buffer, uint32_t len = 0); 33 | virtual uint32_t Write(std::shared_ptr buffer, uint32_t len = 0); 34 | 35 | virtual uint32_t Read(char* res, uint32_t len); 36 | virtual uint32_t Write(const char* data, uint32_t len); 37 | 38 | // clear all data 39 | virtual void Clear(); 40 | 41 | // move read point 42 | virtual int32_t MoveReadPt(int32_t len); 43 | // move write point 44 | virtual int32_t MoveWritePt(int32_t len); 45 | 46 | // do not read when buffer less than len. 47 | // return len when read otherwise return 0 48 | virtual uint32_t ReadUntil(char* res, uint32_t len); 49 | 50 | // do not read when can't find specified character. 51 | // return read bytes when read otherwise return 0 52 | // when find specified character but res length is too short, 53 | // return 0 and the last param return need length 54 | virtual uint32_t ReadUntil(char* res, uint32_t len, const char* find, uint32_t find_len, uint32_t& need_len); 55 | 56 | virtual uint32_t GetCanWriteLength(); 57 | virtual uint32_t GetCanReadLength(); 58 | 59 | // get free memory block, 60 | // block_vec: memory block vector. 61 | // size: count block_vec's memory, bigger than size. 62 | // if size = 0, return existing free memory block. 63 | // return size of free memory. 64 | virtual uint32_t GetFreeMemoryBlock(std::vector& block_vec, uint32_t size = 0); 65 | 66 | // get use memory block, 67 | // block_vec: memory block vector. 68 | // return size of use memory. 69 | // if size = 0, return all used memory block. 70 | virtual uint32_t GetUseMemoryBlock(std::vector& block_vec, uint32_t max_size = 0); 71 | 72 | // return can read bytes 73 | virtual uint32_t FindStr(const char* s, uint32_t s_len); 74 | 75 | // return block memory pool 76 | virtual std::shared_ptr GetBlockMemoryPool(); 77 | 78 | protected: 79 | virtual void Reset(); 80 | virtual void Append(); 81 | 82 | protected: 83 | uint32_t _can_read_length; 84 | 85 | List _buffer_list; 86 | std::shared_ptr _buffer_write; 87 | 88 | std::shared_ptr _block_alloter; 89 | std::shared_ptr _alloter; 90 | }; 91 | 92 | } 93 | 94 | #endif -------------------------------------------------------------------------------- /common/log/base_logger.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | // Copyright 6 | 7 | #ifndef COMMON_LOG_BASE_LOGGER_H_ 8 | #define COMMON_LOG_BASE_LOGGER_H_ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "common/log/log.h" 15 | #include "common/log/log_stream.h" 16 | #include "common/structure/thread_safe_queue.h" 17 | 18 | namespace cppnet { 19 | 20 | // basic management class of log printing 21 | struct Log; 22 | class Logger; 23 | class Alloter; 24 | class BaseLogger { 25 | public: 26 | BaseLogger(uint16_t cache_size, uint16_t block_size); 27 | ~BaseLogger(); 28 | 29 | void SetLogger(std::shared_ptr log) { _logger = log; } 30 | 31 | void SetLevel(LogLevel level); 32 | 33 | void Debug(const char* file, uint32_t line, 34 | const char* content, va_list list); 35 | void Info(const char* file, uint32_t line, 36 | const char* content, va_list list); 37 | void Warn(const char* file, uint32_t line, 38 | const char* content, va_list list); 39 | void Error(const char* file, uint32_t line, 40 | const char* content, va_list list); 41 | void Fatal(const char* file, uint32_t line, 42 | const char* content, va_list list); 43 | 44 | LogStreamParam GetStreamParam(LogLevel level, 45 | const char* file, uint32_t line); 46 | 47 | private: 48 | std::shared_ptr GetLog(); 49 | void FreeLog(Log* log); 50 | Log* NewLog(); 51 | 52 | protected: 53 | uint16_t _level; 54 | uint16_t _cache_size; 55 | uint16_t _block_size; 56 | 57 | std::shared_ptr _allocter; 58 | ThreadSafeQueue _cache_queue; 59 | std::shared_ptr _logger; 60 | }; 61 | 62 | } // namespace cppnet 63 | 64 | #endif // COMMON_LOG_BASE_LOGGER_H_ 65 | -------------------------------------------------------------------------------- /common/log/file_logger.cpp: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #include 7 | #include 8 | #include "common/util/time.h" 9 | #include "common/log/file_logger.h" 10 | 11 | namespace cppnet { 12 | 13 | FileLogger::FileLogger(const std::string& file, 14 | FileLoggerSpiltUnit unit, 15 | uint16_t max_store_days, 16 | uint16_t time_offset): 17 | _file_name(file), 18 | _time_offset(time_offset), 19 | _spilt_unit(unit) { 20 | 21 | if (unit == FLSU_HOUR) { 22 | _time_buf_len = 13; // xxxx-xx-xx:xx 23 | _max_file_num = max_store_days * 24; 24 | 25 | } else { 26 | _time_buf_len = 10; // xxxx-xx-xx 27 | _max_file_num = max_store_days; 28 | } 29 | 30 | memset(_time, 0, __file_logger_time_buf_size); 31 | 32 | Start(); 33 | } 34 | 35 | FileLogger::~FileLogger() { 36 | Stop(); 37 | Join(); 38 | _stream.close(); 39 | } 40 | 41 | void FileLogger::Run() { 42 | while (!_stop) { 43 | auto log = Pop(); 44 | if (log) { 45 | CheckTime(log->_log); 46 | if (_stream.is_open()) { 47 | _stream.write(log->_log, log->_len); 48 | _stream.put('\n'); 49 | _stream.flush(); 50 | } 51 | 52 | } else { 53 | break; 54 | } 55 | } 56 | } 57 | 58 | void FileLogger::Stop() { 59 | _stop = true; 60 | Push(nullptr); 61 | } 62 | 63 | void FileLogger::Debug(std::shared_ptr& log) { 64 | Push(log); 65 | Logger::Debug(log); 66 | } 67 | 68 | void FileLogger::Info(std::shared_ptr& log) { 69 | Push(log); 70 | Logger::Info(log); 71 | } 72 | 73 | void FileLogger::Warn(std::shared_ptr& log) { 74 | Push(log); 75 | Logger::Warn(log); 76 | } 77 | 78 | void FileLogger::Error(std::shared_ptr& log) { 79 | Push(log); 80 | Logger::Error(log); 81 | } 82 | 83 | void FileLogger::Fatal(std::shared_ptr& log) { 84 | Push(log); 85 | Logger::Fatal(log); 86 | } 87 | 88 | void FileLogger::SetMaxStoreDays(uint16_t max) { 89 | if (_spilt_unit == FLSU_HOUR) { 90 | _time_buf_len = 13; // xxxx-xx-xx:xx 91 | _max_file_num = max * 24; 92 | 93 | } else { 94 | _time_buf_len = 10; // xxxx-xx-xx 95 | _max_file_num = max; 96 | } 97 | 98 | CheckExpireFiles(); 99 | } 100 | 101 | void FileLogger::CheckTime(char* log) { 102 | if (strncmp(_time, log + _time_offset, _time_buf_len) == 0) { 103 | return; 104 | } 105 | 106 | if (_stream.is_open()) { 107 | _stream.close(); 108 | } 109 | 110 | // get new time and file name 111 | memcpy(_time, log + _time_offset, _time_buf_len); 112 | std::string file_name(_file_name); 113 | file_name.append("."); 114 | file_name.append(_time, _time_buf_len); 115 | file_name.append(".log"); 116 | 117 | _history_file_names.push(file_name); 118 | CheckExpireFiles(); 119 | 120 | // open new log file 121 | _stream.open(file_name.c_str(), std::ios::app | std::ios::out); 122 | } 123 | 124 | void FileLogger::CheckExpireFiles() { 125 | // delete expire files 126 | while (_history_file_names.size() > _max_file_num) { 127 | std::string del_file = _history_file_names.front(); 128 | _history_file_names.pop(); 129 | std::remove(del_file.c_str()); 130 | } 131 | } 132 | 133 | } // namespace cppnet 134 | -------------------------------------------------------------------------------- /common/log/file_logger.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef QUIC_COMMON_LOG_FILE_LOGGER 7 | #define QUIC_COMMON_LOG_FILE_LOGGER 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "common/log/logger_interface.h" 14 | #include "common/thread/thread_with_queue.h" 15 | 16 | namespace cppnet { 17 | 18 | enum FileLoggerSpiltUnit { 19 | FLSU_DAY = 1, 20 | FLSU_HOUR = 2, 21 | }; 22 | 23 | class FileLogger: 24 | public Logger, 25 | public ThreadWithQueue> { 26 | 27 | public: 28 | FileLogger(const std::string& file, 29 | FileLoggerSpiltUnit unit = FLSU_DAY, 30 | uint16_t max_store_days = 3, 31 | uint16_t time_offset = 5); 32 | 33 | ~FileLogger(); 34 | 35 | void Run(); 36 | void Stop(); 37 | 38 | void Debug(std::shared_ptr& log); 39 | void Info(std::shared_ptr& log); 40 | void Warn(std::shared_ptr& log); 41 | void Error(std::shared_ptr& log); 42 | void Fatal(std::shared_ptr& log); 43 | 44 | void SetFileName(const std::string& name) { _file_name = name; } 45 | std::string GetFileName() { return _file_name; } 46 | 47 | void SetMaxStoreDays(uint16_t max); 48 | uint16_t GetMAxStorDays() { return _max_file_num; } 49 | 50 | private: 51 | void CheckTime(char* log); 52 | void CheckExpireFiles(); 53 | 54 | private: 55 | enum : uint8_t { 56 | __file_logger_time_buf_size = sizeof("xxxx-xx-xx:xx") 57 | }; 58 | std::string _file_name; 59 | std::fstream _stream; 60 | 61 | // for time check 62 | uint16_t _time_offset; 63 | uint8_t _time_buf_len; 64 | FileLoggerSpiltUnit _spilt_unit; 65 | char _time[__file_logger_time_buf_size]; 66 | 67 | // for log file delete 68 | uint16_t _max_file_num; 69 | std::queue _history_file_names; 70 | }; 71 | 72 | } // namespace cppnet 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /common/log/log.cpp: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #include 7 | 8 | #include "common/log/log.h" 9 | #include "common/log/base_logger.h" 10 | 11 | namespace cppnet { 12 | 13 | SingletonLogger::SingletonLogger() { 14 | _logger = std::make_shared(__log_cache_size, __log_block_size); 15 | } 16 | 17 | SingletonLogger::~SingletonLogger() { 18 | 19 | } 20 | 21 | void SingletonLogger::SetLogger(std::shared_ptr log) { 22 | _logger->SetLogger(log); 23 | } 24 | 25 | void SingletonLogger::SetLevel(LogLevel level){ 26 | _logger->SetLevel(level); 27 | } 28 | 29 | void SingletonLogger::Debug(const char* file, uint32_t line, const char* log...){ 30 | va_list list; 31 | va_start(list, log); 32 | _logger->Debug(file, line, log, list); 33 | va_end(list); 34 | } 35 | 36 | void SingletonLogger::Info(const char* file, uint32_t line, const char* log...){ 37 | va_list list; 38 | va_start(list, log); 39 | _logger->Info(file, line, log, list); 40 | va_end(list); 41 | } 42 | 43 | void SingletonLogger::Warn(const char* file, uint32_t line, const char* log...){ 44 | va_list list; 45 | va_start(list, log); 46 | _logger->Warn(file, line, log, list); 47 | va_end(list); 48 | } 49 | 50 | void SingletonLogger::Error(const char* file, uint32_t line, const char* log...){ 51 | va_list list; 52 | va_start(list, log); 53 | _logger->Error(file, line, log, list); 54 | va_end(list); 55 | } 56 | 57 | void SingletonLogger::Fatal(const char* file, uint32_t line, const char* log...){ 58 | va_list list; 59 | va_start(list, log); 60 | _logger->Fatal(file, line, log, list); 61 | va_end(list); 62 | } 63 | 64 | LogStreamParam SingletonLogger::GetStreamParam(LogLevel level, const char* file, uint32_t line) { 65 | return _logger->GetStreamParam(level, file, line); 66 | } 67 | 68 | } // namespace cppnet 69 | -------------------------------------------------------------------------------- /common/log/log.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef QUIC_COMMON_LOG_LOG 7 | #define QUIC_COMMON_LOG_LOG 8 | 9 | #include 10 | #include 11 | 12 | #include "common/log/log_stream.h" 13 | #include "common/util/singleton.h" 14 | 15 | namespace cppnet { 16 | 17 | // log level and switch 18 | enum LogLevel { 19 | LL_NULL = 0x00, // not print log 20 | LL_FATAL = 0x01, 21 | LL_ERROR = 0x02 | LL_FATAL, 22 | LL_WARN = 0x04 | LL_ERROR, 23 | LL_INFO = 0x08 | LL_WARN, 24 | LL_DEBUG = 0x10 | LL_INFO, 25 | }; 26 | 27 | // log interface for user 28 | #define LOG_SET(log) SingletonLogger::Instance().SetLogger(log) 29 | #define LOG_SET_LEVEL(level) SingletonLogger::Instance().SetLevel(level) 30 | 31 | #define LOG_DEBUG(log, ...) SingletonLogger::Instance().Debug(__FILE__, __LINE__, log, ##__VA_ARGS__) 32 | #define LOG_INFO(log, ...) SingletonLogger::Instance().Info(__FILE__, __LINE__, log, ##__VA_ARGS__) 33 | #define LOG_WARN(log, ...) SingletonLogger::Instance().Warn(__FILE__, __LINE__, log, ##__VA_ARGS__) 34 | #define LOG_ERROR(log, ...) SingletonLogger::Instance().Error(__FILE__, __LINE__, log, ##__VA_ARGS__) 35 | #define LOG_FATAL(log, ...) SingletonLogger::Instance().Fatal(__FILE__, __LINE__, log, ##__VA_ARGS__) 36 | 37 | #define LOG_DEBUG_S LogStream(cppnet::SingletonLogger::Instance().GetStreamParam(cppnet::LL_DEBUG, __FILE__, __LINE__)) 38 | #define LOG_INFO_S LogStream(cppnet::SingletonLogger::Instance().GetStreamParam(cppnet::LL_INFO, __FILE__, __LINE__)) 39 | #define LOG_WARN_S LogStream(cppnet::SingletonLogger::Instance().GetStreamParam(cppnet::LL_WARN, __FILE__, __LINE__)) 40 | #define LOG_ERROR_S LogStream(cppnet::SingletonLogger::Instance().GetStreamParam(cppnet::LL_ERROR, __FILE__, __LINE__)) 41 | #define LOG_FATAL_S LogStream(cppnet::SingletonLogger::Instance().GetStreamParam(cppnet::LL_FATAL, __FILE__, __LINE__)) 42 | 43 | // log cache config 44 | static const uint16_t __log_cache_size = 20; 45 | static const uint16_t __log_block_size = 1024; 46 | 47 | 48 | class Logger; 49 | class BaseLogger; 50 | class SingletonLogger: 51 | public Singleton { 52 | 53 | public: 54 | SingletonLogger(); 55 | ~SingletonLogger(); 56 | 57 | void SetLogger(std::shared_ptr log); 58 | 59 | void SetLevel(LogLevel level); 60 | 61 | // for log print as printf 62 | void Debug(const char* file, uint32_t line, const char* log...); 63 | void Info(const char* file, uint32_t line, const char* log...); 64 | void Warn(const char* file, uint32_t line, const char* log...); 65 | void Error(const char* file, uint32_t line, const char* log...); 66 | void Fatal(const char* file, uint32_t line, const char* log...); 67 | 68 | // for log stream 69 | LogStreamParam GetStreamParam(LogLevel level, const char* file, uint32_t line); 70 | 71 | private: 72 | std::shared_ptr _logger; 73 | }; 74 | 75 | } // namespace cppnet 76 | 77 | #endif -------------------------------------------------------------------------------- /common/log/log_stream.cpp: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #include "common/log/log.h" 7 | #include "common/log/log_stream.h" 8 | #include "common/log/logger_interface.h" 9 | 10 | namespace cppnet { 11 | 12 | #define CHECK_CONTINUE() do{ if (!_log || _log->_len >= __log_block_size) { return *this; } } while(0); 13 | 14 | LogStream::LogStream(const LogStreamParam& param): 15 | _log(param.first), 16 | _call_back(param.second) { 17 | 18 | } 19 | 20 | LogStream::~LogStream() { 21 | if (_log && _call_back) { 22 | _call_back(_log); 23 | } 24 | } 25 | 26 | LogStream& LogStream::operator<<(bool v) { 27 | CHECK_CONTINUE() 28 | 29 | char c = v ? '1' : '0'; 30 | _log->_len += snprintf(_log->_log + _log->_len, __log_block_size - _log->_len, "%c", c); 31 | return *this; 32 | } 33 | 34 | LogStream& LogStream::operator<<(int8_t v) { 35 | CHECK_CONTINUE() 36 | 37 | _log->_len += snprintf(_log->_log + _log->_len, __log_block_size - _log->_len, "%d", v); 38 | return *this; 39 | } 40 | 41 | LogStream& LogStream::operator<<(uint8_t v) { 42 | CHECK_CONTINUE() 43 | 44 | _log->_len += snprintf(_log->_log + _log->_len, __log_block_size - _log->_len, "%u", v); 45 | return *this; 46 | } 47 | 48 | LogStream& LogStream::operator<<(int16_t v) { 49 | CHECK_CONTINUE() 50 | 51 | _log->_len += snprintf(_log->_log + _log->_len, __log_block_size - _log->_len, "%d", v); 52 | return *this; 53 | } 54 | 55 | LogStream& LogStream::operator<<(uint16_t v) { 56 | CHECK_CONTINUE() 57 | 58 | _log->_len += snprintf(_log->_log + _log->_len, __log_block_size - _log->_len, "%u", v); 59 | return *this; 60 | } 61 | 62 | LogStream& LogStream::operator<<(int32_t v) { 63 | CHECK_CONTINUE() 64 | 65 | _log->_len += snprintf(_log->_log + _log->_len, __log_block_size - _log->_len, "%d", v); 66 | return *this; 67 | } 68 | 69 | LogStream& LogStream::operator<<(uint32_t v) { 70 | CHECK_CONTINUE() 71 | 72 | _log->_len += snprintf(_log->_log + _log->_len, __log_block_size - _log->_len, "%u", v); 73 | return *this; 74 | } 75 | 76 | LogStream& LogStream::operator<<(int64_t v) { 77 | CHECK_CONTINUE() 78 | #ifdef __win__ 79 | _log->_len += snprintf(_log->_log + _log->_len, __log_block_size - _log->_len, "%I64d", v); 80 | #else 81 | _log->_len += snprintf(_log->_log + _log->_len, __log_block_size - _log->_len, "%ld", v); 82 | #endif 83 | return *this; 84 | } 85 | 86 | LogStream& LogStream::operator<<(uint64_t v) { 87 | CHECK_CONTINUE() 88 | #ifdef __win__ 89 | _log->_len += snprintf(_log->_log + _log->_len, __log_block_size - _log->_len, "%I64u", v); 90 | #else 91 | _log->_len += snprintf(_log->_log + _log->_len, __log_block_size - _log->_len, "%lu", v); 92 | #endif 93 | return *this; 94 | } 95 | 96 | LogStream& LogStream::operator<<(float v) { 97 | CHECK_CONTINUE() 98 | 99 | _log->_len += snprintf(_log->_log + _log->_len, __log_block_size - _log->_len, "%.10lf", v); 100 | return *this; 101 | } 102 | 103 | LogStream& LogStream::operator<<(double v) { 104 | CHECK_CONTINUE() 105 | 106 | _log->_len += snprintf(_log->_log + _log->_len, __log_block_size - _log->_len, "%.20lf", v); 107 | return *this; 108 | } 109 | 110 | LogStream& LogStream::operator<<(const std::string& v) { 111 | CHECK_CONTINUE() 112 | 113 | _log->_len += snprintf(_log->_log + _log->_len, __log_block_size - _log->_len, "%s", v.c_str()); 114 | return *this; 115 | } 116 | 117 | LogStream& LogStream::operator<<(const char* v) { 118 | CHECK_CONTINUE() 119 | 120 | _log->_len += snprintf(_log->_log + _log->_len, __log_block_size - _log->_len, "%s", v); 121 | return *this; 122 | } 123 | 124 | LogStream& LogStream::operator<<(char v) { 125 | CHECK_CONTINUE() 126 | 127 | _log->_len += snprintf(_log->_log + _log->_len, __log_block_size - _log->_len, "%c", v); 128 | return *this; 129 | } 130 | 131 | } // namespace cppnet 132 | -------------------------------------------------------------------------------- /common/log/log_stream.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef QUIC_COMMON_LOG_LOG_STREAM 7 | #define QUIC_COMMON_LOG_LOG_STREAM 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace cppnet { 15 | 16 | struct Log; 17 | using LogStreamParam = 18 | std::pair, std::function)>>; 19 | 20 | class LogStream { 21 | public: 22 | LogStream(const LogStreamParam& param); 23 | ~LogStream(); 24 | 25 | LogStream& Stream() { return *this; } 26 | 27 | LogStream& operator<<(bool v); 28 | LogStream& operator<<(int8_t v); 29 | LogStream& operator<<(uint8_t v); 30 | LogStream& operator<<(int16_t v); 31 | LogStream& operator<<(uint16_t v); 32 | LogStream& operator<<(int32_t v); 33 | LogStream& operator<<(uint32_t v); 34 | LogStream& operator<<(int64_t v); 35 | LogStream& operator<<(uint64_t v); 36 | LogStream& operator<<(float v); 37 | LogStream& operator<<(double v); 38 | LogStream& operator<<(const std::string& v); 39 | LogStream& operator<<(const char* v); 40 | LogStream& operator<<(char v); 41 | 42 | private: 43 | LogStream(const LogStream&) = delete; 44 | LogStream& operator=(const LogStream&) = delete; 45 | 46 | private: 47 | std::shared_ptr _log; 48 | std::function)> _call_back; 49 | }; 50 | 51 | } // namespace cppnet 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /common/log/logger_interface.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef QUIC_COMMON_LOG_LOG_INTERFACE 7 | #define QUIC_COMMON_LOG_LOG_INTERFACE 8 | 9 | #include 10 | #include 11 | 12 | namespace cppnet { 13 | 14 | struct Log { 15 | char* _log; 16 | uint32_t _len; 17 | }; 18 | 19 | // inherit this class to print log. 20 | // can set subclasses for different print combinations. 21 | class Logger { 22 | public: 23 | Logger() {} 24 | virtual ~Logger() {} 25 | 26 | void SetLogger(std::shared_ptr logger) { _logger = logger; } 27 | std::shared_ptr GetLogger() { return _logger; } 28 | 29 | virtual void Debug(std::shared_ptr& log) { if(_logger) _logger->Debug(log); } 30 | virtual void Info(std::shared_ptr& log) { if(_logger) _logger->Info(log); } 31 | virtual void Warn(std::shared_ptr& log) { if(_logger) _logger->Warn(log); } 32 | virtual void Error(std::shared_ptr& log) { if(_logger) _logger->Error(log); } 33 | virtual void Fatal(std::shared_ptr& log) { if(_logger) _logger->Fatal(log); } 34 | 35 | protected: 36 | std::shared_ptr _logger; 37 | }; 38 | 39 | } // namespace cppnet 40 | 41 | #endif -------------------------------------------------------------------------------- /common/log/stdout_logger.cpp: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #include 7 | #include "common/log/stdout_logger.h" 8 | 9 | namespace cppnet { 10 | 11 | void StdoutLogger::Debug(std::shared_ptr& log) { 12 | { 13 | std::unique_lock lock(_mutex); 14 | std::cout<< log->_log << std::endl; 15 | } 16 | Logger::Debug(log); 17 | } 18 | 19 | void StdoutLogger::Info(std::shared_ptr& log) { 20 | { 21 | std::unique_lock lock(_mutex); 22 | std::cout<< log->_log << std::endl; 23 | } 24 | Logger::Info(log); 25 | } 26 | 27 | void StdoutLogger::Warn(std::shared_ptr& log) { 28 | { 29 | std::unique_lock lock(_mutex); 30 | std::cout<< log->_log << std::endl; 31 | } 32 | Logger::Warn(log); 33 | } 34 | 35 | void StdoutLogger::Error(std::shared_ptr& log) { 36 | { 37 | std::unique_lock lock(_mutex); 38 | std::cerr<< log->_log << std::endl; 39 | } 40 | Logger::Error(log); 41 | } 42 | 43 | void StdoutLogger::Fatal(std::shared_ptr& log) { 44 | { 45 | std::unique_lock lock(_mutex); 46 | std::cerr<< log->_log << std::endl; 47 | } 48 | Logger::Fatal(log); 49 | } 50 | 51 | } // namespace cppnet 52 | -------------------------------------------------------------------------------- /common/log/stdout_logger.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef QUIC_COMMON_LOG_STDOUT_LOGGER 7 | #define QUIC_COMMON_LOG_STDOUT_LOGGER 8 | 9 | #include 10 | #include "common/log/logger_interface.h" 11 | 12 | namespace cppnet { 13 | 14 | class StdoutLogger: 15 | public Logger { 16 | 17 | public: 18 | StdoutLogger() = default; 19 | ~StdoutLogger() = default; 20 | 21 | void Debug(std::shared_ptr& log); 22 | void Info(std::shared_ptr& log); 23 | void Warn(std::shared_ptr& log); 24 | void Error(std::shared_ptr& log); 25 | void Fatal(std::shared_ptr& log); 26 | 27 | private: 28 | std::mutex _mutex; 29 | }; 30 | 31 | } // namespace cppnet 32 | 33 | #endif -------------------------------------------------------------------------------- /common/network/address.cpp: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #include 7 | #include "common/network/address.h" 8 | 9 | namespace cppnet { 10 | 11 | Address::Address(): 12 | Address(AT_IPV6) { 13 | 14 | } 15 | 16 | Address::Address(AddressType at): 17 | _address_type(at), 18 | _ip(""), 19 | _port(0) { 20 | 21 | } 22 | 23 | Address::Address(AddressType at, const std::string& ip, uint16_t port): 24 | _address_type(at), 25 | _ip(ip), 26 | _port(port) { 27 | 28 | } 29 | 30 | Address::Address(const Address& addr): 31 | _address_type(addr._address_type), 32 | _ip(addr._ip), 33 | _port(addr._port) { 34 | 35 | } 36 | 37 | Address::~Address() { 38 | 39 | } 40 | 41 | void Address::SetIp(const std::string& ip) { 42 | if (_address_type == AT_IPV6) { 43 | _ip = ToIpv6(ip); 44 | 45 | } else { 46 | _ip = ToIpv4(ip); 47 | } 48 | } 49 | 50 | const std::string Address::AsString() { 51 | if (_address_type == AT_IPV6) { 52 | return "[" + _ip + "]:" + std::to_string(_port); 53 | 54 | } else { 55 | return _ip + ":" + std::to_string(_port); 56 | } 57 | } 58 | 59 | std::ostream& operator<< (std::ostream &out, Address &addr) { 60 | const std::string str = addr.AsString(); 61 | out.write(str.c_str(), str.length()); 62 | return out; 63 | } 64 | 65 | bool operator==(const Address &addr1, const Address &addr2) { 66 | return addr1._ip == addr2._ip && addr1._port == addr2._port && addr1._port != 0; 67 | } 68 | 69 | bool Address::IsIpv4(const std::string& ip) { 70 | if (ip.find(':') == std::string::npos) { 71 | return true; 72 | } 73 | 74 | return false; 75 | } 76 | 77 | std::string Address::ToIpv6(const std::string& ip) { 78 | if (!IsIpv4(ip)) { 79 | return ip; 80 | } 81 | 82 | std::string ret("::FFFF:"); 83 | ret.append(ip); 84 | return ret; 85 | } 86 | 87 | std::string Address::ToIpv4(const std::string& ip) { 88 | if (IsIpv4(ip)) { 89 | return ip; 90 | } 91 | std::size_t pos = ip.rfind(':'); 92 | 93 | return std::string(&ip[pos], ip.length() - pos); 94 | } 95 | 96 | } -------------------------------------------------------------------------------- /common/network/address.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_NETWORK_ADDRESS 7 | #define COMMON_NETWORK_ADDRESS 8 | 9 | #include 10 | #include 11 | 12 | namespace cppnet { 13 | 14 | enum AddressType { 15 | AT_IPV4 = 0x1, 16 | AT_IPV6 = 0x2, 17 | }; 18 | 19 | class Address { 20 | public: 21 | Address(); 22 | Address(AddressType at); 23 | Address(AddressType at, const std::string& ip, uint16_t port); 24 | Address(const Address& addr); 25 | ~Address(); 26 | 27 | void SetType(AddressType at) { _address_type = at; } 28 | AddressType GetType() { return _address_type; } 29 | 30 | void SetIp(const std::string& ip); 31 | const std::string& GetIp() { return _ip; } 32 | 33 | void SetAddrPort(uint16_t port) { _port = port; } 34 | uint16_t GetAddrPort() { return _port; } 35 | 36 | const std::string AsString(); 37 | 38 | friend std::ostream& operator<< (std::ostream &out, Address &addr); 39 | friend bool operator==(const Address &addr1, const Address &addr2); 40 | 41 | static bool IsIpv4(const std::string& ip); 42 | 43 | private: 44 | std::string ToIpv6(const std::string& ip); 45 | std::string ToIpv4(const std::string& ip); 46 | 47 | protected: 48 | AddressType _address_type; 49 | std::string _ip; 50 | uint16_t _port; 51 | }; 52 | 53 | } 54 | 55 | #endif -------------------------------------------------------------------------------- /common/network/io_handle.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_NETWORK_IO_HANDLE 7 | #define COMMON_NETWORK_IO_HANDLE 8 | 9 | #include 10 | #include "common/util/os_return.h" 11 | #include "common/network/address.h" 12 | 13 | namespace cppnet { 14 | 15 | struct Iovec { 16 | #ifdef __win__ 17 | size_t _iov_len; // size of buffer 18 | void* _iov_base; // starting address of buffer 19 | #else 20 | void* _iov_base; // starting address of buffer 21 | size_t _iov_len; // size of buffer 22 | #endif 23 | Iovec(void* base, size_t len): _iov_base(base), _iov_len(len) {} 24 | }; 25 | 26 | class OsHandle { 27 | public: 28 | static SysCallInt64Result TcpSocket(bool ipv4 = false); 29 | 30 | static SysCallInt32Result Bind(int64_t sockfd, Address& addr); 31 | 32 | static SysCallInt32Result Listen(int64_t sockfd, uint32_t len = 0); 33 | 34 | static SysCallInt32Result Connect(int64_t sockfd, Address& addr); 35 | 36 | static SysCallInt32Result Close(int64_t sockfd); 37 | 38 | static SysCallInt64Result Accept(int64_t sockfd, Address& address); 39 | 40 | static SysCallInt32Result Write(int64_t sockfd, const char *data, uint32_t len); 41 | static SysCallInt32Result Writev(int64_t sockfd, Iovec *vec, uint32_t vec_len); 42 | 43 | static SysCallInt32Result Recv(int64_t sockfd, char *data, uint32_t len, uint16_t flag); 44 | static SysCallInt32Result Readv(int64_t sockfd, Iovec *vec, uint32_t vec_len); 45 | 46 | }; 47 | 48 | } 49 | 50 | #endif -------------------------------------------------------------------------------- /common/network/posix/socket.cpp: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "common/network/socket.h" 12 | 13 | namespace cppnet { 14 | 15 | int32_t SocketNoblocking(uint64_t sock) { 16 | int32_t old_option = fcntl(sock, F_GETFL); 17 | int32_t new_option = old_option | O_NONBLOCK; 18 | fcntl(sock, F_SETFL, new_option); 19 | return old_option; 20 | } 21 | 22 | int32_t ReusePort(uint64_t sock) { 23 | int32_t opt = 1; 24 | int32_t ret = setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, 25 | &opt, static_cast(sizeof(opt))); 26 | return ret; 27 | } 28 | 29 | bool CheckConnect(const uint64_t sock) { 30 | /*struct pollfd fd; 31 | int32_t ret = 0; 32 | socklen_t len = 0; 33 | fd.fd = sock; 34 | fd.events = POLLOUT; 35 | if (poll(&fd, 1, 20000) == -1) { 36 | if(errno != EINTR){ 37 | return false; 38 | } 39 | }*/ 40 | int32_t ret = 0; 41 | socklen_t len = sizeof(ret); 42 | if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &ret, &len) == -1) { 43 | return false; 44 | } 45 | if(ret != 0) { 46 | return false; 47 | } 48 | return true; 49 | } 50 | 51 | 52 | } -------------------------------------------------------------------------------- /common/network/socket.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_NETWORK_SOCKET 7 | #define COMMON_NETWORK_SOCKET 8 | 9 | #include 10 | 11 | namespace cppnet { 12 | 13 | int32_t SocketNoblocking(uint64_t sock); 14 | 15 | int32_t ReusePort(uint64_t sock); 16 | 17 | // check socket connect 18 | bool CheckConnect(const uint64_t sock); 19 | 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /common/network/win/socket.cpp: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #include 7 | #include 8 | #include "common/network/socket.h" 9 | 10 | namespace cppnet { 11 | 12 | int32_t SocketNoblocking(uint64_t sock) { 13 | unsigned long ul = 1; 14 | return ioctlsocket(sock, FIONBIO, (unsigned long *)&ul); 15 | } 16 | 17 | int32_t ReusePort(uint64_t sock) { 18 | int32_t opt = 1; 19 | return setsockopt((SOCKET)sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt)); 20 | } 21 | 22 | bool CheckConnect(const uint64_t sock) { 23 | int32_t seconds; 24 | int32_t bytes = sizeof(seconds); 25 | int32_t iResult = 0; 26 | 27 | iResult = getsockopt(sock, SOL_SOCKET, SO_CONNECT_TIME, (char*)&seconds, (PINT)&bytes); 28 | if (iResult != NO_ERROR) { 29 | return false; 30 | 31 | } else { 32 | if (seconds == 0xFFFFFFFF) { 33 | return false; 34 | } 35 | } 36 | return true; 37 | } 38 | 39 | 40 | } -------------------------------------------------------------------------------- /common/os/convert.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_OS_CONVERT 7 | #define COMMON_OS_CONVERT 8 | 9 | #include 10 | 11 | namespace cppnet { 12 | 13 | void Localtime(const uint64_t* time, void* out_tm); 14 | 15 | char* ErrnoInfo(uint32_t err); 16 | 17 | } 18 | 19 | #endif -------------------------------------------------------------------------------- /common/os/os_info.cpp: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #include 7 | #include "common/os/os_info.h" 8 | 9 | uint32_t cppnet::GetCpuNum() { 10 | return std::thread::hardware_concurrency(); 11 | } -------------------------------------------------------------------------------- /common/os/os_info.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_OS_OS_INFO 7 | #define COMMON_OS_OS_INFO 8 | 9 | #include 10 | 11 | namespace cppnet { 12 | 13 | uint32_t GetCpuNum(); 14 | 15 | } 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /common/os/posix/convert.cpp: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #include 7 | #include 8 | #include "common/os/convert.h" 9 | 10 | namespace cppnet { 11 | 12 | void Localtime(const uint64_t* time, void* out_tm) { 13 | ::localtime_r((time_t*)time, (tm*)out_tm); 14 | } 15 | 16 | char* ErrnoInfo(uint32_t err) { 17 | return strerror(err); 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /common/os/win/convert.cpp: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #include 7 | #include 8 | #include "common/os/convert.h" 9 | 10 | namespace cppnet { 11 | 12 | void Localtime(const uint64_t* time, void* out_tm) { 13 | localtime_s((tm*)out_tm, (time_t*)time); 14 | } 15 | 16 | char* ErrnoInfo(uint32_t err) { 17 | LPVOID hlocal = NULL; 18 | ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL 19 | , err, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), (LPTSTR)&hlocal, 0, NULL); 20 | 21 | return (char*)hlocal; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /common/structure/list.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_STRUCTURE_LIST 7 | #define COMMON_STRUCTURE_LIST 8 | 9 | #include 10 | #include 11 | #include "common/structure/list_slot.h" 12 | 13 | namespace cppnet { 14 | 15 | template 16 | class List { 17 | public: 18 | List(): _size(0) {} 19 | ~List() {} 20 | 21 | uint32_t Size() { return _size; } 22 | 23 | std::shared_ptr GetHead() { return _head; } 24 | std::shared_ptr GetTail() { return _tail; } 25 | 26 | void Clear() { 27 | _size = 0; 28 | 29 | _head.reset(); 30 | _tail.reset(); 31 | } 32 | 33 | void PushBack(std::shared_ptr v) { 34 | if (!v) { 35 | return; 36 | } 37 | 38 | if (!_tail) { 39 | _tail = v; 40 | _head = v; 41 | 42 | } else { 43 | _tail->SetNext(v); 44 | v->SetPrev(_tail); 45 | _tail = v; 46 | } 47 | _size++; 48 | } 49 | 50 | std::shared_ptr PopBack() { 51 | if (!_tail) { 52 | return nullptr; 53 | } 54 | 55 | auto ret = _tail; 56 | _tail = _tail->GetPrev(); 57 | if (!_tail) { 58 | _head.reset(); 59 | 60 | } else { 61 | _tail->SetNext(nullptr); 62 | } 63 | _size--; 64 | 65 | return ret; 66 | } 67 | 68 | void PushFront(std::shared_ptr v) { 69 | if (!v) { 70 | return; 71 | } 72 | 73 | if (!_head) { 74 | _tail = v; 75 | _head = v; 76 | 77 | } else { 78 | _head->SetPrev(v); 79 | v->SetNext(_head); 80 | _head = v; 81 | } 82 | _size++; 83 | } 84 | 85 | std::shared_ptr PopFront() { 86 | if (!_head) { 87 | return nullptr; 88 | } 89 | 90 | auto ret = _head; 91 | _head = _head->GetNext(); 92 | if (!_head) { 93 | _tail.reset(); 94 | } 95 | 96 | _size--; 97 | 98 | return ret; 99 | } 100 | 101 | private: 102 | uint32_t _size; 103 | std::shared_ptr _head; 104 | std::shared_ptr _tail; 105 | }; 106 | 107 | } 108 | 109 | #endif -------------------------------------------------------------------------------- /common/structure/list_slot.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_STRUCTURE_LIST_SLOT 7 | #define COMMON_STRUCTURE_LIST_SLOT 8 | 9 | #include 10 | 11 | namespace cppnet { 12 | 13 | template 14 | class ListSlot { 15 | public: 16 | ListSlot() {} 17 | virtual ~ListSlot() {} 18 | 19 | void SetNext(std::shared_ptr v) { _next = v; } 20 | std::shared_ptr GetNext() { return _next; } 21 | 22 | void SetPrev(std::shared_ptr v) { _prev = v; } 23 | std::shared_ptr GetPrev() { return _prev.lock(); } 24 | 25 | protected: 26 | std::weak_ptr _prev; 27 | std::shared_ptr _next; 28 | }; 29 | 30 | } 31 | 32 | #endif -------------------------------------------------------------------------------- /common/structure/thread_safe_block_queue.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_STRUCTURE_THREAD_SAFE_BLOCK_QUEUE 7 | #define COMMON_STRUCTURE_THREAD_SAFE_BLOCK_QUEUE 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace cppnet { 14 | 15 | template 16 | class ThreadSafeBlockQueue { 17 | public: 18 | ThreadSafeBlockQueue() {} 19 | ~ThreadSafeBlockQueue() {} 20 | 21 | void Push(const T& element) { 22 | std::lock_guard lock(_mutex); 23 | _queue.push(element); 24 | _empty_notify.notify_one(); 25 | } 26 | 27 | T Pop() { 28 | std::unique_lock lock(_mutex); 29 | _empty_notify.wait(_mutex, [this]() {return !this->_queue.empty(); }); 30 | 31 | auto ret = std::move(_queue.front()); 32 | _queue.pop(); 33 | 34 | return ret; 35 | } 36 | 37 | void Clear() { 38 | std::lock_guard lock(_mutex); 39 | while (!_queue.empty()) { 40 | _queue.pop(); 41 | } 42 | } 43 | 44 | uint32_t Size() { 45 | std::lock_guard lock(_mutex); 46 | return _queue.size(); 47 | } 48 | 49 | bool Empty() { 50 | std::lock_guard lock(_mutex); 51 | return _queue.empty(); 52 | } 53 | 54 | private: 55 | std::mutex _mutex; 56 | std::queue _queue; 57 | std::condition_variable_any _empty_notify; 58 | }; 59 | 60 | } 61 | #endif -------------------------------------------------------------------------------- /common/structure/thread_safe_queue.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_STRUCTURE_THREAD_SAFE_QUEUE 7 | #define COMMON_STRUCTURE_THREAD_SAFE_QUEUE 8 | 9 | #include 10 | #include 11 | 12 | namespace cppnet { 13 | 14 | template 15 | class ThreadSafeQueue { 16 | public: 17 | ThreadSafeQueue() {} 18 | ~ThreadSafeQueue() {} 19 | 20 | void Push(const T& element) { 21 | std::unique_lock lock(_mutex); 22 | _queue.push(element); 23 | } 24 | 25 | bool Pop(T& value) { 26 | std::unique_lock lock(_mutex); 27 | if (_queue.empty()) { 28 | return false; 29 | } 30 | value = std::move(_queue.front()); 31 | _queue.pop(); 32 | return true; 33 | } 34 | 35 | void Clear() { 36 | std::unique_lock lock(_mutex); 37 | while (!_queue.empty()) { 38 | _queue.pop(); 39 | } 40 | } 41 | 42 | size_t Size() { 43 | std::unique_lock lock(_mutex); 44 | return _queue.size(); 45 | } 46 | 47 | bool Empty() { 48 | std::unique_lock lock(_mutex); 49 | return _queue.empty(); 50 | } 51 | 52 | private: 53 | std::mutex _mutex; 54 | std::queue _queue; 55 | }; 56 | 57 | } 58 | 59 | #endif -------------------------------------------------------------------------------- /common/structure/thread_safe_unordered_map.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_STRUCTURE_THREAD_SAFE_QUEUE 7 | #define COMMON_STRUCTURE_THREAD_SAFE_QUEUE 8 | 9 | #include 10 | #include 11 | 12 | namespace cppnet { 13 | 14 | template 15 | class ThreadSafeUnorderedMap { 16 | public: 17 | ThreadSafeUnorderedMap() {} 18 | ~ThreadSafeUnorderedMap() {} 19 | 20 | V& operator[] (const K& key) { 21 | std::lock_guard lock(_mutex); 22 | return _unordered_map[key]; 23 | } 24 | 25 | bool Find(const K& key) { 26 | std::lock_guard lock(_mutex); 27 | return _unordered_map.find(key) != _unordered_map.end(); 28 | } 29 | 30 | void Insert(const std::pair& item) { 31 | std::lock_guard lock(_mutex); 32 | _unordered_map.insert(item); 33 | } 34 | 35 | void Erase(const K& key) { 36 | std::lock_guard lock(_mutex); 37 | _unordered_map.erase(key); 38 | } 39 | 40 | void Clear() { 41 | std::lock_guard lock(_mutex); 42 | _unordered_map.clear(); 43 | } 44 | 45 | size_t Size() { 46 | std::lock_guard lock(_mutex); 47 | return _unordered_map.size(); 48 | } 49 | 50 | bool Empty() { 51 | std::lock_guard lock(_mutex); 52 | return _unordered_map.empty(); 53 | } 54 | 55 | std::unordered_map& GetMap() { 56 | return _unordered_map; 57 | } 58 | 59 | private: 60 | std::unordered_map _unordered_map; 61 | std::mutex _mutex; 62 | }; 63 | 64 | } 65 | 66 | #endif -------------------------------------------------------------------------------- /common/thread/thread.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_THREAD_THREAD 7 | #define COMMON_THREAD_THREAD 8 | 9 | #include // about thread 10 | #include // for atomic_bool 11 | #include // for shared_ptr 12 | #include // for bind 13 | 14 | namespace cppnet { 15 | 16 | class Thread { 17 | public: 18 | Thread(): _stop(true) {} 19 | virtual ~Thread() {} 20 | 21 | //base option 22 | virtual void Start() { 23 | _stop = false; 24 | if (!_thread) { 25 | _thread = std::unique_ptr(new std::thread(std::bind(&Thread::Run, this))); 26 | } 27 | } 28 | 29 | virtual void Stop() { 30 | _stop = true; 31 | } 32 | 33 | virtual void Join() { 34 | if (_thread && _thread->joinable()) { 35 | _thread->join(); 36 | } 37 | } 38 | //TO DO 39 | virtual void Run() = 0; 40 | 41 | virtual bool IsStop() { 42 | return _stop; 43 | } 44 | 45 | protected: 46 | Thread(const Thread&) = delete; 47 | Thread& operator=(const Thread&) = delete; 48 | 49 | protected: 50 | std::atomic_bool _stop; 51 | std::unique_ptr _thread; 52 | }; 53 | 54 | } 55 | #endif -------------------------------------------------------------------------------- /common/thread/thread_with_queue.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_THREAD_THREAD_WITH_QUEUE 7 | #define COMMON_THREAD_THREAD_WITH_QUEUE 8 | 9 | #include "common/thread/thread.h" 10 | #include "common/structure/thread_safe_block_queue.h" 11 | 12 | namespace cppnet { 13 | 14 | template 15 | class ThreadWithQueue: 16 | public Thread { 17 | 18 | public: 19 | ThreadWithQueue() {} 20 | virtual ~ThreadWithQueue() {} 21 | 22 | uint32_t GetQueueSize() { 23 | return _queue.Size(); 24 | } 25 | 26 | void Push(const T& t) { 27 | _queue.Push(t); 28 | } 29 | 30 | T Pop() { 31 | return std::move(_queue.Pop()); 32 | } 33 | 34 | //TO DO 35 | virtual void Run() = 0; 36 | 37 | protected: 38 | ThreadWithQueue(const ThreadWithQueue&) = delete; 39 | ThreadWithQueue& operator=(const ThreadWithQueue&) = delete; 40 | 41 | private: 42 | ThreadSafeBlockQueue _queue; 43 | }; 44 | 45 | } 46 | #endif -------------------------------------------------------------------------------- /common/timer/timer.cpp: -------------------------------------------------------------------------------- 1 | 2 | // Use of this source code is governed by a BSD 3-Clause License 3 | // that can be found in the LICENSE file. 4 | 5 | // Author: caozhiyi (caozhiyi5@gmail.com) 6 | 7 | #include "common/timer/timer.h" 8 | #include "common/timer/timer_container.h" 9 | 10 | namespace cppnet { 11 | 12 | std::shared_ptr MakeTimer1Sec() { 13 | return std::make_shared(nullptr, TU_MILLISECOND, TU_SECOND); 14 | } 15 | 16 | std::shared_ptr MakeTimer1Min() { 17 | auto sec_sub = std::make_shared(nullptr, TU_MILLISECOND, TU_SECOND); 18 | auto timer = std::make_shared(sec_sub, TU_SECOND, TU_MINUTE); 19 | sec_sub->SetRootTimer(timer); 20 | return timer; 21 | } 22 | 23 | std::shared_ptr MakeTimer1Hour() { 24 | auto sec_sub = std::make_shared(nullptr, TU_MILLISECOND, TU_SECOND); 25 | auto min_sub = std::make_shared(sec_sub, TU_SECOND, TU_MINUTE); 26 | auto timer = std::make_shared(min_sub, TU_MINUTE, TU_HOUR); 27 | sec_sub->SetRootTimer(timer); 28 | min_sub->SetRootTimer(timer); 29 | 30 | return timer; 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /common/timer/timer.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_TIMER_TIMER 7 | #define COMMON_TIMER_TIMER 8 | 9 | #include 10 | #include "common/timer/timer_interface.h" 11 | 12 | namespace cppnet { 13 | 14 | std::shared_ptr MakeTimer1Sec(); 15 | 16 | std::shared_ptr MakeTimer1Min(); 17 | 18 | std::shared_ptr MakeTimer1Hour(); 19 | 20 | } 21 | 22 | #endif -------------------------------------------------------------------------------- /common/timer/timer_container.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_TIMER_TIMER_CONTAINER 7 | #define COMMON_TIMER_TIMER_CONTAINER 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "common/util/bitmap.h" 15 | #include "common/timer/timer_interface.h" 16 | 17 | namespace cppnet { 18 | 19 | // timer wheel container, include a sub timer. 20 | // if set timeout time is little than accuracy, will be added to sub timer wheel. 21 | // It inherits from the timer interface, 22 | // so can set another timer wheel container to sub timer to support more timer set. 23 | // More timer define see timer.h file. 24 | class TimerContainer: 25 | public Timer { 26 | 27 | public: 28 | TimerContainer(std::shared_ptr sub_timer, TIME_UNIT unit, TIME_UNIT max); 29 | ~TimerContainer(); 30 | 31 | bool AddTimer(std::weak_ptr t, uint32_t time, bool always = false); 32 | bool RmTimer(std::weak_ptr t); 33 | 34 | // get min next time out time 35 | // return 36 | // >= 0 : the next time 37 | // < 0 : has no timer 38 | int32_t MinTime(); 39 | // return the timer wheel current time 40 | int32_t CurrentTimer(); 41 | // timer wheel run time 42 | // return carry 43 | uint32_t TimerRun(uint32_t step); 44 | 45 | bool Empty(); 46 | void Clear(); 47 | 48 | // get current timer wheel timeout time 49 | int32_t LocalMinTime(); 50 | bool InnerAddTimer(std::shared_ptr ptr, uint32_t time); 51 | 52 | void SetRootTimer(std::shared_ptr timer) { _root_timer = timer; } 53 | 54 | protected: 55 | uint16_t TimeUnit2TimeType(TIME_UNIT tu); 56 | uint32_t GetIndexLeftInterval(uint16_t index); 57 | void GetIndexTimer(std::vector>& run_timer_solts, 58 | std::vector>& sub_timer_solts, uint32_t index, uint32_t time_pass); 59 | void DoTimer(std::vector>& run_timer_solts, 60 | std::vector>& sub_timer_solts); 61 | 62 | protected: 63 | TIME_UNIT _time_unit; 64 | uint32_t _size; 65 | uint32_t _timer_max; 66 | 67 | uint32_t _cur_time; 68 | Bitmap _bitmap; 69 | std::weak_ptr _root_timer; 70 | std::shared_ptr _sub_timer; 71 | std::unordered_map>>> _timer_wheel; 72 | //std::unordered_map>> _timer_wheel; 73 | }; 74 | 75 | } 76 | 77 | #endif -------------------------------------------------------------------------------- /common/timer/timer_interface.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_TIMER_TIMER_INTERFACE 7 | #define COMMON_TIMER_TIMER_INTERFACE 8 | 9 | #include 10 | #include 11 | 12 | namespace cppnet { 13 | 14 | // time unit 15 | enum TIME_UNIT: uint32_t { 16 | TU_MILLISECOND = 1, 17 | TU_SECOND = TU_MILLISECOND * 1000, 18 | TU_MINUTE = TU_SECOND * 60, 19 | TU_HOUR = TU_MINUTE * 60, 20 | }; 21 | 22 | enum TIMER_CODE { 23 | NO_TIMER = -1 // don't have timer 24 | }; 25 | 26 | class TimerSlot; 27 | 28 | // timer interface, timer inherits from this. 29 | class Timer { 30 | public: 31 | Timer() {} 32 | ~Timer() {} 33 | 34 | virtual bool AddTimer(std::weak_ptr t, uint32_t time, bool always = false) = 0; 35 | virtual bool RmTimer(std::weak_ptr t) = 0; 36 | 37 | // get min next time out time 38 | // return: 39 | // >= 0 : the next time 40 | // < 0 : has no timer 41 | virtual int32_t MinTime() = 0; 42 | 43 | // return the timer wheel current time 44 | virtual int32_t CurrentTimer() = 0; 45 | 46 | // timer wheel run time 47 | // return carry 48 | virtual uint32_t TimerRun(uint32_t time) = 0; 49 | 50 | virtual bool Empty() = 0; 51 | }; 52 | 53 | } 54 | 55 | #endif -------------------------------------------------------------------------------- /common/timer/timer_slot.cpp: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #include "common/timer/timer_slot.h" 7 | 8 | namespace cppnet { 9 | 10 | TimerSlot::TimerSlot(): 11 | _total_interval(0), 12 | _left_interval(0) { 13 | 14 | } 15 | 16 | void TimerSlot::SetInterval(uint32_t interval) { 17 | _total_interval = interval; 18 | _left_interval = interval; 19 | } 20 | 21 | uint32_t TimerSlot::GetTotalInterval() { 22 | _total_interval &= ~(TSF_ALWAYS | TSF_IN_TIMER); 23 | return _total_interval; 24 | } 25 | 26 | uint32_t TimerSlot::GetLeftInterval() { 27 | return _left_interval; 28 | } 29 | 30 | void TimerSlot::ResetTime() { 31 | _left_interval = _total_interval; 32 | _cur_index = 0; 33 | } 34 | 35 | uint32_t TimerSlot::TimePass(uint32_t time) { 36 | _left_interval -= time; 37 | return _left_interval; 38 | } 39 | 40 | void TimerSlot::SetInTimer() { 41 | _total_interval |= TSF_IN_TIMER; 42 | } 43 | 44 | bool TimerSlot::IsInTimer() { 45 | return _total_interval & TSF_IN_TIMER; 46 | } 47 | 48 | void TimerSlot::RmInTimer() { 49 | _total_interval &= ~TSF_IN_TIMER; 50 | } 51 | 52 | void TimerSlot::SetAlways() { 53 | _total_interval |= TSF_ALWAYS; 54 | } 55 | 56 | bool TimerSlot::IsAlways() { 57 | return _total_interval & TSF_ALWAYS; 58 | } 59 | 60 | void TimerSlot::RmAlways() { 61 | _total_interval &= ~TSF_ALWAYS; 62 | } 63 | 64 | void TimerSlot::SetCurIndex(uint16_t index, uint16_t type) { 65 | _cur_index = index | type; 66 | } 67 | 68 | void TimerSlot::GetCurIndex(uint16_t& index, uint16_t& type) { 69 | index = _cur_index & ~TIT_MUSK; 70 | type = _cur_index & TIT_MUSK; 71 | } 72 | 73 | } -------------------------------------------------------------------------------- /common/timer/timer_slot.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_TIMER_TIMER_SLOT 7 | #define COMMON_TIMER_TIMER_SLOT 8 | 9 | #include 10 | #include "common/timer/timer_interface.h" 11 | 12 | namespace cppnet { 13 | 14 | enum TIME_INDEX_TYPE: uint16_t { 15 | TIT_MILLISECOND = 0x01 << 10, 16 | TIT_SECOND = 0x02 << 10, 17 | TIT_MINUTE = 0x04 << 10, 18 | TIT_MUSK = 0x07 << 10, 19 | }; 20 | 21 | // Inherit this class to add to timer. 22 | // don't call any function in this class, 23 | // they internal used by timer. 24 | class TimerSlot { 25 | public: 26 | TimerSlot(); 27 | ~TimerSlot() {} 28 | 29 | //private: 30 | public: 31 | enum TIMER_SOLT_FLAG: uint32_t { 32 | TSF_IN_TIMER = (uint32_t)1 << 30, 33 | TSF_ALWAYS = (uint32_t)1 << 31, 34 | }; 35 | 36 | // timer out call back 37 | virtual void OnTimer() = 0; 38 | 39 | void SetInterval(uint32_t interval); 40 | uint32_t GetTotalInterval(); 41 | uint32_t GetLeftInterval(); 42 | 43 | void ResetTime(); 44 | uint32_t TimePass(uint32_t time); 45 | 46 | void SetInTimer(); 47 | bool IsInTimer(); 48 | void RmInTimer(); 49 | 50 | void SetAlways(); 51 | bool IsAlways(); 52 | void RmAlways(); 53 | 54 | void SetCurIndex(uint16_t index, uint16_t type); 55 | void GetCurIndex(uint16_t& index, uint16_t& type); 56 | 57 | private: 58 | friend class TimerContainer; 59 | 60 | uint32_t _total_interval; 61 | uint32_t _left_interval; 62 | 63 | uint16_t _cur_index; 64 | }; 65 | 66 | } 67 | 68 | #endif -------------------------------------------------------------------------------- /common/util/any.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_UTIL_ANY 7 | #define COMMON_UTIL_ANY 8 | 9 | #include 10 | #include 11 | 12 | namespace cppnet { 13 | 14 | class Any { 15 | public: 16 | Any(): _content(0) {} 17 | template 18 | Any(const ValueType & value): _content(new CHolder(value)) {} 19 | Any(const Any & other): _content(other._content ? other._content->Clone() : 0) {} 20 | Any(Any&& other): _content(other._content) { 21 | other._content = 0; 22 | } 23 | ~Any() { 24 | delete _content; 25 | } 26 | public: // modifiers 27 | Any& Swap(Any & rhs) { 28 | std::swap(_content, rhs._content); 29 | return *this; 30 | } 31 | template 32 | Any& operator=(const ValueType & rhs) { 33 | Any(rhs).Swap(*this); 34 | return *this; 35 | } 36 | Any& operator=(Any rhs) { 37 | Any(rhs).Swap(*this); 38 | return *this; 39 | } 40 | // move assignement 41 | Any& operator=(Any&& rhs) { 42 | rhs.Swap(*this); 43 | Any().Swap(rhs); 44 | return *this; 45 | } 46 | public: // queries 47 | bool Empty() const { 48 | return !_content; 49 | } 50 | void Clear() { 51 | Any().Swap(*this); 52 | } 53 | const std::type_info& Type() const { 54 | return _content ? _content->Type() : typeid(void); 55 | } 56 | class CPlaceHolder { 57 | public: 58 | virtual ~CPlaceHolder() { 59 | } 60 | // queries 61 | virtual const std::type_info& Type() const = 0; 62 | virtual CPlaceHolder * Clone() const = 0; 63 | }; 64 | template 65 | class CHolder : public CPlaceHolder { 66 | public: 67 | CHolder(const ValueType& value) : _held(value) { 68 | } 69 | CHolder(ValueType&& value) : _held(static_cast(value)) { 70 | } 71 | // queries 72 | virtual const std::type_info& Type() const { 73 | return typeid(ValueType); 74 | } 75 | virtual CPlaceHolder * Clone() const { 76 | return new CHolder(_held); 77 | } 78 | public: 79 | ValueType _held; 80 | private: 81 | CHolder & operator=(const CHolder&) {} 82 | }; 83 | private: // representation 84 | template 85 | friend ValueType* any_cast(Any *) ; 86 | CPlaceHolder* _content; 87 | }; 88 | 89 | template 90 | ValueType* any_cast(Any * operand) { 91 | if (operand && operand->Type() == typeid(ValueType)) { 92 | return &static_cast *>(operand->_content)->_held; 93 | } 94 | return nullptr; 95 | } 96 | 97 | template 98 | const ValueType * any_cast(const Any * operand) { 99 | return any_cast(const_cast(operand)); 100 | } 101 | 102 | template 103 | ValueType any_cast(Any & operand) { 104 | ValueType * result = any_cast(&operand); 105 | if (!result) { 106 | throw "bad_any_cast: failed conversion using any_cast"; 107 | } 108 | return static_cast(*result); 109 | } 110 | 111 | template 112 | inline ValueType any_cast(const Any& operand) { 113 | return any_cast(const_cast(operand)); 114 | } 115 | 116 | template 117 | inline ValueType any_cast(Any&& operand) { 118 | return any_cast(operand); 119 | } 120 | 121 | } 122 | 123 | #endif -------------------------------------------------------------------------------- /common/util/bitmap.cpp: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #include 7 | #include "common/util/bitmap.h" 8 | 9 | namespace cppnet { 10 | 11 | static const uint32_t __step_size = sizeof(int64_t) * 8; 12 | static const uint64_t __setp_base = 1; 13 | 14 | Bitmap::Bitmap(): 15 | _vec_bitmap(0) { 16 | 17 | } 18 | 19 | Bitmap::~Bitmap() { 20 | 21 | } 22 | 23 | bool Bitmap::Init(uint32_t size) { 24 | uint32_t vec_size = size / __step_size; 25 | // too large size 26 | if (vec_size > sizeof(_vec_bitmap) * 8) { 27 | return false; 28 | } 29 | if (size % __step_size > 0) { 30 | vec_size++; 31 | } 32 | _bitmap.resize(vec_size); 33 | for (std::size_t i = 0; i < _bitmap.size(); i++) { 34 | _bitmap[i] = 0; 35 | } 36 | return true; 37 | } 38 | 39 | bool Bitmap::Insert(uint32_t index) { 40 | if (index > _bitmap.size() * __step_size) { 41 | return false; 42 | } 43 | 44 | // get index in vector 45 | uint32_t bitmap_index = index / __step_size; 46 | // get index in uint64_t 47 | uint32_t bit_index = index % __step_size; 48 | 49 | _bitmap[bitmap_index] |= __setp_base << bit_index; 50 | _vec_bitmap |= __setp_base << bitmap_index; 51 | 52 | return true; 53 | } 54 | 55 | bool Bitmap::Remove(uint32_t index) { 56 | if (index > _bitmap.size() * __step_size) { 57 | return false; 58 | } 59 | 60 | // get index in vector 61 | uint32_t bitmap_index = index / __step_size; 62 | // get index in uint64_t 63 | uint32_t bit_index = index % __step_size; 64 | 65 | _bitmap[bitmap_index] &= ~(__setp_base << bit_index); 66 | if (_bitmap[bitmap_index] == 0) { 67 | _vec_bitmap &= ~(__setp_base << bitmap_index); 68 | } 69 | return true; 70 | } 71 | 72 | int32_t Bitmap::GetMinAfter(uint32_t index) { 73 | // get next bit. 74 | if (index >= _bitmap.size() * __step_size || Empty()) { 75 | return -1; 76 | } 77 | 78 | // get index in vector 79 | uint32_t bitmap_index = index / __step_size; 80 | // filter smaller bitmap index 81 | uint32_t ret = bitmap_index * __step_size; 82 | 83 | // find current uint64_t have next 1? 84 | if (_bitmap[bitmap_index] != 0) { 85 | int64_t cur_bitmap = _bitmap[bitmap_index]; 86 | int32_t cur_step = index - ret; 87 | cur_bitmap = cur_bitmap >> cur_step; 88 | 89 | // don't have next 1 90 | if (cur_bitmap == 0) { 91 | ret += __step_size; 92 | 93 | // find next 1 94 | } else { 95 | ret += cur_step; 96 | ret += (uint32_t)std::log2f(float(cur_bitmap & (-cur_bitmap))); 97 | return ret; 98 | } 99 | 100 | } else { 101 | ret += __step_size; 102 | } 103 | 104 | // find next used vector index 105 | int32_t temp_vec_bitmap = _vec_bitmap >> bitmap_index; 106 | if (temp_vec_bitmap == 0) { 107 | return -1; 108 | } 109 | 110 | uint32_t next_vec_index = (uint32_t)std::log2f(float((temp_vec_bitmap & (-temp_vec_bitmap)) + 1)); 111 | uint32_t target_vec_index = next_vec_index + bitmap_index; 112 | if (target_vec_index == bitmap_index) { 113 | return -1; 114 | } 115 | 116 | if (target_vec_index >= _bitmap.size()) { 117 | return -1; 118 | } 119 | 120 | int64_t cur_bitmap = _bitmap[target_vec_index]; 121 | ret += (next_vec_index - 1) * __step_size; 122 | ret += (uint32_t)std::log2f(float((cur_bitmap & (-cur_bitmap)) + 1)); 123 | 124 | return ret; 125 | } 126 | 127 | bool Bitmap::Empty() { 128 | return _vec_bitmap == 0; 129 | } 130 | 131 | void Bitmap::Clear() { 132 | while (_vec_bitmap != 0) { 133 | int32_t next_vec_index = (int32_t)std::log2f(float((_vec_bitmap & (-(int32_t)_vec_bitmap)) + 1)); 134 | _bitmap[next_vec_index] = 0; 135 | _vec_bitmap = _vec_bitmap & (_vec_bitmap - 1); 136 | } 137 | } 138 | 139 | } -------------------------------------------------------------------------------- /common/util/bitmap.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_UTIL_BITMAP 7 | #define COMMON_UTIL_BITMAP 8 | 9 | #include 10 | #include 11 | 12 | namespace cppnet { 13 | 14 | // bitmap base on array. 15 | // find next valid bit in O(1) time. 16 | class Bitmap { 17 | public: 18 | Bitmap(); 19 | ~Bitmap(); 20 | 21 | // init whit array size. 22 | // one size means bitmap support 64 bit set. 23 | bool Init(uint32_t size); 24 | 25 | // return false if input param more than bitmap support size. 26 | bool Insert(uint32_t index); 27 | 28 | // return true even the bit is not in bitmap 29 | bool Remove(uint32_t index); 30 | 31 | // get min index after input param 32 | // if return -1, means the bitmap has no value 33 | int32_t GetMinAfter(uint32_t index = 0); 34 | 35 | // bitmap is empty 36 | bool Empty(); 37 | 38 | void Clear(); 39 | 40 | private: 41 | // which index of vector used 42 | uint32_t _vec_bitmap; 43 | // all bit 44 | std::vector _bitmap; 45 | }; 46 | 47 | } 48 | 49 | #endif -------------------------------------------------------------------------------- /common/util/config.cpp: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #include 7 | #include 8 | 9 | #include "common/log/log.h" 10 | #include "common/util/config.h" 11 | 12 | namespace cppnet { 13 | 14 | void Config::SetFilePath(const std::string& path) { 15 | _file = path; 16 | } 17 | 18 | bool Config::ReLoadFile() { 19 | return LoadFile(_file); 20 | } 21 | 22 | bool Config::LoadFile(const std::string& path) { 23 | SetFilePath(path); 24 | std::fstream file(path); 25 | if (!file) { 26 | LOG_ERROR("load config file failed, can't open file."); 27 | return false; 28 | } 29 | std::string line; 30 | std::string key; 31 | std::string value; 32 | std::map temp_map; 33 | while (!file.eof()) { 34 | char buf[1024] = { 0 }; 35 | file.getline(buf, 1024); 36 | if (strlen(buf) < 3) { 37 | continue; 38 | } 39 | line = buf; 40 | _Trim(line); 41 | if (line[0] == '#') { 42 | continue; 43 | } 44 | 45 | key = line.substr(0, line.find_first_of("=")); 46 | value = line.substr(line.find_first_of("=") + 1); 47 | _Trim(key); 48 | _Trim(value); 49 | LOG_INFO("load config key : %s, value : %s", key.c_str(), value.c_str()); 50 | temp_map[key] = value; 51 | } 52 | 53 | std::unique_lock lock(_mutex); 54 | _config_map = temp_map; 55 | return true; 56 | } 57 | 58 | int Config::GetIntValue(const std::string& key) { 59 | try { 60 | std::unique_lock lock(_mutex); 61 | auto iter = _config_map.find(key); 62 | if (iter != _config_map.end()) { 63 | return atoi(iter->second.c_str()); 64 | } 65 | return -1; 66 | 67 | } catch (...) { 68 | LOG_ERROR("get config int value failed."); 69 | return -1; 70 | } 71 | } 72 | 73 | std::string Config::GetStringValue(const std::string& key) { 74 | try { 75 | std::unique_lock lock(_mutex); 76 | auto iter = _config_map.find(key); 77 | if (iter != _config_map.end()) { 78 | return iter->second; 79 | } 80 | return ""; 81 | 82 | } catch (...) { 83 | LOG_ERROR("get config string value failed."); 84 | return ""; 85 | } 86 | } 87 | 88 | double Config::GetDoubleValue(const std::string& key) { 89 | try { 90 | std::unique_lock lock(_mutex); 91 | auto iter = _config_map.find(key); 92 | if (iter != _config_map.end()) { 93 | return atof(iter->second.c_str()); 94 | } 95 | return -1; 96 | 97 | } catch (...) { 98 | LOG_ERROR("get config double value failed."); 99 | return -1; 100 | } 101 | } 102 | 103 | bool Config::GetBoolValue(const std::string& key) { 104 | try { 105 | std::unique_lock lock(_mutex); 106 | auto iter = _config_map.find(key); 107 | if (iter != _config_map.end()) { 108 | return iter->second == "true" || iter->second == "1"; 109 | } 110 | return false; 111 | 112 | } catch (...) { 113 | LOG_ERROR("get config double value failed."); 114 | return false; 115 | } 116 | } 117 | 118 | void Config::_Trim(std::string& line) { 119 | if (line.empty()) { 120 | return; 121 | } 122 | line.erase(0, line.find_first_not_of(" ")); 123 | line.erase(line.find_last_not_of(" ") + 1); 124 | } 125 | 126 | } -------------------------------------------------------------------------------- /common/util/config.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_UTIL_CONFIG 7 | #define COMMON_UTIL_CONFIG 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace cppnet { 14 | 15 | class Config { 16 | public: 17 | void SetFilePath(const std::string& path); 18 | bool ReLoadFile(); 19 | 20 | bool LoadFile(const std::string& path); 21 | 22 | int GetIntValue(const std::string& key); 23 | std::string GetStringValue(const std::string& key); 24 | double GetDoubleValue(const std::string& key); 25 | bool GetBoolValue(const std::string& key); 26 | 27 | private: 28 | void _Trim(std::string& line); 29 | 30 | private: 31 | std::string _file; 32 | std::mutex _mutex; 33 | std::map _config_map; 34 | }; 35 | 36 | } 37 | #endif 38 | -------------------------------------------------------------------------------- /common/util/os_return.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_UTIL_OS_RETURN 7 | #define COMMON_UTIL_OS_RETURN 8 | 9 | #include 10 | 11 | namespace cppnet { 12 | 13 | template 14 | struct SysCallResult { 15 | T _return_value; 16 | int32_t _errno; 17 | }; 18 | 19 | using SysCallInt32Result = SysCallResult; 20 | using SysCallInt64Result = SysCallResult; 21 | 22 | } 23 | 24 | #endif -------------------------------------------------------------------------------- /common/util/random.cpp: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #include 7 | #include "common/util/random.h" 8 | 9 | namespace cppnet { 10 | 11 | std::random_device RangeRandom::_random; 12 | std::mt19937 RangeRandom::_engine(_random()); 13 | 14 | RangeRandom::RangeRandom(int32_t min, int32_t max): 15 | _uniform(min, max) { 16 | 17 | } 18 | 19 | RangeRandom::~RangeRandom() { 20 | 21 | } 22 | 23 | int32_t RangeRandom::Random() { 24 | return _uniform(_engine); 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /common/util/random.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_UTIL_RANDOM 7 | #define COMMON_UTIL_RANDOM 8 | 9 | #include 10 | #include 11 | 12 | namespace cppnet { 13 | 14 | class RangeRandom { 15 | public: 16 | RangeRandom(int32_t min, int32_t max); 17 | ~RangeRandom(); 18 | 19 | int32_t Random(); 20 | 21 | private: 22 | static std::random_device _random; 23 | static std::mt19937 _engine; 24 | std::uniform_int_distribution _uniform; 25 | }; 26 | 27 | } // namespace cppnet 28 | 29 | #endif -------------------------------------------------------------------------------- /common/util/singleton.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_UTIL_SINGLETON 7 | #define COMMON_UTIL_SINGLETON 8 | 9 | namespace cppnet { 10 | 11 | template 12 | class Singleton { 13 | public: 14 | static T& Instance() { 15 | static T instance; 16 | return instance; 17 | } 18 | 19 | protected: 20 | Singleton(const Singleton&) {} 21 | Singleton& operator = (const Singleton&) {} 22 | Singleton() {} 23 | virtual ~Singleton() {} 24 | }; 25 | 26 | } 27 | #endif -------------------------------------------------------------------------------- /common/util/time.cpp: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #include 7 | #include 8 | #include "time.h" 9 | #include "common/os/convert.h" 10 | 11 | namespace cppnet { 12 | 13 | uint64_t UTCTimeSec() { 14 | return std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); 15 | } 16 | 17 | uint64_t UTCTimeMsec() { 18 | return std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); 19 | } 20 | 21 | std::string GetFormatTime(FormatTimeUnit unit) { 22 | char buf[__format_time_buf_size] = {0}; 23 | uint32_t len = __format_time_buf_size; 24 | 25 | GetFormatTime(buf, len, unit); 26 | return std::move(std::string(buf, len)); 27 | } 28 | 29 | void GetFormatTime(char* buf, uint32_t& len, FormatTimeUnit unit) { 30 | auto now_time = std::chrono::system_clock::now(); 31 | auto now_time_t = std::chrono::system_clock::to_time_t(now_time); 32 | 33 | int32_t millisecond = 0; 34 | if (unit == FTU_MILLISECOND) { 35 | auto msec = std::chrono::duration_cast(now_time.time_since_epoch()).count(); 36 | auto sec = std::chrono::duration_cast(now_time.time_since_epoch()).count(); 37 | millisecond = (int32_t)(msec - (sec * 1000)); 38 | } 39 | 40 | tm time; 41 | Localtime((uint64_t*)&now_time_t, (void*)&time); 42 | switch (unit) 43 | { 44 | case FTU_MILLISECOND: 45 | len = snprintf(buf, len, "%04d-%02d-%02d:%02d:%02d:%02d:%03d", 1900 + time.tm_year, 1 + time.tm_mon, time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec, millisecond); 46 | break; 47 | case FTU_SECOND: 48 | len = snprintf(buf, len, "%04d-%02d-%02d:%02d:%02d:%02d", 1900 + time.tm_year, 1 + time.tm_mon, time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec); 49 | break; 50 | case FTU_MINUTE: 51 | len = snprintf(buf, len, "%04d-%02d-%02d:%02d:%02d", 1900 + time.tm_year, 1 + time.tm_mon, time.tm_mday, time.tm_hour, time.tm_min); 52 | break; 53 | case FTU_HOUR: 54 | len = snprintf(buf, len, "%04d-%02d-%02d:%02d", 1900 + time.tm_year, 1 + time.tm_mon, time.tm_mday, time.tm_hour); 55 | break; 56 | case FTU_DAY: 57 | len = snprintf(buf, len, "%04d-%02d-%02d", 1900 + time.tm_year, 1 + time.tm_mon, time.tm_mday); 58 | break; 59 | case FTU_MONTH: 60 | len = snprintf(buf, len, "%04d-%02d", 1900 + time.tm_year, 1 + time.tm_mon); 61 | break; 62 | case FTU_YEAR: 63 | len = snprintf(buf, len, "%04d", 1900 + time.tm_year); 64 | break; 65 | default: 66 | // default FTU_MILLISECOND 67 | len = snprintf(buf, len, "%04d-%02d-%02d:%02d:%02d:%02d:%03d", 1900 + time.tm_year, 1 + time.tm_mon, time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec, millisecond); 68 | break; 69 | } 70 | } 71 | 72 | 73 | void Sleep(uint32_t interval) { 74 | std::this_thread::sleep_for(std::chrono::milliseconds(interval)); 75 | } 76 | 77 | 78 | } -------------------------------------------------------------------------------- /common/util/time.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef COMMON_UTIL_TIME 7 | #define COMMON_UTIL_TIME 8 | 9 | #include 10 | 11 | namespace cppnet { 12 | 13 | static const uint8_t __format_time_buf_size = sizeof("xxxx-xx-xx:xx:xx:xx:xxx"); 14 | 15 | enum FormatTimeUnit { 16 | FTU_YEAR = 1, // 2021 17 | FTU_MONTH = 2, // 2021-03 18 | FTU_DAY = 3, // 2021-03-16 19 | FTU_HOUR = 4, // 2021-03-16:10 20 | FTU_MINUTE = 5, // 2021-03-16:10:03 21 | FTU_SECOND = 6, // 2021-03-16:10:03:33 22 | FTU_MILLISECOND = 7, // 2021-03-16:10:03:33:258 23 | }; 24 | 25 | // get format time string [xxxx-xx-xx xx:xx:xx] 26 | std::string GetFormatTime(FormatTimeUnit unit = FTU_MILLISECOND); 27 | // get format time string as [xxxx-xx-xx xx:xx:xx] 28 | void GetFormatTime(char* buf, uint32_t& len, FormatTimeUnit unit = FTU_MILLISECOND); 29 | 30 | // get utc time 31 | uint64_t UTCTimeSec(); 32 | uint64_t UTCTimeMsec(); 33 | 34 | // sleep interval milliseconds 35 | void Sleep(uint32_t interval); 36 | 37 | } 38 | 39 | #endif -------------------------------------------------------------------------------- /cppnet/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | project(cppnet CXX) 4 | 5 | aux_source_directory(${PROJECT_SOURCE_DIR} src_files) 6 | aux_source_directory(${PROJECT_SOURCE_DIR}/event src_files) 7 | aux_source_directory(${PROJECT_SOURCE_DIR}/socket src_files) 8 | 9 | IF(WIN32) 10 | aux_source_directory(${PROJECT_SOURCE_DIR}/event/epoll src_files) 11 | aux_source_directory(${PROJECT_SOURCE_DIR}/event/epoll/wepoll src_files) 12 | ELSEIF(APPLE) 13 | aux_source_directory(${PROJECT_SOURCE_DIR}/event/kqueue src_files) 14 | ELSEIF(UNIX) 15 | IF(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") 16 | aux_source_directory(${PROJECT_SOURCE_DIR}/event/kqueue src_files) 17 | ELSE() 18 | aux_source_directory(${PROJECT_SOURCE_DIR}/event/epoll src_files) 19 | ENDIF() 20 | ENDIF() 21 | 22 | SET(cppnet_source ${src_files} PARENT_SCOPE) 23 | -------------------------------------------------------------------------------- /cppnet/cppnet.cpp: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #include "include/cppnet.h" 7 | #include "cppnet/cppnet_base.h" 8 | #include "cppnet/cppnet_config.h" 9 | 10 | #include "common/log/log.h" 11 | #include "common/util/random.h" 12 | #include "common/log/file_logger.h" 13 | #include "common/log/stdout_logger.h" 14 | 15 | namespace cppnet { 16 | 17 | 18 | CppNet::~CppNet() { 19 | if (_cppnet_base) { 20 | _cppnet_base->Dealloc(); 21 | } 22 | } 23 | 24 | void CppNet::Init(int32_t thread_num) { 25 | if (!_cppnet_base) { 26 | _cppnet_base = std::make_shared(); 27 | 28 | } else { 29 | return; 30 | } 31 | 32 | _cppnet_base->Init(thread_num); 33 | if (__print_log) { 34 | std::shared_ptr file_log = std::make_shared(__log_file_name); 35 | std::shared_ptr std_log = std::make_shared(); 36 | file_log->SetLogger(std_log); 37 | LOG_SET(file_log); 38 | LOG_SET_LEVEL((LogLevel)__log_level); 39 | } else { 40 | LOG_SET_LEVEL(LL_NULL); 41 | } 42 | } 43 | 44 | void CppNet::Destory() { 45 | _cppnet_base->Dealloc(); 46 | } 47 | 48 | void CppNet::Join() { 49 | _cppnet_base->Join(); 50 | } 51 | 52 | void CppNet::SetReadCallback(read_call_back&& cb) { 53 | _cppnet_base->SetReadCallback(std::move(cb)); 54 | } 55 | 56 | void CppNet::SetWriteCallback(write_call_back&& cb) { 57 | _cppnet_base->SetWriteCallback(std::move(cb)); 58 | } 59 | 60 | void CppNet::SetDisconnectionCallback(connect_call_back&& cb) { 61 | _cppnet_base->SetDisconnectionCallback(std::move(cb)); 62 | } 63 | 64 | void CppNet::SetTimerCallback(timer_call_back&& cb) { 65 | _cppnet_base->SetTimerCallback(std::move(cb)); 66 | } 67 | 68 | uint64_t CppNet::AddTimer(int32_t interval, user_timer_call_back&& cb, void* param, bool always) { 69 | return _cppnet_base->AddTimer(interval, std::move(cb), param, always); 70 | } 71 | 72 | void CppNet::RemoveTimer(uint64_t timer_id) { 73 | _cppnet_base->RemoveTimer(timer_id); 74 | } 75 | 76 | void CppNet::SetAcceptCallback(connect_call_back&& cb) { 77 | _cppnet_base->SetAcceptCallback(std::move(cb)); 78 | } 79 | 80 | bool CppNet::ListenAndAccept(const std::string& ip, uint16_t port) { 81 | return _cppnet_base->ListenAndAccept(ip, port); 82 | } 83 | 84 | void CppNet::SetConnectionCallback(connect_call_back&& cb) { 85 | _cppnet_base->SetConnectionCallback(std::move(cb)); 86 | } 87 | 88 | bool CppNet::Connection(const std::string& ip, uint16_t port) { 89 | return _cppnet_base->Connection(ip, port); 90 | } 91 | 92 | } // namespace cppnet 93 | -------------------------------------------------------------------------------- /cppnet/cppnet_base.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef CPPNET_CPPNET_BASE 7 | #define CPPNET_CPPNET_BASE 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "include/cppnet_type.h" 14 | 15 | namespace cppnet { 16 | 17 | 18 | class RWSocket; 19 | class Dispatcher; 20 | class RangeRandom; 21 | class InnerBuffer; 22 | 23 | class CppNetBase: 24 | public std::enable_shared_from_this { 25 | 26 | public: 27 | CppNetBase() = default; 28 | ~CppNetBase() = default; 29 | // common 30 | void Init(uint32_t thread_num); 31 | void Dealloc(); 32 | void Join(); 33 | 34 | // set call back 35 | void SetReadCallback(read_call_back&& cb) { _read_cb = std::move(cb); } 36 | void SetWriteCallback(write_call_back&& cb) { _write_cb = std::move(cb); } 37 | void SetDisconnectionCallback(connect_call_back&& cb) { _disconnect_cb = std::move(cb); } 38 | void SetTimerCallback(timer_call_back&& cb) { _timer_cb = std::move(cb); } 39 | 40 | // about timer 41 | uint64_t AddTimer(uint32_t interval, user_timer_call_back&& cb, void* param = nullptr, bool always = false); 42 | void RemoveTimer(uint64_t timer_id); 43 | 44 | //server 45 | void SetAcceptCallback(connect_call_back&& cb) { _accept_cb = std::move(cb); } 46 | bool ListenAndAccept(const std::string& ip, uint16_t port); 47 | 48 | //client 49 | void SetConnectionCallback(connect_call_back&& cb) { _connect_cb = std::move(cb); } 50 | bool Connection(const std::string& ip, uint16_t port); 51 | 52 | // call back 53 | void OnTimer(std::shared_ptr sock); 54 | void OnAccept(std::shared_ptr sock); 55 | void OnRead(std::shared_ptr sock, std::shared_ptr buffer, uint32_t len); 56 | void OnWrite(std::shared_ptr sock, uint32_t len); 57 | void OnConnect(std::shared_ptr sock, uint16_t err); 58 | void OnDisConnect(std::shared_ptr sock, uint16_t err); 59 | 60 | private: 61 | timer_call_back _timer_cb; 62 | read_call_back _read_cb; 63 | write_call_back _write_cb; 64 | connect_call_back _connect_cb; 65 | connect_call_back _disconnect_cb; 66 | connect_call_back _accept_cb; 67 | 68 | std::unique_ptr _random; 69 | std::vector> _dispatchers; 70 | }; 71 | 72 | } // namespace cppnet 73 | 74 | #endif -------------------------------------------------------------------------------- /cppnet/cppnet_config.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef CPPNET_CPPNET_CONFIGE 7 | #define CPPNET_CPPNET_CONFIGE 8 | 9 | #include 10 | #include 11 | 12 | namespace cppnet { 13 | 14 | // on Linux, we have two ways to avoid thundering herd: 15 | // 1. use TCP flag reuse port flag, multi socket listen to one same port. 16 | // 2. only use one socket but set EPOLLEXCLUSIVE flag when add to EPOLL.(require Linux Kernal > 4.5) 17 | 18 | // use reuse port TCP flag. must set true on windows and macOS. 19 | static const bool __reuse_port = true; 20 | // use EPOLLEXCLUSIVE flag. must set false on windows and macOS. 21 | static const bool __epoll_exclusive = !__reuse_port; 22 | 23 | // size of block memory in block memory pool. 24 | static const uint16_t __mem_block_size = 1024; 25 | // how many block memory will be add to block memory pool. 26 | static const uint16_t __mem_block_add_step = 5; 27 | // max number of blocks in memory pool. If block memory more than this number, will reduce to half. 28 | static const uint16_t __max_block_num = 20; 29 | // max data to write when net is busy. 30 | static const uint32_t __max_write_cache = 1024 * 1024 * 4; 31 | 32 | // log level. 33 | static const uint16_t __log_level = 15; // info level 34 | // log file name. 35 | static const std::string __log_file_name = "cppnet_log"; 36 | // open log print. 37 | static const bool __print_log = false; 38 | 39 | // EPOLL use et model. 40 | static const bool __epoll_use_et = true; 41 | // the start extend size of read buff while buff isn't enough. 42 | static const uint16_t __linux_read_buff_expand_len = 4096; 43 | // max extend size of read buff while buff isn't enough. 44 | static const uint32_t __linux_read_buff_expand_max = 65536; 45 | // max size of buffer will get from buffer. Be careful IOV_MAX. 46 | static const uint16_t __linux_write_buff_get = 4096; 47 | // waiting time to re detect the connection status when connecting 48 | static const uint16_t __connect_recheck_time_ms = 2000; 49 | 50 | // IOCP buffer length. 51 | static const uint16_t __iocp_buff_size = 1024*4; 52 | // number of IOCP accept event post when first call accept 53 | static const uint16_t __iocp_accept_event_num = 20; 54 | 55 | 56 | } 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /cppnet/dispatcher.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef CPPNET_DISPATCHER 7 | #define CPPNET_DISPATCHER 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "include/cppnet_type.h" 16 | #include "common/thread/thread_with_queue.h" 17 | 18 | namespace cppnet { 19 | 20 | using Task = std::function; 21 | 22 | class Timer; 23 | class RWSocket; 24 | class TimerEvent; 25 | class CppNetBase; 26 | class EventActions; 27 | 28 | class Dispatcher: 29 | public Thread, 30 | public std::enable_shared_from_this { 31 | 32 | public: 33 | Dispatcher(std::shared_ptr base, uint32_t thread_num, uint32_t base_id); 34 | explicit Dispatcher(std::shared_ptr base, uint32_t base_id = 0); 35 | ~Dispatcher() override; 36 | 37 | void Run() override; 38 | 39 | void Stop() override; 40 | 41 | void Listen(uint64_t sock, const std::string& ip, uint16_t port); 42 | 43 | void Connect(const std::string& ip, uint16_t port); 44 | 45 | void PostTask(const Task& task); 46 | 47 | uint32_t AddTimer(const user_timer_call_back& cb, void* param, uint32_t interval, bool always = false); 48 | uint32_t AddTimer(std::shared_ptr sock, uint32_t interval, bool always = false); 49 | void StopTimer(uint32_t timer_id); 50 | 51 | std::thread::id GetThreadID() { return _local_thread_id; } 52 | 53 | private: 54 | void DoTask(); 55 | uint32_t MakeTimerID(); 56 | 57 | uint64_t _cur_utc_time; 58 | 59 | std::mutex _timer_id_mutex; 60 | uint32_t _timer_id_creater; 61 | 62 | std::mutex _task_list_mutex; 63 | std::vector _task_list; 64 | 65 | std::thread::id _local_thread_id; 66 | std::shared_ptr _timer; 67 | std::shared_ptr _event_actions; 68 | 69 | std::weak_ptr _cppnet_base; 70 | 71 | static thread_local std::unordered_map> __all_timer_event_map; 72 | }; 73 | 74 | } 75 | 76 | #endif -------------------------------------------------------------------------------- /cppnet/event/action_interface.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef CPPNET_EVENT_ACTION_INTERFACE 7 | #define CPPNET_EVENT_ACTION_INTERFACE 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace cppnet { 17 | 18 | class Timer; 19 | class Event; 20 | class Address; 21 | class TimeSolt; 22 | 23 | // net IO event interface 24 | class EventActions { 25 | public: 26 | EventActions() {} 27 | virtual ~EventActions() {} 28 | 29 | virtual bool Init(uint32_t thread_num = 0) = 0; 30 | virtual bool Dealloc() = 0; 31 | 32 | // net IO event 33 | virtual bool AddSendEvent(Event* event) = 0; 34 | virtual bool AddRecvEvent(Event* event) = 0; 35 | virtual bool AddAcceptEvent(Event* event) = 0; 36 | virtual bool AddConnection(Event* event, Address& addr) = 0; 37 | virtual bool AddDisconnection(Event* event) = 0; 38 | 39 | virtual bool DelEvent(Event* event) = 0; 40 | // IO thread process 41 | virtual void ProcessEvent(int32_t wait_ms) = 0; 42 | // weak up net IO thread 43 | virtual void Wakeup() = 0; 44 | }; 45 | 46 | std::shared_ptr MakeEventActions(); 47 | 48 | } 49 | 50 | #endif -------------------------------------------------------------------------------- /cppnet/event/epoll/epoll_action.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef NET_EVENT_EPOLL_EPOLL_ACTION 7 | #define NET_EVENT_EPOLL_EPOLL_ACTION 8 | 9 | #include 10 | #ifdef __win__ 11 | #include "wepoll/wepoll.h" 12 | #else 13 | #include 14 | #endif 15 | #include "cppnet/event/action_interface.h" 16 | 17 | namespace cppnet { 18 | 19 | // epoll event interface 20 | class EpollEventActions: 21 | public EventActions { 22 | 23 | public: 24 | EpollEventActions(); 25 | virtual ~EpollEventActions(); 26 | 27 | virtual bool Init(uint32_t thread_num = 0); 28 | virtual bool Dealloc(); 29 | // net io event 30 | virtual bool AddSendEvent(Event* event); 31 | virtual bool AddRecvEvent(Event* event); 32 | virtual bool AddAcceptEvent(Event* event); 33 | virtual bool AddConnection(Event* event, Address& address); 34 | virtual bool AddDisconnection(Event* event); 35 | 36 | virtual bool DelEvent(Event* event); 37 | // io thread process 38 | virtual void ProcessEvent(int32_t wait_ms); 39 | // weak up net io thread 40 | virtual void Wakeup(); 41 | 42 | private: 43 | void OnEvent(std::vector& event_vec, int16_t num); 44 | bool AddEvent(epoll_event* ev, int32_t event_flag, uint64_t sock, bool in_actions); 45 | bool MakeEpollEvent(Event* event, epoll_event* &ep_event); 46 | 47 | private: 48 | #ifdef __win__ 49 | bool Pipe(SOCKET fd[2]); 50 | HANDLE _epoll_handler; 51 | SOCKET _pipe[2]; 52 | #else 53 | int32_t _epoll_handler; 54 | uint32_t _pipe[2]; 55 | #endif 56 | epoll_event _pipe_content; 57 | std::vector _active_list; 58 | 59 | }; 60 | 61 | } 62 | 63 | #endif -------------------------------------------------------------------------------- /cppnet/event/epoll/wepoll/wepoll.h: -------------------------------------------------------------------------------- 1 | /* 2 | * wepoll - epoll for Windows 3 | * https://github.com/piscisaureus/wepoll 4 | * 5 | * Copyright 2012-2020, Bert Belder 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are 10 | * met: 11 | * 12 | * * Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 15 | * * Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #ifndef WEPOLL_H_ 33 | #define WEPOLL_H_ 34 | 35 | #ifndef WEPOLL_EXPORT 36 | #define WEPOLL_EXPORT 37 | #endif 38 | 39 | #include 40 | 41 | enum EPOLL_EVENTS { 42 | EPOLLIN = (int) (1U << 0), 43 | EPOLLPRI = (int) (1U << 1), 44 | EPOLLOUT = (int) (1U << 2), 45 | EPOLLERR = (int) (1U << 3), 46 | EPOLLHUP = (int) (1U << 4), 47 | EPOLLRDNORM = (int) (1U << 6), 48 | EPOLLRDBAND = (int) (1U << 7), 49 | EPOLLWRNORM = (int) (1U << 8), 50 | EPOLLWRBAND = (int) (1U << 9), 51 | EPOLLMSG = (int) (1U << 10), /* Never reported. */ 52 | EPOLLRDHUP = (int) (1U << 13), 53 | EPOLLONESHOT = (int) (1U << 31) 54 | }; 55 | 56 | #define EPOLLIN (1U << 0) 57 | #define EPOLLPRI (1U << 1) 58 | #define EPOLLOUT (1U << 2) 59 | #define EPOLLERR (1U << 3) 60 | #define EPOLLHUP (1U << 4) 61 | #define EPOLLRDNORM (1U << 6) 62 | #define EPOLLRDBAND (1U << 7) 63 | #define EPOLLWRNORM (1U << 8) 64 | #define EPOLLWRBAND (1U << 9) 65 | #define EPOLLMSG (1U << 10) 66 | #define EPOLLRDHUP (1U << 13) 67 | #define EPOLLONESHOT (1U << 31) 68 | 69 | #define EPOLL_CTL_ADD 1 70 | #define EPOLL_CTL_MOD 2 71 | #define EPOLL_CTL_DEL 3 72 | 73 | typedef void* HANDLE; 74 | typedef uintptr_t SOCKET; 75 | 76 | typedef union epoll_data { 77 | void* ptr; 78 | int fd; 79 | uint32_t u32; 80 | uint64_t u64; 81 | SOCKET sock; /* Windows specific */ 82 | HANDLE hnd; /* Windows specific */ 83 | } epoll_data_t; 84 | 85 | struct epoll_event { 86 | uint32_t events; /* Epoll events and flags */ 87 | epoll_data_t data; /* User data variable */ 88 | }; 89 | 90 | #ifdef __cplusplus 91 | extern "C" { 92 | #endif 93 | 94 | WEPOLL_EXPORT HANDLE epoll_create(int size); 95 | WEPOLL_EXPORT HANDLE epoll_create1(int flags); 96 | 97 | WEPOLL_EXPORT int epoll_close(HANDLE ephnd); 98 | 99 | WEPOLL_EXPORT int epoll_ctl(HANDLE ephnd, 100 | int op, 101 | SOCKET sock, 102 | struct epoll_event* event); 103 | 104 | WEPOLL_EXPORT int epoll_wait(HANDLE ephnd, 105 | struct epoll_event* events, 106 | int maxevents, 107 | int timeout); 108 | 109 | #ifdef __cplusplus 110 | } /* extern "C" */ 111 | #endif 112 | 113 | #endif /* WEPOLL_H_ */ 114 | -------------------------------------------------------------------------------- /cppnet/event/event_interface.cpp: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #include "cppnet/event/event_interface.h" 7 | 8 | namespace cppnet { 9 | 10 | const char* TypeString(EventType type) { 11 | switch (type) 12 | { 13 | case ET_READ: 14 | return "read"; 15 | break; 16 | case ET_WRITE: 17 | return "write"; 18 | break; 19 | case ET_ACCEPT: 20 | return "accept"; 21 | break; 22 | case ET_TIMER: 23 | return "timer"; 24 | break; 25 | case ET_USER_TIMER: 26 | return "user_timer"; 27 | break; 28 | case ET_CONNECT: 29 | return "connect"; 30 | break; 31 | case ET_DISCONNECT: 32 | return "disconnect"; 33 | break; 34 | case ET_INACTIONS: 35 | return "inactions"; 36 | break; 37 | default: 38 | return "unknow"; 39 | break; 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /cppnet/event/event_interface.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef CPPNET_EVENT_EVENT_INTERFACE 7 | #define CPPNET_EVENT_EVENT_INTERFACE 8 | 9 | #include 10 | #include 11 | 12 | namespace cppnet { 13 | 14 | enum EventType { 15 | ET_READ = 0x001, // read event 16 | ET_WRITE = 0x002, // write event 17 | ET_ACCEPT = 0x004, // accept event 18 | ET_TIMER = 0x008, // timer event 19 | ET_USER_TIMER = 0x010, // timer event 20 | ET_CONNECT = 0x020, // connect event 21 | ET_DISCONNECT = 0x040, // disconnect event 22 | 23 | ET_INACTIONS = 0x080, // set to actions 24 | }; 25 | 26 | const char* TypeString(EventType type); 27 | 28 | class Socket; 29 | class BufferQueue; 30 | class Event { 31 | public: 32 | Event(): _data(nullptr), _event_type(0) {} 33 | virtual ~Event() {} 34 | 35 | void SetData(void* data) { _data = data; } 36 | void* GetData() { return _data; } 37 | 38 | void AddType(EventType type) { _event_type |= type; } 39 | void RemoveType(EventType type) { _event_type &= ~type; } 40 | uint16_t GetType() { return _event_type; } 41 | void ClearType() { _event_type = 0; } 42 | void ForceSetType(EventType type) { _event_type = type; } 43 | 44 | void SetSocket(std::shared_ptr socket) { _socket = socket; } 45 | std::shared_ptr GetSocket() { return _socket.lock(); } 46 | 47 | #ifdef __win__ 48 | void SetBuffer(std::shared_ptr& buffer) { _buffer = buffer; } 49 | std::shared_ptr GetBuffer() { return _buffer; } 50 | private: 51 | std::shared_ptr _buffer; 52 | #endif 53 | 54 | protected: 55 | void* _data; 56 | uint16_t _event_type; 57 | std::weak_ptr _socket; 58 | 59 | 60 | }; 61 | 62 | } 63 | 64 | #endif -------------------------------------------------------------------------------- /cppnet/event/kqueue/kqueue_action.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef NET_EVENT_KQUEUE_KQUEUE_ACTION 7 | #define NET_EVENT_KQUEUE_KQUEUE_ACTION 8 | 9 | #include 10 | #include 11 | #include 12 | #include // for kqueue 13 | #include "cppnet/event/action_interface.h" 14 | 15 | namespace cppnet { 16 | 17 | // kqueue event interface 18 | class KqueueEventActions: public EventActions { 19 | public: 20 | KqueueEventActions(); 21 | virtual ~KqueueEventActions(); 22 | 23 | virtual bool Init(uint32_t thread_num = 0); 24 | virtual bool Dealloc(); 25 | // net io event 26 | virtual bool AddSendEvent(Event* event); 27 | virtual bool AddRecvEvent(Event* event); 28 | virtual bool AddAcceptEvent(Event* event); 29 | virtual bool AddConnection(Event* event, Address& address); 30 | virtual bool AddDisconnection(Event* event); 31 | 32 | virtual bool DelEvent(Event* event); 33 | // io thread process 34 | virtual void ProcessEvent(int32_t wait_ms); 35 | // weak up net io thread 36 | virtual void Wakeup(); 37 | 38 | private: 39 | void OnEvent(std::vector& event_vec, int16_t num); 40 | 41 | protected: 42 | std::mutex _mutex; 43 | int32_t _kqueue_handler; 44 | uint32_t _pipe[2]; 45 | timespec _kqueue_timeout; 46 | std::vector _change_list; 47 | std::vector _active_list; 48 | }; 49 | 50 | } 51 | 52 | #endif -------------------------------------------------------------------------------- /cppnet/event/timer_event.cpp: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #include "common/log/log.h" 7 | #include "cppnet/socket/rw_socket.h" 8 | #include "cppnet/event/timer_event.h" 9 | 10 | namespace cppnet { 11 | 12 | void TimerEvent::SetTimerCallBack(const user_timer_call_back& cb, void* param) { 13 | _timer_cb = cb; 14 | SetData(param); 15 | } 16 | 17 | void TimerEvent::OnTimer() { 18 | if (GetType() & ET_USER_TIMER) { 19 | _timer_cb(GetData()); 20 | 21 | } else if (GetType() & ET_TIMER) { 22 | auto sock = GetSocket(); 23 | auto rw_sock = std::dynamic_pointer_cast(sock); 24 | rw_sock->OnTimer(); 25 | 26 | } else { 27 | LOG_ERROR("invalid timer type. type:%d", GetType()); 28 | } 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /cppnet/event/timer_event.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef CPPNET_EVENT_TIMER_EVENT 7 | #define CPPNET_EVENT_TIMER_EVENT 8 | 9 | #include 10 | #include 11 | #include "include/cppnet_type.h" 12 | #include "common/timer/timer_slot.h" 13 | #include "cppnet/event/event_interface.h" 14 | 15 | namespace cppnet { 16 | 17 | class TimerEvent: 18 | public Event, 19 | public TimerSlot { 20 | 21 | public: 22 | TimerEvent(): _timer_id(0) {} 23 | ~TimerEvent() {} 24 | 25 | void SetTimerCallBack(const user_timer_call_back& cb, void* param); 26 | 27 | void OnTimer(); 28 | private: 29 | uint64_t _timer_id; 30 | user_timer_call_back _timer_cb; 31 | 32 | }; 33 | 34 | } 35 | 36 | #endif -------------------------------------------------------------------------------- /cppnet/socket/connect_socket.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef CPPNET_SOCKET_CONNECT_SOCKET 7 | #define CPPNET_SOCKET_CONNECT_SOCKET 8 | 9 | #include 10 | #include "cppnet/socket/socket_interface.h" 11 | 12 | namespace cppnet { 13 | 14 | class Event; 15 | class ConnectSocket: 16 | public Socket, 17 | public std::enable_shared_from_this { 18 | 19 | public: 20 | ConnectSocket(); 21 | virtual ~ConnectSocket(); 22 | 23 | virtual bool Bind(const std::string& ip, uint16_t port); 24 | virtual bool Listen(); 25 | virtual void Accept(); 26 | virtual void Close(); 27 | 28 | virtual void OnAccept(); 29 | private: 30 | Event* _accept_event; 31 | }; 32 | 33 | std::shared_ptr MakeConnectSocket(); 34 | 35 | } 36 | 37 | #endif -------------------------------------------------------------------------------- /cppnet/socket/rw_socket.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef CPPNET_SOCKET_READ_WRITE_SOCKET 7 | #define CPPNET_SOCKET_READ_WRITE_SOCKET 8 | 9 | #include 10 | #include "include/cppnet_socket.h" 11 | #include "cppnet/socket/socket_interface.h" 12 | 13 | 14 | namespace cppnet { 15 | 16 | class Event; 17 | class BufferQueue; 18 | class AlloterWrap; 19 | class BlockMemoryPool; 20 | 21 | class RWSocket: 22 | public Socket, 23 | public CNSocket, 24 | public std::enable_shared_from_this { 25 | 26 | public: 27 | 28 | RWSocket(); 29 | RWSocket(std::shared_ptr alloter); 30 | RWSocket(uint64_t sock, std::shared_ptr alloter); 31 | virtual ~RWSocket(); 32 | 33 | virtual uint64_t GetSocket() { return _sock; } 34 | virtual void SetListenPort(uint16_t port) { _listen_port = port; } 35 | virtual uint16_t GetListenPort() { return _listen_port; } 36 | virtual bool GetAddress(std::string& ip, uint16_t& port); 37 | 38 | virtual void Close(); 39 | 40 | virtual void Read(); 41 | virtual bool Write(const char* src, uint32_t len); 42 | virtual void Connect(const std::string& ip, uint16_t port); 43 | virtual void Disconnect(); 44 | 45 | virtual void AddTimer(uint32_t interval, bool always = false); 46 | virtual void StopTimer(); 47 | 48 | virtual void OnTimer(); 49 | virtual void OnRead(uint32_t len = 0); 50 | virtual void OnWrite(uint32_t len = 0); 51 | virtual void OnConnect(uint16_t err); 52 | virtual void OnDisConnect(uint16_t err); 53 | 54 | virtual void SetContext(void* context) { _context = context; } 55 | virtual void* GetContext() { return _context; } 56 | 57 | virtual void SetShutdown() { _shutdown = true; } 58 | virtual bool IsShutdown() { return _shutdown; } 59 | 60 | std::shared_ptr GetAlloter() { return _alloter; } 61 | 62 | private: 63 | bool Recv(uint32_t len); 64 | bool Send(); 65 | 66 | protected: 67 | void* _context; 68 | uint32_t _timer_id; 69 | uint16_t _listen_port; 70 | std::atomic_bool _shutdown; 71 | std::atomic_bool _connecting; 72 | Event* _event; 73 | 74 | std::shared_ptr _write_buffer; 75 | std::shared_ptr _read_buffer; 76 | 77 | std::shared_ptr _alloter; 78 | std::shared_ptr _block_pool; 79 | 80 | static thread_local std::unordered_map> __connecting_socket_map; 81 | }; 82 | 83 | std::shared_ptr MakeRWSocket(); 84 | std::shared_ptr MakeRWSocket(std::shared_ptr alloter); 85 | std::shared_ptr MakeRWSocket(uint64_t sock, std::shared_ptr alloter); 86 | 87 | } 88 | 89 | #endif -------------------------------------------------------------------------------- /cppnet/socket/socket_interface.cpp: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #include "cppnet/socket/socket_interface.h" 7 | 8 | namespace cppnet { 9 | 10 | thread_local std::unordered_map> Socket::__all_socket_map; 11 | 12 | } -------------------------------------------------------------------------------- /cppnet/socket/socket_interface.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef CPPNET_SOCKET_SOCKET_INTERFACE 7 | #define CPPNET_SOCKET_SOCKET_INTERFACE 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "common/network/address.h" 14 | 15 | namespace cppnet { 16 | 17 | class Address; 18 | class CppNetBase; 19 | class Dispatcher; 20 | class EventActions; 21 | class Socket { 22 | public: 23 | Socket(): _sock(0) {} 24 | Socket(uint64_t sock): _sock(sock) {} 25 | virtual ~Socket() {} 26 | 27 | void SetSocket(const uint64_t& sock) { _sock = sock; } 28 | uint64_t GetSocket() { return _sock; } 29 | 30 | void SetAddress(const Address& addr) { _addr = addr; } 31 | const Address& GetAddress() const { return _addr; } 32 | 33 | void SetCppNetBase(std::shared_ptr base) { _cppnet_base = base; } 34 | const std::shared_ptr GetCppNetBase() const { return _cppnet_base.lock(); } 35 | 36 | void SetEventActions(std::weak_ptr actions) { _event_actions = actions; } 37 | const std::shared_ptr GetEventActions() const { return _event_actions.lock(); } 38 | 39 | void SetDispatcher(std::shared_ptr dis) { _dispatcher = dis; } 40 | std::shared_ptr GetDispatcher() { return _dispatcher.lock(); } 41 | 42 | protected: 43 | uint64_t _sock; 44 | Address _addr; 45 | 46 | std::weak_ptr _cppnet_base; 47 | std::weak_ptr _event_actions; 48 | std::weak_ptr _dispatcher; 49 | 50 | static thread_local std::unordered_map> __all_socket_map; 51 | }; 52 | 53 | } 54 | 55 | #endif -------------------------------------------------------------------------------- /doc/build/build.md: -------------------------------------------------------------------------------- 1 | # Build 2 | 3 | `cppnet` supports three compilation methods: 4 | - Linux and Mac OS use `make` 5 | - Windows use `VS 2019` 6 | - use `cmake` 7 | 8 | ## make 9 | On Linux and Mac OS, can executed directly in `cppnet` directory 10 | ``` 11 | make 12 | ``` 13 | The `cppnet` static library can be compiled. 14 | For other sample codes, you need to enter the corresponding subdirectories and execute the `make` command respectively. 15 | All compilation outputs are in the current execution directory. 16 | 17 | ## VS 2019 18 | `cppnet` has no special requirements for WinSDK. The project file carried on GitHub is vs2019. Other versions of vs can be recompiled to the platform. 19 | 20 | ## cmake 21 | `cmake` can be used to compile on all three platforms. 22 | ``` 23 | mkdir build 24 | cd build 25 | cmake .. 26 | ``` 27 | Then execute 28 | ``` 29 | make 30 | ``` 31 | Or compile with the corresponding vs. 32 | All executable outputs are in the `bin` directory of the current `build` directory, and the `cppnet` static library is in the `lib` directory of the current build directory. -------------------------------------------------------------------------------- /doc/build/build_cn.md: -------------------------------------------------------------------------------- 1 | # 编译 2 | 3 | `Cppnet`目前支持三种编译方式: 4 | - Linux和Mac OS下可使用 `make` 5 | - Windows下可使用 `VS 2019` 6 | - 使用 `cmake` 7 | 8 | ## make 9 | 在Linux和Mac OS下可直接在cppnet 目录执行 10 | ``` 11 | make 12 | ``` 13 | 即可编译`cppnet`静态库。 14 | 其他示例代码,则需要进入到对应子目录,分别执行 `make` 命令。 15 | 所有编译产出都在当前执行目录下。 16 | 17 | ## VS 2019 18 | `cppnet`对WinSDK没有特殊要求,github上携带的工程文件为VS2019,其他版本的VS可重新向平台之后再编译。 19 | 20 | ## cmake 21 | 三个平台下均可使用cmake进行编译。 22 | ``` 23 | mkdir build 24 | cd build 25 | cmake .. 26 | ``` 27 | 之后执行 28 | ``` 29 | make 30 | ``` 31 | 或使用对应VS编译。 32 | 所有可执行产出物均在当前`build`目录的`bin`目录下,`cppnet`静态库在当前`build`目录的`lib`目录下。 -------------------------------------------------------------------------------- /doc/efficiency/apache_ab_bench.md: -------------------------------------------------------------------------------- 1 | # Apache ab Benchmark 2 | 3 | Apache `ab` is a commonly used tool for HTTP server pressure testing. I press test the `http` test service in the `cppnet` test directory on different platforms, The command to be executed is: 4 | ```shell 5 | ab -kc[1-10000] -n100000 http://127.0.0.1:8921/hello 6 | ``` 7 | Execute the above command three times each time, take the highest value of QPS among the three times, and draw the test result as a line chart. 8 | In the line chart, the ordinate is QPS and the abscissa is concurrent value. 9 | 10 | ### Linux 11 | 12 | **environment**: 13 | - the system environment is `WSL2` in windows 14 | - the operating system is `Ubuntu20.04` 15 | - system memory `16G DDR3 2666Mhz` 16 | - CPU is `i7-6700 @ 3.40GHz` four cores 17 | - compile optimized `-O2` 18 | - all tests have `2` threads 19 | 20 | Compared with `Muduo` on Linux,because Linux support `REUSE_PORT` and `EPOLLEXCLUSIVE`, so I added a comparison of two different options, The results are shown in the figure below 21 |

linux_apache_ab_bench

22 | 23 | In the picture `cppnet_1` used `REUSE_PORT`,`cppnet_2` used `EPOLLEXCLUSIVE`. 24 | When use `REUSE_PORT`, efficiency is slightly better than `muduo`. 25 | When use `EPOLLEXCLUSIVE`, the overall performance is better than `muduo`(muduo does not support the `EPOLLEXCLUSIVE` setting). 26 | 27 | ### Windows 28 | 29 | **environment**: 30 | - The system environment is physical real machine 31 | - the operating system is `Windows 10 @ 19042.985` 32 | - system memory `16G DDR3 2666HZ` 33 | - CPU is `i7-6700 @ 3.40GHz` four cores 34 | - compile optimized `/O2` 35 | 36 | Because `IOCP` is used in the Windows, the system kernel is responsible for managing the thread pool, and each socket wake-up operation will be executed on different threads, which is quite different from Linux and MacOS. Therefore, the pressure test performance of different number of threads is specially listed, The results are shown in the figure below 37 |

linux_apache_ab_bench

38 | 39 | ### MacOS 40 | 41 | **environment**: 42 | - The system environment is physical real machine 43 | - the operating system is `MacOS @ 10.15.4` 44 | - system memory `8G DDR3 2133Mhz` 45 | - CPU is `i5-8257U @ 1.40GHz` four cores 46 | - compile optimized `-O2` 47 | - `2` threads 48 | 49 | The results are shown in the figure below 50 |

linux_apache_ab_bench

51 | 52 | ### Result 53 | It is difficult to have both cross platform and high performance. Due to the Linux platform developed first, the windows platform adapted later, the usage of `IOCP` is very different from `epoll` and `kqueue`. There are many thread safe locks on Windows, The performance of `IOCP` is not displayed, so the performance on Windows is normal. 54 | On Linux and MacOS, most QPS can exceed 100000 under normal concurrency conditions, the performance is excellent. -------------------------------------------------------------------------------- /doc/efficiency/apache_ab_bench_cn.md: -------------------------------------------------------------------------------- 1 | # Apache ab 压测 2 | 3 | Apache `ab` 是一个常用的http服务器压测工具。这里对`cppnet` test目录中的`http`测试服务分别在不同平台进行压测,执行的命令为: 4 | ```shell 5 | ab -kc[1-10000] -n100000 http://127.0.0.1:8921/hello 6 | ``` 7 | 每次将上述命令执行三次,取三次中QPS的最高值,并将测试结果绘制为折线图。 8 | 折线图中纵坐标为QPS, 横坐标为并发值。 9 | 10 | ### Linux 11 | 12 | **压测环境**: 13 | - 系统环境为Widnows的`WSL2` 14 | - 操作系统为`Ubuntu20.04` 15 | - 系统内存`16G DDR3 2666Mhz` 16 | - CPU为 `i7-6700 @ 3.40GHz` 四核 17 | - 编译优化为`-O2` 18 | - 所有测试均开`2`个线程 19 | 20 | 在Linux上与`muduo`进行了对比,由于Linux上可以在`REUSE_PORT`之外额外支持`EPOLLEXCLUSIVE`,所以又添加了两种不同选项的对比,结果如下图所示 21 |

linux_apache_ab_bench

22 | 23 | 图中`cppnet_1`为使用`REUSE_PORT`,`cppnet_2`为使用`EPOLLEXCLUSIVE`。 24 | 使用`REUSE_PORT`时,整体效率稍稍优于`muduo`。 25 | 在使用`EPOLLEXCLUSIVE`时,性能整体都优于`muduo`(muduo尚未支持`EPOLLEXCLUSIVE`设置)。 26 | 27 | ### Windows 28 | 29 | **压测环境**: 30 | - 系统环境为物理真机 31 | - 操作系统为`Windows 10 @ 19042.985` 32 | - 系统内存`16G DDR3 2666HZ` 33 | - CPU为 `i7-6700 @ 3.40GHz` 四核 34 | - 编译优化为`/O2` 35 | 36 | 由于在Windows环境使用的是`IOCP`,系统内核负责管理线程池,各个socket唤醒操作将在不同的线程上执行,这与Linux和MacOS大相径庭,所以特意列了不同线程数量时的压测表现,结果如下图所示 37 |

linux_apache_ab_bench

38 | 39 | ### MacOS 40 | 41 | **压测环境**: 42 | - 系统环境为物理真机 43 | - 操作系统为`MacOS @ 10.15.4` 44 | - 系统内存`8G DDR3 2133Mhz` 45 | - CPU为 `i5-8257U @ 1.40GHz` 四核 46 | - 编译优化为`-O2` 47 | - 开`2`个线程 48 | 49 | 压测结果如下图所示 50 |

linux_apache_ab_bench

51 | 52 | ### 结语 53 | 跨平台与高性能往往难以兼得,由于先开发的Linux平台,后适配的Windows平台,且`IOCP`的使用方式与`Epoll`和`Kqueue`有着极大的不同,框架上也没法过于妥协。Windows平台上有很多保证线程安全的锁,并没有完美发挥出`IOCP`的性能,所以在Windows平台上性能表现一般。 54 | 在Linux和MacOS上,常规并发条件下,大部分QPS都能超过10万,性能表现还算优异。 -------------------------------------------------------------------------------- /doc/image/cppnet_level.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caozhiyi/CppNet/03bead273ab931412d4e01f0ca6b6a1aee357107/doc/image/cppnet_level.png -------------------------------------------------------------------------------- /doc/image/linux_apache_ab_bench.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caozhiyi/CppNet/03bead273ab931412d4e01f0ca6b6a1aee357107/doc/image/linux_apache_ab_bench.png -------------------------------------------------------------------------------- /doc/image/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caozhiyi/CppNet/03bead273ab931412d4e01f0ca6b6a1aee357107/doc/image/logo.png -------------------------------------------------------------------------------- /doc/image/macos_apache_ab_bench.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caozhiyi/CppNet/03bead273ab931412d4e01f0ca6b6a1aee357107/doc/image/macos_apache_ab_bench.png -------------------------------------------------------------------------------- /doc/image/windows_apache_ab_bench.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caozhiyi/CppNet/03bead273ab931412d4e01f0ca6b6a1aee357107/doc/image/windows_apache_ab_bench.png -------------------------------------------------------------------------------- /doc/start/quick_start.md: -------------------------------------------------------------------------------- 1 | # Quick Start 2 | 3 | ### Build 4 | Download the source code through `git`, and then compile the `cppnet` static library,please refer to [Build](../build/build.md). 5 | The header file to be referenced is defined in [include](../../include), just need reference a header file. 6 | ```c++ 7 | #include "include/cppnet.h" 8 | ``` 9 | 10 | ### Use 11 | Construct an instance of `cppnet` and call the `Init` interface for initialization, like 12 | ```c++ 13 | CppNet net; 14 | net.Init(2); 15 | ``` 16 | Then set the callback notification function, like 17 | ```c++ 18 | net.SetAcceptCallback(std::bind(&HttpServer::OnConnection, &server, std::placeholders::_1, std::placeholders::_2)); 19 | net.SetWriteCallback(std::bind(&HttpServer::OnMessageSend, &server, std::placeholders::_1, std::placeholders::_2)); 20 | net.SetReadCallback(std::bind(&HttpServer::OnMessage, &server, std::placeholders::_1, std::placeholders::_2, 21 | std::placeholders::_3)); 22 | net.SetDisconnectionCallback(std::bind(&HttpServer::OnDisConnection, &server, std::placeholders::_1, std::placeholders::_2)); 23 | ``` 24 | Other API details, see [API](../api/api.md). 25 | Relevant examples can be referred to [test](../../test). 26 | 27 | ### Best Practices 28 | 29 | **About Thread** 30 | + On Linux and MacOS, Each received client socket will only be active in one thread, So you don't have to think about thread safety. 31 | + On Windows, The IOCP schedules all IO threads to wake up, The read and write of each socket is not fixed in one thread, so thread safety should be considered. 32 | + All network IO and callbacks are performed in child threads. Do not perform time-consuming operations in callbacks. 33 | + If the main thread does not have other blocking operations, call the `Join` interface to block and wait for the network IO thread. 34 | 35 | 36 | **Connection Context** 37 | `CNSocket` Provided 38 | ```c++ 39 | virtual void SetContext(void* context) = 0; 40 | virtual void* GetContext() = 0; 41 | ``` 42 | connection context setting interface. It can be set in the connection request callback, obtained in the send or read callback, and destructed in the connection disconnection callback. There is no need to maintain a central data structure in the application layer. 43 | The use process can be referred to [httpser](../../test/http/http_server.cpp)。 44 | 45 | **Socket Object** 46 | The `CNSocket` handle that is passed in each callback, it's life cycle is maintained by intelligent pointer internal `cppnet`. It is not recommended to hold it in the application layer, so as not to affect the resource release after the connection is closed. 47 | 48 | **Configure** 49 | Common configurations are defined in [cppnet_config.h](../../cppnet/cppnet_config.h), The function of each configuration item can be referred to the notes. 50 | On the Linux platform, the efficiency of opening the `EPOLLEXCLUSIVE` will be improved by nearly `40%`(see [ab bench](../efficiency/apache_ab_bench.md)), If the kernel version is higher than `4.5`, it is recommended to enable this setting. 51 | 52 | **Multi Port** 53 | When there are multiple ports to listen on, it can be called repeatedly 54 | ```c++ 55 | bool ListenAndAccept(const std::string& ip, uint16_t port); 56 | ``` 57 | In the callback notification of connection establishment, through 58 | ```c++ 59 | virtual uint16_t GetListenPort() = 0; 60 | ``` 61 | interface gets the listening port to distinguish different services. 62 | The use process can be referred to [multi_port](../../test/multi_port/multi_port_server.cpp)。 -------------------------------------------------------------------------------- /doc/start/quick_start_cn.md: -------------------------------------------------------------------------------- 1 | # 快速开始 2 | 3 | ### 编译 4 | 通过`git`下载源码,然后编译`cppnet`静态库,编译请参考[编译](../build/build_cn.md)。 5 | 需要引用的头文件定义在[include](../../include)目录中,只需引用一个头文件即可。 6 | ```c++ 7 | #include "include/cppnet.h" 8 | ``` 9 | 10 | ### 使用 11 | 构造`CppNet`实例,并调用`Init`接口初始化,类似 12 | ```c++ 13 | CppNet net; 14 | net.Init(2); 15 | ``` 16 | 之后设置各个关心的回调通知函数,类似: 17 | ```c++ 18 | net.SetAcceptCallback(std::bind(&HttpServer::OnConnection, &server, std::placeholders::_1, std::placeholders::_2)); 19 | net.SetWriteCallback(std::bind(&HttpServer::OnMessageSend, &server, std::placeholders::_1, std::placeholders::_2)); 20 | net.SetReadCallback(std::bind(&HttpServer::OnMessage, &server, std::placeholders::_1, std::placeholders::_2, 21 | std::placeholders::_3)); 22 | net.SetDisconnectionCallback(std::bind(&HttpServer::OnDisConnection, &server, std::placeholders::_1, std::placeholders::_2)); 23 | ``` 24 | 其他API详情可参考[API](../api/api_cn.md)。 25 | 相关使用示例可参考[test](../../test)。 26 | 27 | ### 最佳实践 28 | 29 | **线程** 30 | + 在Linux和MacOS上,每个接收到的client socket都只会在一个线程中活动,所以不必考虑线程安全问题。 31 | + Windows上,由IOCP调度所有的IO线程唤醒,每个socket的读写不固定在一个线程内,需考虑线程安全问题。 32 | + 所有的网络IO和回调均在子线程中进行,请勿在各回调中进行耗时操作。 33 | + 若主线程没有其他阻塞操作,请调用`Join`接口阻塞等待网络IO线程。 34 | 35 | 36 | **连接上下文** 37 | `CNSocket`提供了 38 | ```c++ 39 | virtual void SetContext(void* context) = 0; 40 | virtual void* GetContext() = 0; 41 | ``` 42 | 连接上下文设置接口,可以在连接请求的回调中设置,在发送或读取回调中获取,在连接断开回调中析构,不用在应用层维护一个中心的数据结构。 43 | 使用过程可参考[httpser](../../test/http/http_server.cpp)。 44 | 45 | **Socket对象** 46 | 建立连接的`CNSocket`句柄在每次回调中传递,`cppnet`内部通过智能指针维护其生命周期,不建议在应用层持有,以免影响连接关闭后的资源释放。 47 | 48 | **配置** 49 | 通用的配置都定义在[cppnet_config.h](../../cppnet/cppnet_config.h)文件中,其中各配置项作用可参考注释。 50 | 在Linux平台上,开启`EPOLLEXCLUSIVE`标识效率会提升近`40%`(参考[ab压测结果](../efficiency/apache_ab_bench_cn.md)),如果内核版本高于`4.5`建议开启此项设置。 51 | 52 | **多端口监听** 53 | 当有多个端口需要监听时,可重复调用 54 | ```c++ 55 | bool ListenAndAccept(const std::string& ip, uint16_t port); 56 | ``` 57 | 接口。在连接建立的回调通知中,通过 58 | ```c++ 59 | virtual uint16_t GetListenPort() = 0; 60 | ``` 61 | 接口获取监听端口,以区分不同服务。 62 | 使用过程可参考[multi_port](../../test/multi_port/multi_port_server.cpp)。 -------------------------------------------------------------------------------- /include/cppnet.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef INCLUDE_CPPNET 7 | #define INCLUDE_CPPNET 8 | 9 | #include 10 | #include 11 | 12 | #include "cppnet_buffer.h" 13 | #include "cppnet_socket.h" 14 | #include "cppnet_type.h" 15 | 16 | namespace cppnet { 17 | 18 | class CppNetBase; 19 | // cppnet instance 20 | class CppNet { 21 | public: 22 | CppNet() = default; 23 | ~CppNet(); 24 | // common 25 | // init cppnet library. 26 | // thread_num : the number of running threads. 27 | void Init(int32_t thread_num = 0); 28 | void Destory(); 29 | 30 | // thread join 31 | void Join(); 32 | 33 | // must set callback before listen 34 | void SetReadCallback(read_call_back&& cb); 35 | void SetWriteCallback(write_call_back&& cb); 36 | void SetDisconnectionCallback(connect_call_back&& cb); 37 | 38 | // if use socket timer, set it 39 | void SetTimerCallback(timer_call_back&& cb); 40 | 41 | // return timer id 42 | uint64_t AddTimer(int32_t interval, user_timer_call_back&& cb, void* param = nullptr, bool always = false); 43 | void RemoveTimer(uint64_t timer_id); 44 | 45 | //server 46 | void SetAcceptCallback(connect_call_back&& cb); 47 | bool ListenAndAccept(const std::string& ip, uint16_t port); 48 | 49 | //client 50 | void SetConnectionCallback(connect_call_back&& cb); 51 | bool Connection(const std::string& ip, uint16_t port); 52 | 53 | private: 54 | std::shared_ptr _cppnet_base; 55 | }; 56 | 57 | } // namespace cppnet 58 | 59 | #endif -------------------------------------------------------------------------------- /include/cppnet_buffer.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef INCLUDE_CPPNET_BUFFER 7 | #define INCLUDE_CPPNET_BUFFER 8 | 9 | #include 10 | 11 | namespace cppnet { 12 | 13 | class Buffer { 14 | public: 15 | Buffer() = default; 16 | virtual ~Buffer() = default; 17 | 18 | // read to data to buf but don't move the read point. 19 | // return read size. 20 | virtual uint32_t ReadNotMovePt(char* buf, uint32_t buf_len) = 0; 21 | // read data to res buf and move the read point. 22 | // return read size. 23 | virtual uint32_t Read(char* res, uint32_t len) = 0; 24 | 25 | // clear all data 26 | virtual void Clear() = 0; 27 | 28 | // do not read when buffer less than len. 29 | // return len when read otherwise return 0 30 | virtual uint32_t ReadUntil(char* res, uint32_t len) = 0; 31 | 32 | // move read point 33 | virtual int32_t MoveReadPt(int32_t len) = 0; 34 | 35 | // do not read when can't find specified character. 36 | // return read bytes when read otherwise return 0 37 | // when find specified character but res length is too short, 38 | // return 0 and the last param return need length 39 | virtual uint32_t ReadUntil(char* res, uint32_t len, const char* find, uint32_t find_len, uint32_t& need_len) = 0; 40 | 41 | // return size of data that can be read 42 | virtual uint32_t GetCanReadLength() = 0; 43 | 44 | // return can read bytes 45 | virtual uint32_t FindStr(const char* s, uint32_t s_len) = 0; 46 | }; 47 | 48 | } // namespace cppnet 49 | 50 | #endif -------------------------------------------------------------------------------- /include/cppnet_socket.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef INCLUDE_CPPNET_SOCKET 7 | #define INCLUDE_CPPNET_SOCKET 8 | 9 | #include 10 | #include 11 | 12 | namespace cppnet { 13 | 14 | // cppnet socket interface 15 | class CNSocket { 16 | public: 17 | CNSocket() = default; 18 | virtual ~CNSocket() = default; 19 | // get os native socket 20 | virtual uint64_t GetSocket() = 0; 21 | // get local listen port 22 | virtual uint16_t GetListenPort() = 0; 23 | // get socket IP and address 24 | virtual bool GetAddress(std::string& ip, uint16_t& port) = 0; 25 | 26 | // post sync write event. 27 | virtual bool Write(const char* src, uint32_t len) = 0; 28 | // close the connect 29 | virtual void Close() = 0; 30 | 31 | // add a timer. must set timer call back 32 | // interval support max 1 minute 33 | virtual void AddTimer(uint32_t interval, bool always = false) = 0; 34 | // stop the timer 35 | virtual void StopTimer() = 0; 36 | 37 | // set cppnet socket context. 38 | virtual void SetContext(void* context) = 0; 39 | // get context. 40 | virtual void* GetContext() = 0; 41 | }; 42 | 43 | } // namespace cppnet 44 | 45 | #endif -------------------------------------------------------------------------------- /include/cppnet_type.h: -------------------------------------------------------------------------------- 1 | // Use of this source code is governed by a BSD 3-Clause License 2 | // that can be found in the LICENSE file. 3 | 4 | // Author: caozhiyi (caozhiyi5@gmail.com) 5 | 6 | #ifndef INCLUDE_CPPNET_TYPE 7 | #define INCLUDE_CPPNET_TYPE 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace cppnet { 14 | 15 | // socket 16 | class Buffer; 17 | class CNSocket; 18 | using Handle = std::shared_ptr; 19 | using BufferPtr = std::shared_ptr; 20 | 21 | // call back define 22 | // param : param is set when call 23 | using timer_call_back = std::function; 24 | using user_timer_call_back = std::function; 25 | 26 | // handle : handle of socket 27 | // err : error code 28 | using connect_call_back = std::function; 29 | 30 | // handle : handle of socket 31 | // len : send date len 32 | using write_call_back = std::function; 33 | 34 | // handle : handle of socket 35 | // data : point to recv data buffer 36 | // len : recv data len 37 | using read_call_back = std::function; 38 | 39 | // error code 40 | enum CPPNET_ERROR_CODE { 41 | CEC_SUCCESS = 0, // success. 42 | CEC_CLOSED = 1, // remote close the socket. 43 | CEC_CONNECT_BREAK = 2, // connection break. 44 | CEC_CONNECT_REFUSE = 3, // remote refuse connect or server not exist. 45 | }; 46 | 47 | } // namespace cppnet 48 | 49 | #endif -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | detected_OS := $(shell sh -c 'uname 2>/dev/null || echo Unknown') 2 | 3 | SRCS = $(wildcard ./common/alloter/*.cpp \ 4 | ./common/buffer/*.cpp \ 5 | ./common/log/*.cpp \ 6 | ./common/timer/*.cpp \ 7 | ./common/network/*.cpp \ 8 | ./common/network/posix/*.cpp \ 9 | ./common/structure/*.cpp \ 10 | ./common/thread/*.cpp \ 11 | ./common/util/*.cpp \ 12 | ./common/os/*.cpp \ 13 | ./common/os/posix/*.cpp \ 14 | ./common/util/*.cpp \ 15 | ./cppnet/event/*.cpp \ 16 | ./cppnet/socket/*.cpp \ 17 | ./cppnet/*.cpp \ 18 | ) 19 | 20 | ifeq ($(detected_OS),Linux) #linux 21 | SRCS += $(wildcard ./cppnet/event/epoll/*.cpp) 22 | endif 23 | 24 | ifeq ($(detected_OS),Darwin) # Mac OS X 25 | SRCS += $(wildcard ./cppnet/event/kqueue/*.cpp) 26 | endif 27 | 28 | ifeq ($(detected_OS),FreeBSD) # FreeBSD 29 | SRCS += $(wildcard ./cppnet/event/kqueue/*.cpp) 30 | endif 31 | 32 | OBJS = $(patsubst %.cpp, %.o, $(SRCS)) 33 | 34 | 35 | CC = g++ 36 | 37 | INCLUDES = -I. 38 | 39 | #debug 40 | 41 | #CCFLAGS = -lpthread -fPIC -m64 -g -std=c++11 -lstdc++ -pipe -Wall 42 | 43 | CCFLAGS = -lpthread -fPIC -m64 -O2 -std=c++11 -lstdc++ -pipe 44 | 45 | TARGET = libcppnet.a 46 | 47 | all:$(TARGET) 48 | 49 | $(TARGET):$(OBJS) 50 | ar rcs $@ $^ 51 | 52 | %.o : %.cpp 53 | $(CC) -c $< -o $@ $(CCFLAGS) $(INCLUDES) 54 | 55 | clean: 56 | rm -rf $(OBJS) $(TARGET) $(SERBIN) $(CLIBIN) 57 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(echo) 2 | add_subdirectory(http) 3 | add_subdirectory(pingpong) 4 | add_subdirectory(rpc) 5 | add_subdirectory(sendfile) 6 | add_subdirectory(simple) 7 | add_subdirectory(multi_port) 8 | -------------------------------------------------------------------------------- /test/echo/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | project(echoclient) 4 | add_executable(${PROJECT_NAME} echo_client.cpp) 5 | 6 | if(WIN32) 7 | target_link_libraries(${PROJECT_NAME} cppnet) 8 | target_link_libraries(${PROJECT_NAME} ws2_32) 9 | else() 10 | target_link_libraries(${PROJECT_NAME} cppnet) 11 | target_link_libraries(${PROJECT_NAME} pthread) 12 | endif() 13 | 14 | 15 | project(echoserver) 16 | add_executable(${PROJECT_NAME} echo_server.cpp) 17 | 18 | if(WIN32) 19 | target_link_libraries(${PROJECT_NAME} cppnet) 20 | target_link_libraries(${PROJECT_NAME} ws2_32) 21 | else() 22 | target_link_libraries(${PROJECT_NAME} cppnet) 23 | target_link_libraries(${PROJECT_NAME} pthread) 24 | endif() 25 | 26 | -------------------------------------------------------------------------------- /test/echo/echo_client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include // for std::find 6 | 7 | #include "common/util/time.h" 8 | #include "include/cppnet.h" 9 | 10 | using namespace cppnet; 11 | 12 | std::atomic_bool __stop(false); 13 | int msg_index = 0; 14 | std::map handle_map; 15 | static const char* __buf_spilt = "\r\n"; 16 | 17 | 18 | std::string GetMsg() { 19 | return "It is a test msg, It is a long test msg. index : " + std::to_string(msg_index++) + __buf_spilt; 20 | } 21 | 22 | void ReadFunc(Handle handle, cppnet::BufferPtr data, uint32_t len) { 23 | // print 24 | char buf[1024] = {0}; 25 | data->Read(buf, 1024); 26 | std::cout << buf << std::endl; 27 | cppnet::Sleep(100); 28 | handle->Write(buf, len); 29 | } 30 | 31 | void ConnectFunc(Handle handle, uint32_t error) { 32 | if (error != CEC_SUCCESS) { 33 | std::cout << "something err while connect : " << error << std::endl; 34 | } else { 35 | handle_map[handle->GetSocket()] = handle; 36 | 37 | auto msg = GetMsg(); 38 | handle->Write(msg.c_str(), (uint32_t)msg.length()); 39 | } 40 | } 41 | 42 | void DisConnectionFunc(Handle handle, uint32_t err) { 43 | __stop = true; 44 | handle_map.erase(handle->GetSocket()); 45 | if (handle_map.empty()) { 46 | std::cout << "20 clients all disconnect" << std::endl; 47 | } 48 | } 49 | 50 | int main() { 51 | cppnet::CppNet net; 52 | net.Init(1); 53 | 54 | net.SetConnectionCallback(ConnectFunc); 55 | net.SetReadCallback(ReadFunc); 56 | net.SetDisconnectionCallback(DisConnectionFunc); 57 | for (size_t i = 0; i < 200; i++) { 58 | net.Connection("127.0.0.1", 8921); 59 | } 60 | // wait all connect success. 61 | cppnet::Sleep(20000); 62 | 63 | std::cout << "200 clients all connected" << std::endl; 64 | 65 | net.Join(); 66 | } 67 | -------------------------------------------------------------------------------- /test/echo/echo_server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include // for strlen 5 | #include 6 | 7 | #include "include/cppnet.h" 8 | 9 | using namespace cppnet; 10 | 11 | static const int __buf_len = 2048; 12 | static const char* __buf_spilt = "\r\n"; 13 | 14 | void ReadFunc(Handle handle, cppnet::BufferPtr data, uint32_t len) { 15 | char msg_buf[__buf_len] = {0}; 16 | uint32_t need_len = 0; 17 | uint32_t find_len = (uint32_t)strlen(__buf_spilt); 18 | // get recv data to send back. 19 | uint32_t size = data->ReadUntil(msg_buf, __buf_len, __buf_spilt, find_len, need_len); 20 | handle->Write(msg_buf, size); 21 | } 22 | 23 | void ConnectFunc(Handle handle, uint32_t error) { 24 | static std::mutex mutex; 25 | std::lock_guard lock(mutex); 26 | if (error == CEC_CLOSED) { 27 | std::cout << "remote closed connect : " << handle->GetSocket() << std::endl; 28 | } else if (error != CEC_SUCCESS) { 29 | std::cout << "something err while connect : " << error << std::endl; 30 | } 31 | } 32 | 33 | 34 | int main() { 35 | 36 | // start 4 threads 37 | cppnet::CppNet net; 38 | net.Init(4); 39 | 40 | net.SetAcceptCallback(ConnectFunc); 41 | net.SetReadCallback(ReadFunc); 42 | net.SetDisconnectionCallback(ConnectFunc); 43 | 44 | net.ListenAndAccept("0.0.0.0", 8921); 45 | 46 | net.Join(); 47 | } -------------------------------------------------------------------------------- /test/echo/makefile: -------------------------------------------------------------------------------- 1 | SER = echo_server.cpp 2 | CLI = echo_client.cpp 3 | 4 | CC = g++ 5 | 6 | INCLUDES = -I../../ 7 | 8 | #debug 9 | #CCFLAGS = -lpthread -fPIC -m64 -g -std=c++11 -lstdc++ -pipe 10 | 11 | CCFLAGS = -lpthread -fPIC -m64 -O2 -std=c++11 -lstdc++ -pipe 12 | 13 | TARGET = ../../libcppnet.a 14 | SERBIN = echoserver 15 | CLIBIN = echoclient 16 | 17 | all:$(SERBIN) $(CLIBIN) 18 | 19 | $(SERBIN):$(SER) 20 | $(CC) $(SER) -o $@ $(TARGET) $(CCFLAGS) $(INCLUDES) 21 | 22 | $(CLIBIN):$(CLI) 23 | $(CC) $(CLI) -o $@ $(TARGET) $(CCFLAGS) $(INCLUDES) 24 | 25 | clean: 26 | rm -rf $(SERBIN) $(CLIBIN) -------------------------------------------------------------------------------- /test/http/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | aux_source_directory(${CMAKE_CURRENT_LIST_DIR} http_source) 4 | 5 | project(httpser) 6 | add_executable(${PROJECT_NAME} ${http_source}) 7 | 8 | if(WIN32) 9 | target_link_libraries(${PROJECT_NAME} cppnet) 10 | target_link_libraries(${PROJECT_NAME} ws2_32) 11 | else() 12 | target_link_libraries(${PROJECT_NAME} cppnet) 13 | target_link_libraries(${PROJECT_NAME} pthread) 14 | endif() 15 | -------------------------------------------------------------------------------- /test/http/http.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /test/http/http_context.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "http_context.h" 3 | #include "include/cppnet_buffer.h" 4 | 5 | const char CRLF[] = "\r\n"; 6 | const int CRLF_LEN = 2; 7 | const int VERSION_LEN = sizeof("HTTP/1.1"); 8 | 9 | bool HttpContext::processRequestLine(const char* begin, const char* end) { 10 | bool succeed = false; 11 | const char* start = begin; 12 | const char* space = std::find(start, end, ' '); 13 | if (space != end && _request.SetMethod(start, space)) { 14 | start = space + 1; 15 | space = std::find(start, end, ' '); 16 | if (space != end) { 17 | const char* question = std::find(start, space, '?'); 18 | if (question != space) { 19 | _request.SetPath(start, question); 20 | _request.SetQuery(question, space); 21 | 22 | } else { 23 | _request.SetPath(start, space); 24 | } 25 | 26 | start = space + 1; 27 | const char* version_end = start + VERSION_LEN - 1; 28 | succeed = true; 29 | if (std::equal(start, version_end, "HTTP/1.1")) { 30 | _request.SetVersion(Http11); 31 | 32 | } else if (std::equal(start, version_end, "HTTP/1.0")) { 33 | _request.SetVersion(Http10); 34 | 35 | } else { 36 | succeed = false; 37 | } 38 | } 39 | } 40 | return succeed; 41 | } 42 | 43 | // return false if any error 44 | bool HttpContext::ParseRequest(cppnet::BufferPtr buf, uint64_t receive_time) { 45 | bool ok = true; 46 | bool hasMore = true; 47 | while (hasMore) { 48 | if (_state == ExpectRequestLine) { 49 | char line_buf[1024] = {0}; 50 | uint32_t need_len = 0; 51 | uint32_t size = buf->ReadUntil(line_buf, 1024, CRLF, CRLF_LEN, need_len); 52 | if (size > 0) { 53 | ok = processRequestLine(line_buf, line_buf + size); 54 | if (ok) { 55 | _request.SetReceiveTime(receive_time); 56 | _state = ExpectHeaders; 57 | 58 | } else { 59 | hasMore = false; 60 | } 61 | 62 | } else { 63 | hasMore = false; 64 | } 65 | 66 | } else if (_state == ExpectHeaders) { 67 | char line_buf[1024] = { 0 }; 68 | uint32_t need_len = 0; 69 | uint32_t size = buf->ReadUntil(line_buf, 1024, CRLF, CRLF_LEN, need_len); 70 | char* end = line_buf + size - CRLF_LEN; 71 | if (size > 0) { 72 | const char* colon = std::find(line_buf, end, ':'); 73 | if (colon != end) { 74 | _request.AddHeader(line_buf, colon, end); 75 | 76 | } else { 77 | // empty line, end of header 78 | // FIXME: 79 | _state = GotAll; 80 | hasMore = false; 81 | } 82 | 83 | } else { 84 | hasMore = false; 85 | } 86 | 87 | } else if (_state == ExpectBody) { 88 | // TODO: 89 | } 90 | } 91 | return ok; 92 | } 93 | -------------------------------------------------------------------------------- /test/http/http_context.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_HTTP_HTTP_CONTEXT_HEADER 2 | #define TEST_HTTP_HTTP_CONTEXT_HEADER 3 | 4 | #include "http_request.h" 5 | #include "include/cppnet_type.h" 6 | 7 | enum HttpRequestParseState{ 8 | ExpectRequestLine, 9 | ExpectHeaders, 10 | ExpectBody, 11 | GotAll, 12 | }; 13 | 14 | class HttpContext { 15 | public: 16 | HttpContext() : _state(ExpectRequestLine), _request() { } 17 | ~HttpContext() {} 18 | 19 | // default copy-ctor, dtor and assignment are fine 20 | // return false if any error 21 | bool ParseRequest(cppnet::BufferPtr buf, uint64_t receive_time); 22 | 23 | bool IsGotAll() const { 24 | return _state == GotAll; 25 | } 26 | 27 | void Reset() { 28 | _state = ExpectRequestLine; 29 | _request.Clear(); 30 | } 31 | 32 | const HttpRequest& GetRequest() const { 33 | return _request; 34 | } 35 | 36 | HttpRequest& GetRequest(){ 37 | return _request; 38 | } 39 | 40 | bool IsKeepAlive() { 41 | const std::string& connection = _request.GetHeader("Connection"); 42 | return !(connection != "close" || (_request.GetVersion() == Http10 && connection != "Keep-Alive")); 43 | } 44 | 45 | private: 46 | bool processRequestLine(const char* begin, const char* end); 47 | private: 48 | HttpRequestParseState _state; 49 | HttpRequest _request; 50 | }; 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /test/http/http_request.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_HTTP_HTTP_REQUEST_HEADER 2 | #define TEST_HTTP_HTTP_REQUEST_HEADER 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | enum Method { 11 | Invalid, 12 | Get, 13 | Post, 14 | Head, 15 | Put, 16 | Delete 17 | }; 18 | 19 | enum Version { 20 | Unknown, 21 | Http10, 22 | Http11 23 | }; 24 | 25 | class HttpRequest { 26 | public: 27 | HttpRequest() : _method(Invalid), _version(Unknown), _path(), _query(), _receive_time(0), _headers_map() { } 28 | ~HttpRequest() { 29 | _headers_map.clear(); 30 | } 31 | 32 | void SetVersion(Version v) { 33 | _version = v; 34 | } 35 | 36 | Version GetVersion() const { 37 | return _version; 38 | } 39 | 40 | bool SetMethod(const char* start, const char* end) { 41 | assert(_method == Invalid); 42 | std::string temp_method(start, end); 43 | if (temp_method == "GET") { 44 | _method = Get; 45 | 46 | } else if (temp_method == "POST") { 47 | _method = Post; 48 | 49 | } else if (temp_method == "HEAD") { 50 | _method = Head; 51 | 52 | } else if (temp_method == "PUT") { 53 | _method = Put; 54 | 55 | } else if (temp_method == "DELETE") { 56 | _method = Delete; 57 | 58 | } else { 59 | _method = Invalid; 60 | } 61 | return _method != Invalid; 62 | } 63 | 64 | Method GetMethod() const { 65 | return _method; 66 | } 67 | 68 | const char* GetMethodString() const { 69 | const char* result = "UNKNOWN"; 70 | switch(_method) 71 | { 72 | case Get: 73 | result = "GET"; 74 | break; 75 | case Post: 76 | result = "POST"; 77 | break; 78 | case Head: 79 | result = "HEAD"; 80 | break; 81 | case Put: 82 | result = "PUT"; 83 | break; 84 | case Delete: 85 | result = "DELETE"; 86 | break; 87 | default: 88 | break; 89 | } 90 | return result; 91 | } 92 | 93 | void SetPath(const char* start, const char* end) { 94 | _path.assign(start, end); 95 | } 96 | 97 | const std::string& GetPath() const { 98 | return _path; 99 | } 100 | 101 | void SetQuery(const char* start, const char* end) { 102 | _query.assign(start, end); 103 | } 104 | 105 | const std::string& GetQuery() const { 106 | return _query; 107 | } 108 | 109 | void SetReceiveTime(uint64_t t) { 110 | _receive_time = t; 111 | } 112 | 113 | uint64_t GetReceiveTime() const { 114 | return _receive_time; 115 | } 116 | 117 | void AddHeader(const char* start, const char* colon, const char* end) { 118 | std::string field(start, colon); 119 | ++colon; 120 | while (colon < end && isspace(*colon)) { 121 | ++colon; 122 | } 123 | std::string value(colon, end); 124 | while (!value.empty() && isspace(value[value.size()-1])) { 125 | value.resize(value.size()-1); 126 | } 127 | _headers_map[field] = value; 128 | } 129 | 130 | std::string GetHeader(const std::string& field) const { 131 | std::string result; 132 | auto it = _headers_map.find(field); 133 | if (it != _headers_map.end()) { 134 | result = it->second; 135 | } 136 | return result; 137 | } 138 | 139 | const std::unordered_map& GetHeaders() const { 140 | return _headers_map; 141 | } 142 | 143 | void Clear() { 144 | _method = Invalid; 145 | _version = Unknown; 146 | _headers_map.clear(); 147 | _path.clear(); 148 | _query.clear(); 149 | } 150 | 151 | private: 152 | Method _method; 153 | Version _version; 154 | std::string _path; 155 | std::string _query; 156 | uint64_t _receive_time; 157 | std::unordered_map _headers_map; 158 | }; 159 | 160 | #endif -------------------------------------------------------------------------------- /test/http/http_response.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "http_response.h" 4 | 5 | std::string HttpResponse::GetSendBuffer() const { 6 | std::string ret; 7 | ret.append("HTTP/1.1 "); 8 | ret.append(std::to_string(_status_code)); 9 | ret.append(" "); 10 | ret.append(_status_message); 11 | ret.append("\r\n"); 12 | 13 | if (_close_connection) { 14 | ret.append("Connection: close\r\n"); 15 | 16 | } else { 17 | ret.append("Content-Length: "); 18 | ret.append(std::to_string(_body.size())); 19 | ret.append("\r\n"); 20 | ret.append("Connection: Keep-Alive\r\n"); 21 | } 22 | 23 | for (const auto& header : _headers_map) { 24 | ret.append(header.first); 25 | ret.append(": "); 26 | ret.append(header.second); 27 | ret.append("\r\n"); 28 | } 29 | ret.append("\r\n"); 30 | ret.append(_body); 31 | 32 | return std::move(ret); 33 | } 34 | -------------------------------------------------------------------------------- /test/http/http_response.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_HTTP_HTTP_RESPONSE_HEADER 2 | #define TEST_HTTP_HTTP_RESPONSE_HEADER 3 | 4 | #include 5 | #include 6 | 7 | enum HttpStatusCode { 8 | kUnknown, 9 | k200Ok = 200, 10 | k301MovedPermanently = 301, 11 | k400BadRequest = 400, 12 | k404NotFound = 404, 13 | }; 14 | 15 | class HttpResponse { 16 | public: 17 | explicit HttpResponse(bool close) : _status_code(kUnknown), _close_connection(close) { 18 | } 19 | 20 | void SetStatusCode(HttpStatusCode code) { 21 | _status_code = code; 22 | } 23 | 24 | void SetStatusMessage(const std::string& message) { 25 | _status_message = message; 26 | } 27 | 28 | void SetCloseConnection(bool on) { 29 | _close_connection = on; 30 | } 31 | 32 | bool GetCloseConnection() const { 33 | return _close_connection; 34 | } 35 | 36 | void SetContentType(const std::string& contentType) { 37 | AddHeader("Content-Type", contentType); 38 | } 39 | 40 | // FIXME: replace string with StringPiece 41 | void AddHeader(const std::string& key, const std::string& value) { 42 | _headers_map[key] = value; 43 | } 44 | 45 | void SetBody(const std::string& body) { 46 | _body = body; 47 | } 48 | 49 | std::string GetSendBuffer() const; 50 | 51 | private: 52 | std::map _headers_map; 53 | HttpStatusCode _status_code; 54 | // FIXME: add http version 55 | std::string _status_message; 56 | bool _close_connection; 57 | std::string _body; 58 | }; 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /test/http/http_server.cpp: -------------------------------------------------------------------------------- 1 | #include "http_server.h" 2 | #include "http_request.h" 3 | #include "http_context.h" 4 | #include "http_response.h" 5 | 6 | #include "common/util/time.h" 7 | 8 | using namespace cppnet; 9 | 10 | HttpServer::HttpServer() { 11 | 12 | } 13 | 14 | HttpServer::~HttpServer() { 15 | 16 | } 17 | 18 | void HttpServer::OnConnection(cppnet::Handle handle, uint32_t err) { 19 | if (err == CEC_SUCCESS) { 20 | auto context = new HttpContext(); 21 | handle->SetContext((void*)context); 22 | } 23 | } 24 | 25 | void HttpServer::OnDisConnection(cppnet::Handle handle, uint32_t err) { 26 | auto context = (HttpContext*)handle->GetContext(); 27 | delete context; 28 | } 29 | 30 | void HttpServer::OnMessage(cppnet::Handle handle, cppnet::BufferPtr data, 31 | uint32_t) { 32 | 33 | auto context = (HttpContext*)handle->GetContext(); 34 | 35 | if (!context->ParseRequest(data, cppnet::UTCTimeMsec())) { 36 | handle->Write("HTTP/1.1 400 Bad Request\r\n\r\n", sizeof("HTTP/1.1 400 Bad Request\r\n\r\n")); 37 | handle->Close(); 38 | } 39 | 40 | if (context->IsGotAll()) { 41 | bool is_keep_alive = context->IsKeepAlive(); 42 | OnRequest(handle, !is_keep_alive, context->GetRequest()); 43 | 44 | if (is_keep_alive) { 45 | context->Reset(); 46 | } 47 | } 48 | } 49 | 50 | void HttpServer::OnMessageSend(cppnet::Handle , uint32_t) { 51 | // do nothing. 52 | } 53 | 54 | void HttpServer::OnRequest(cppnet::Handle handle, bool close, const HttpRequest& req) { 55 | HttpResponse response(close); 56 | _http_call_back(req, response); 57 | 58 | std::string res = response.GetSendBuffer(); 59 | handle->Write(res.c_str(), (uint32_t)res.length()); 60 | if (response.GetCloseConnection()) { 61 | handle->Close(); 62 | } 63 | } 64 | 65 | -------------------------------------------------------------------------------- /test/http/http_server.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_HTTP_HTTPSERVER_HEADER 2 | #define TEST_HTTP_HTTPSERVER_HEADER 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "http_context.h" 9 | #include "http_request.h" 10 | #include "http_response.h" 11 | 12 | #include "include/cppnet.h" 13 | 14 | typedef std::function HttpCallback; 15 | 16 | class HttpServer { 17 | public: 18 | HttpServer(); 19 | ~HttpServer(); 20 | 21 | void SetHttpCallback(const HttpCallback& cb) { 22 | _http_call_back = cb; 23 | } 24 | 25 | void OnConnection(cppnet::Handle handle, uint32_t err); 26 | 27 | void OnDisConnection(cppnet::Handle handle, uint32_t err); 28 | 29 | void OnMessage(cppnet::Handle handle, cppnet::BufferPtr data, 30 | uint32_t len); 31 | 32 | void OnMessageSend(cppnet::Handle handle, uint32_t len); 33 | 34 | private: 35 | void OnRequest(cppnet::Handle handle, bool close, const HttpRequest&); 36 | 37 | private: 38 | HttpCallback _http_call_back; 39 | }; 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /test/http/http_server_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "http_server.h" 7 | #include "http_request.h" 8 | #include "http_response.h" 9 | 10 | #include "common/util/time.h" 11 | 12 | std::string image; 13 | bool benchmark = true; 14 | 15 | std::string GetFile(); 16 | void OnRequest(const HttpRequest& req, HttpResponse& resp) { 17 | //std::cout << "Headers " << req.GetMethodString() << " " << req.GetPath() << std::endl; 18 | if (!benchmark) { 19 | const std::unordered_map& headers = req.GetHeaders(); 20 | for (const auto& header : headers) { 21 | std::cout << header.first << ": " << header.second << std::endl; 22 | } 23 | } 24 | 25 | if (req.GetPath() == "/") { 26 | resp.SetStatusCode(k200Ok); 27 | resp.SetStatusMessage("OK"); 28 | resp.SetContentType("text/html"); 29 | resp.AddHeader("Server", "CppNet"); 30 | std::string now = cppnet::GetFormatTime(); 31 | resp.SetBody("This is title" 32 | "

Hello

Now is " + now + 33 | ""); 34 | 35 | } else if (req.GetPath() == "/favicon.ico") { 36 | resp.SetStatusCode(k200Ok); 37 | resp.SetStatusMessage("OK"); 38 | resp.SetContentType("image/png"); 39 | if (image.empty()) { 40 | image = GetFile(); 41 | } 42 | resp.SetBody(image); 43 | 44 | } else if (req.GetPath() == "/hello") { 45 | resp.SetStatusCode(k200Ok); 46 | resp.SetStatusMessage("OK"); 47 | resp.SetContentType("text/plain"); 48 | resp.AddHeader("Server", "CppNet"); 49 | resp.SetBody("hello, world!\n"); 50 | 51 | } else { 52 | resp.SetStatusCode(k404NotFound); 53 | resp.SetStatusMessage("Not Found"); 54 | resp.SetCloseConnection(true); 55 | } 56 | } 57 | 58 | std::string GetFile() { 59 | std::ifstream t("logo.png"); 60 | std::string str((std::istreambuf_iterator(t)), 61 | std::istreambuf_iterator()); 62 | return std::move(str); 63 | } 64 | 65 | void DisConnectionFunc(const cppnet::Handle& , uint32_t ) { 66 | //std::cout << "[DisConnectionFunc]" << std::endl; 67 | } 68 | 69 | int main() { 70 | cppnet::CppNet net; 71 | net.Init(2); 72 | 73 | HttpServer server; 74 | server.SetHttpCallback(OnRequest); 75 | 76 | net.SetAcceptCallback(std::bind(&HttpServer::OnConnection, &server, std::placeholders::_1, std::placeholders::_2)); 77 | net.SetWriteCallback(std::bind(&HttpServer::OnMessageSend, &server, std::placeholders::_1, std::placeholders::_2)); 78 | net.SetReadCallback(std::bind(&HttpServer::OnMessage, &server, std::placeholders::_1, std::placeholders::_2, 79 | std::placeholders::_3)); 80 | net.SetDisconnectionCallback(std::bind(&HttpServer::OnDisConnection, &server, std::placeholders::_1, std::placeholders::_2)); 81 | 82 | net.ListenAndAccept("0.0.0.0", 8921); 83 | 84 | net.Join(); 85 | } 86 | -------------------------------------------------------------------------------- /test/http/makefile: -------------------------------------------------------------------------------- 1 | SRCS = $(wildcard ./*.cpp) 2 | 3 | OBJS = $(patsubst %.cpp, %.o, $(SRCS)) 4 | 5 | CC = g++ 6 | 7 | INCLUDES = -I../../ 8 | 9 | #debug 10 | #CCFLAGS = -lpthread -fPIC -m64 -g -std=c++11 -lstdc++ -pipe 11 | 12 | CCFLAGS = -lpthread -fPIC -m64 -O2 -std=c++11 -lstdc++ -pipe 13 | 14 | TARGET = ../../libcppnet.a 15 | SERBIN = httpser 16 | 17 | all: $(SERBIN) 18 | 19 | $(SERBIN):$(OBJS) $(TARGET) 20 | $(CC) $^ -o $@ $(TARGET) $(CCFLAGS) $(INCLUDES) 21 | 22 | %.o : %.cpp 23 | $(CC) -c $< -o $@ $(CCFLAGS) $(INCLUDES) 24 | 25 | clean: 26 | rm -rf $(OBJS) $(SERBIN) -------------------------------------------------------------------------------- /test/multi_port/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(multiportserver) 2 | add_executable(${PROJECT_NAME} multi_port_server.cpp) 3 | 4 | if(WIN32) 5 | target_link_libraries(${PROJECT_NAME} cppnet) 6 | target_link_libraries(${PROJECT_NAME} ws2_32) 7 | else() 8 | target_link_libraries(${PROJECT_NAME} cppnet) 9 | target_link_libraries(${PROJECT_NAME} pthread) 10 | endif() 11 | 12 | 13 | project(multiportclient) 14 | add_executable(${PROJECT_NAME} multi_port_client.cpp) 15 | 16 | if(WIN32) 17 | target_link_libraries(${PROJECT_NAME} cppnet) 18 | target_link_libraries(${PROJECT_NAME} ws2_32) 19 | else() 20 | target_link_libraries(${PROJECT_NAME} cppnet) 21 | target_link_libraries(${PROJECT_NAME} pthread) 22 | endif() 23 | 24 | -------------------------------------------------------------------------------- /test/multi_port/makefile: -------------------------------------------------------------------------------- 1 | SER = multi_port_server.cpp 2 | CLI = multi_port_client.cpp 3 | 4 | CC = g++ 5 | 6 | INCLUDES = -I../../ 7 | 8 | #debug -pg 9 | CCFLAGS = -lpthread -fPIC -m64 -g -std=c++11 -lstdc++ -pipe 10 | 11 | #CCFLAGS = -lpthread -fPIC -m64 -O2 -std=c++11 -lstdc++ -pipe -march=corei7 12 | 13 | TARGET = ../../libcppnet.a 14 | SERBIN = multi_port_server 15 | CLIBIN = multi_port_client 16 | 17 | all:$(SERBIN) $(CLIBIN) 18 | 19 | $(SERBIN):$(SER) $(TARGET) 20 | $(CC) $(SER) -o $@ $(TARGET) $(CCFLAGS) $(INCLUDES) 21 | 22 | $(CLIBIN):$(CLI) $(TARGET) 23 | $(CC) $(CLI) -o $@ $(TARGET) $(CCFLAGS) $(INCLUDES) 24 | 25 | clean: 26 | rm -rf $(SERBIN) $(CLIBIN) 27 | -------------------------------------------------------------------------------- /test/multi_port/multi_port_client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "include/cppnet.h" 6 | #include "common/util/time.h" 7 | 8 | using namespace cppnet; 9 | 10 | void ConnectFunc(Handle handle, uint32_t err) { 11 | if (err == CEC_SUCCESS) { 12 | std::string msg("it is a test message."); 13 | handle->Write(msg.c_str(), (uint32_t)msg.length()); 14 | handle->Close(); 15 | 16 | } else { 17 | std::cout << " [ConnectFunc] some thing error : " << err << std::endl; 18 | } 19 | } 20 | 21 | 22 | int main() { 23 | 24 | cppnet::CppNet net; 25 | net.Init(1); 26 | net.SetConnectionCallback(ConnectFunc); 27 | 28 | net.Connection("127.0.0.1", 8921); 29 | net.Connection("127.0.0.1", 8922); 30 | 31 | Sleep(2000); 32 | } -------------------------------------------------------------------------------- /test/multi_port/multi_port_client.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /test/multi_port/multi_port_server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "include/cppnet.h" 7 | #include "common/util/time.h" 8 | 9 | using namespace cppnet; 10 | 11 | void ReadFunc(Handle handle, std::shared_ptr data, uint32_t len) { 12 | char msg_buf[128] = {0}; 13 | // get recv data to send back. 14 | uint32_t size = data->Read(msg_buf, 128); 15 | 16 | std::cout << "get message: " << msg_buf << " listen port is: " << handle->GetListenPort() << std::endl; 17 | } 18 | 19 | void ConnectFunc(Handle handle, uint32_t err) { 20 | if (err == CEC_SUCCESS) { 21 | std::cout << handle->GetListenPort() << " port get connect socket: " << handle->GetSocket() << std::endl; 22 | 23 | } else { 24 | std::cout << "[ConnectFunc] some thing error : " << err << std::endl; 25 | } 26 | } 27 | 28 | 29 | int main() { 30 | 31 | cppnet::CppNet net; 32 | net.Init(1); 33 | 34 | net.SetAcceptCallback(ConnectFunc); 35 | net.SetReadCallback(ReadFunc); 36 | 37 | net.ListenAndAccept("0.0.0.0", 8921); 38 | net.ListenAndAccept("0.0.0.0", 8922); 39 | 40 | net.Join(); 41 | } -------------------------------------------------------------------------------- /test/multi_port/multi_port_server.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /test/pingpong/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(pingpongserver) 2 | add_executable(${PROJECT_NAME} server.cpp) 3 | 4 | if(WIN32) 5 | target_link_libraries(${PROJECT_NAME} cppnet) 6 | target_link_libraries(${PROJECT_NAME} ws2_32) 7 | else() 8 | target_link_libraries(${PROJECT_NAME} cppnet) 9 | target_link_libraries(${PROJECT_NAME} pthread) 10 | endif() 11 | 12 | project(pingpongclient) 13 | add_executable(${PROJECT_NAME} client.cpp) 14 | 15 | if(WIN32) 16 | target_link_libraries(${PROJECT_NAME} cppnet) 17 | target_link_libraries(${PROJECT_NAME} ws2_32) 18 | else() 19 | target_link_libraries(${PROJECT_NAME} cppnet) 20 | target_link_libraries(${PROJECT_NAME} pthread) 21 | endif() -------------------------------------------------------------------------------- /test/pingpong/client.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /test/pingpong/makefile: -------------------------------------------------------------------------------- 1 | SER = server.cpp 2 | CLI = client.cpp 3 | 4 | CC = g++ 5 | 6 | INCLUDES = -I../../ 7 | 8 | #debug -pg 9 | #CCFLAGS = -lpthread -fPIC -m64 -g -std=c++11 -lstdc++ -pipe 10 | 11 | CCFLAGS = -lpthread -fPIC -m64 -O2 -std=c++11 -lstdc++ -pipe 12 | 13 | TARGET = ../../libcppnet.a 14 | SERBIN = pp_server 15 | CLIBIN = pp_client 16 | 17 | all:$(SERBIN) $(CLIBIN) 18 | 19 | $(SERBIN):$(SER) $(TARGET) 20 | $(CC) $(SER) -o $@ $(TARGET) $(CCFLAGS) $(INCLUDES) 21 | 22 | $(CLIBIN):$(CLI) $(TARGET) 23 | $(CC) $(CLI) -o $@ $(TARGET) $(CCFLAGS) $(INCLUDES) 24 | 25 | clean: 26 | rm -rf $(SERBIN) $(CLIBIN) 27 | -------------------------------------------------------------------------------- /test/pingpong/server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "include/cppnet.h" 5 | 6 | #ifdef __win__ 7 | #include 8 | void SetNoDelay(const uint64_t& sock) { 9 | int opt = 1; 10 | int ret = setsockopt(sock, SOL_SOCKET, TCP_NODELAY, (const char*)&opt, sizeof(opt)); 11 | } 12 | #else 13 | #include 14 | #include 15 | #include 16 | void SetNoDelay(const uint64_t& sock) { 17 | int optval = 1; 18 | setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, 19 | &optval, static_cast(sizeof(optval))); 20 | } 21 | #endif 22 | 23 | void OnConnection(const cppnet::Handle& handle, uint32_t error) { 24 | if (error == cppnet::CEC_SUCCESS) { 25 | SetNoDelay(handle->GetSocket()); 26 | } 27 | } 28 | 29 | void OnMessage(const cppnet::Handle& handle, cppnet::BufferPtr data, uint32_t) { 30 | char buff[65535]; 31 | 32 | while (data->GetCanReadLength()) { 33 | int ret = data->Read(buff, 65535); 34 | handle->Write(buff, ret); 35 | } 36 | } 37 | 38 | int main() { 39 | cppnet::CppNet net; 40 | net.Init(4); 41 | 42 | net.SetAcceptCallback(OnConnection); 43 | net.SetReadCallback(OnMessage); 44 | 45 | net.ListenAndAccept("0.0.0.0", 8921); 46 | 47 | net.Join(); 48 | } 49 | 50 | -------------------------------------------------------------------------------- /test/pingpong/server.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /test/rpc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | SET(common_source func_thread.cpp info_router.cpp parse_package.cpp rpc_client.cpp rpc_server.cpp) 4 | 5 | project(rpcserver) 6 | add_executable(${PROJECT_NAME} ${common_source} server.cpp) 7 | 8 | if(WIN32) 9 | target_link_libraries(${PROJECT_NAME} cppnet) 10 | target_link_libraries(${PROJECT_NAME} ws2_32) 11 | else() 12 | target_link_libraries(${PROJECT_NAME} cppnet) 13 | target_link_libraries(${PROJECT_NAME} pthread) 14 | endif() 15 | 16 | 17 | project(rpcclient) 18 | add_executable(${PROJECT_NAME} ${common_source} client.cpp) 19 | 20 | if(WIN32) 21 | target_link_libraries(${PROJECT_NAME} cppnet) 22 | target_link_libraries(${PROJECT_NAME} ws2_32) 23 | else() 24 | target_link_libraries(${PROJECT_NAME} cppnet) 25 | target_link_libraries(${PROJECT_NAME} pthread) 26 | endif() 27 | 28 | -------------------------------------------------------------------------------- /test/rpc/client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "rpc_client.h" 4 | #include "common/util/any.h" 5 | #include "common/util/time.h" 6 | using namespace std; 7 | 8 | void Add1CallBack(int code, std::vector& ret) { 9 | if (code == NO_ERROR) { 10 | cout << code << " " << cppnet::any_cast(ret[0]) << endl; 11 | } 12 | } 13 | 14 | Call_back func = Add1CallBack; 15 | 16 | int main() { 17 | RPCClient client; 18 | client.SetCallBack("Add1", func); 19 | client.Start(8951, "127.0.0.1"); 20 | for (;;) { 21 | cppnet::Sleep(1000); 22 | client.CallFunc("Add1", 100, 200); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/rpc/common_struct.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_RPC_COMMONSTRUCT_HEADER 2 | #define TEST_RPC_COMMONSTRUCT_HEADER 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "common/util/any.h" 9 | #include "include/cppnet_type.h" 10 | #include "include/cppnet_socket.h" 11 | 12 | enum MessageType { 13 | FUNCTION_CALL = 0x01, //client call functnion request 14 | FUNCTION_RET = 0x02, //server return functnion response 15 | FUNCTION_INFO = 0x04 //server notice functnion info 16 | }; 17 | 18 | enum ERROR_CODE { 19 | NO_ERROR = 0, 20 | PARAM_TYPE_ERROR = 1, 21 | PARAM_NUM_ERROR = 2, 22 | NO_FUNC_ERROR = 3, 23 | PARSE_FUNC_ERROR = 4 24 | }; 25 | 26 | struct FuncCallInfo { 27 | std::string _func_name; 28 | std::vector _func_param_ret; 29 | 30 | cppnet::Handle _socket; 31 | }; 32 | 33 | 34 | typedef std::function(std::vector)> CommonFunc; 35 | #endif 36 | -------------------------------------------------------------------------------- /test/rpc/func_thread.cpp: -------------------------------------------------------------------------------- 1 | #include "func_thread.h" 2 | #include "info_router.h" 3 | 4 | FuncThread::FuncThread(std::shared_ptr& router): 5 | _func_router(router) { 6 | } 7 | 8 | FuncThread::~FuncThread() { 9 | } 10 | 11 | void FuncThread::Run() { 12 | while (!_stop) { 13 | auto t = Pop(); 14 | if (t) { 15 | if (CallFunc(t->_func_name, t->_func_param_ret)){ 16 | _func_router->PushRet(t); 17 | } 18 | 19 | } else { 20 | continue; 21 | } 22 | } 23 | } 24 | 25 | void FuncThread::Stop() { 26 | _stop = true; 27 | Push(nullptr); 28 | } 29 | 30 | bool FuncThread::RegisterFunc(const std::string& name, const CommonFunc& func) { 31 | std::unique_lock lock(_mutex); 32 | if (_func_map.count(name)) { 33 | return false; 34 | } 35 | _func_map[name] = func; 36 | return true; 37 | } 38 | 39 | bool FuncThread::RemoveFunc(const std::string& name) { 40 | std::unique_lock lock(_mutex); 41 | auto iter = _func_map.find(name); 42 | if (iter != _func_map.end()) { 43 | _func_map.erase(iter); 44 | return true; 45 | } 46 | return false; 47 | } 48 | 49 | CommonFunc FuncThread::FindFunc(const std::string& name) { 50 | std::unique_lock lock(_mutex); 51 | auto iter = _func_map.find(name); 52 | if (iter != _func_map.end()) { 53 | return iter->second; 54 | } 55 | return nullptr; 56 | } 57 | 58 | bool FuncThread::CallFunc(const std::string& name, std::vector& param_ret) { 59 | auto iter = _func_map.find(name); 60 | if (iter == _func_map.end()) { 61 | return false; 62 | } 63 | 64 | //client responsible for parameter verification 65 | //so can direct call here 66 | param_ret = iter->second(param_ret); 67 | return true; 68 | } 69 | 70 | -------------------------------------------------------------------------------- /test/rpc/func_thread.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_RPC_CFUNCTHREAD_HEADER 2 | #define TEST_RPC_CFUNCTHREAD_HEADER 3 | 4 | #include 5 | #include "common_struct.h" 6 | #include "common/util/any.h" 7 | #include "common/thread/thread_with_queue.h" 8 | 9 | class FuncManager; 10 | class InfoRouter; 11 | class FuncThread : public cppnet::ThreadWithQueue { 12 | public: 13 | FuncThread(std::shared_ptr& router); 14 | ~FuncThread(); 15 | 16 | //main loop 17 | virtual void Run(); 18 | 19 | virtual void Stop(); 20 | //register function to map 21 | bool RegisterFunc(const std::string& name, const CommonFunc& func); 22 | bool RemoveFunc(const std::string& name); 23 | 24 | //find function by name 25 | CommonFunc FindFunc(const std::string& name); 26 | //call function by name. Thread unsafety. param_ret use in/out 27 | bool CallFunc(const std::string& name, std::vector& param_ret); 28 | 29 | private: 30 | 31 | std::mutex _mutex; 32 | std::map _func_map; 33 | std::shared_ptr _func_router; 34 | }; 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /test/rpc/info_router.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "info_router.h" 3 | #include "func_thread.h" 4 | 5 | InfoRouter::InfoRouter() { 6 | } 7 | 8 | InfoRouter::~InfoRouter() { 9 | } 10 | 11 | void InfoRouter::AddThread(std::shared_ptr& thread) { 12 | _func_thread_vec.push_back(thread); 13 | thread->Start(); 14 | } 15 | 16 | void InfoRouter::StopAllThread() { 17 | for (int i = 0; i < (int)_func_thread_vec.size(); i++) { 18 | _func_thread_vec[i]->Stop(); 19 | _func_thread_vec[i]->Join(); 20 | } 21 | } 22 | 23 | void InfoRouter::PushTask(FuncCallInfo* info) { 24 | { 25 | std::unique_lock lock(_mutex); 26 | _func_thread_vec[_curent_index]->Push(info); 27 | } 28 | _curent_index++; 29 | if (_curent_index > _func_thread_vec.size() - 1) { 30 | _curent_index = _curent_index % (int)_func_thread_vec.size(); 31 | } 32 | } 33 | 34 | void InfoRouter::PushRet(FuncCallInfo* info) { 35 | _out_task_list.Push(info); 36 | } 37 | 38 | FuncCallInfo* InfoRouter::GetRet() { 39 | return _out_task_list.Pop(); 40 | } 41 | 42 | void InfoRouter::RegisterFunc(const std::string& name, const CommonFunc& func) { 43 | std::unique_lock lock(_mutex); 44 | for (int i = 0; i < (int)_func_thread_vec.size(); i++) { 45 | _func_thread_vec[i]->RegisterFunc(name, func); 46 | } 47 | } 48 | 49 | void InfoRouter::RemoveFunc(const std::string& name) { 50 | std::unique_lock lock(_mutex); 51 | for (int i = 0; i < (int)_func_thread_vec.size(); i++) { 52 | _func_thread_vec[i]->RemoveFunc(name); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /test/rpc/info_router.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_RPC_CINFOROUTER_HEADER 2 | #define TEST_RPC_CINFOROUTER_HEADER 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "common_struct.h" 11 | #include "common/structure/thread_safe_block_queue.h" 12 | 13 | struct FuncCallInfo; 14 | class FuncThread; 15 | class InfoRouter { 16 | public: 17 | InfoRouter(); 18 | ~InfoRouter(); 19 | //add a funcmanager thread. 20 | void AddThread(std::shared_ptr& thread); 21 | void StopAllThread(); 22 | //push call info 23 | void PushTask(FuncCallInfo* info); 24 | //push call function return value 25 | void PushRet(FuncCallInfo* info); 26 | //may block the thread 27 | FuncCallInfo* GetRet(); 28 | 29 | void RegisterFunc(const std::string& name, const CommonFunc& func); 30 | void RemoveFunc(const std::string& name); 31 | 32 | private: 33 | cppnet::ThreadSafeBlockQueue _out_task_list; 34 | 35 | std::atomic_int _curent_index; 36 | std::mutex _mutex; 37 | std::vector> _func_thread_vec; 38 | }; 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /test/rpc/makefile: -------------------------------------------------------------------------------- 1 | SRCS = func_thread.cpp info_router.cpp parse_package.cpp rpc_client.cpp rpc_server.cpp 2 | 3 | OBJS = $(patsubst %.cpp, %.o, $(SRCS)) 4 | CLI = client.cpp 5 | SER = server.cpp 6 | 7 | 8 | CC = g++ 9 | 10 | INCLUDES = -I../../ 11 | 12 | #debug 13 | #CCFLAGS = -lpthread -fPIC -m64 -g -pg -std=c++11 -lstdc++ -pipe 14 | 15 | CCFLAGS = -lpthread -fPIC -m64 -O2 -std=c++11 -lstdc++ -pipe -march=corei7 16 | 17 | TARGET = ../../libcppnet.a 18 | SERBIN = serrpc 19 | CLIBIN = clirpc 20 | 21 | all: $(SERBIN) $(CLIBIN) 22 | 23 | $(SERBIN):$(OBJS) $(TARGET) $(SER) 24 | $(CC) $^ -o $@ $(TARGET) $(CCFLAGS) $(INCLUDES) 25 | 26 | $(CLIBIN):$(OBJS) $(TARGET) $(CLI) 27 | $(CC) $^ -o $@ $(TARGET) $(CCFLAGS) $(INCLUDES) 28 | 29 | %.o : %.cpp 30 | $(CC) -c $< -o $@ $(CCFLAGS) $(INCLUDES) 31 | 32 | clean: 33 | rm -rf $(OBJS) $(SERBIN) $(CLIBIN) -------------------------------------------------------------------------------- /test/rpc/rpc_client.cpp: -------------------------------------------------------------------------------- 1 | #include "rpc_client.h" 2 | #include "info_router.h" 3 | #include "func_thread.h" 4 | #include "parse_package.h" 5 | 6 | #include "common/log/log.h" 7 | 8 | RPCClient::RPCClient() : _connected(false){ 9 | } 10 | 11 | 12 | RPCClient::~RPCClient() { 13 | } 14 | 15 | //start work 16 | void RPCClient::Start(short port, std::string ip) { 17 | _ip = ip; 18 | _port = port; 19 | _net.Init(1); 20 | 21 | _net.SetConnectionCallback(std::bind(&RPCClient::_DoConnect, this, std::placeholders::_1, std::placeholders::_2)); 22 | _net.SetWriteCallback(std::bind(&RPCClient::_DoWrite, this, std::placeholders::_1, std::placeholders::_2)); 23 | _net.SetReadCallback(std::bind(&RPCClient::_DoRead, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 24 | _net.SetDisconnectionCallback(std::bind(&RPCClient::_DoDisConnect, this, std::placeholders::_1, std::placeholders::_2)); 25 | 26 | _net.Connection(ip, port); 27 | 28 | } 29 | 30 | void RPCClient::SetCallBack(const std::string& func_name, Call_back& func) { 31 | _func_call_map[func_name] = func; 32 | } 33 | 34 | void RPCClient::_DoRead(cppnet::Handle handle, cppnet::BufferPtr data, 35 | uint32_t len) { 36 | char recv_buf[8192] = { 0 }; 37 | uint32_t get_len = 8192; 38 | uint32_t need_len = 0; 39 | uint32_t recv_len = 0; 40 | for (;;) { 41 | get_len = data->ReadUntil(recv_buf, 8192, "\r\n\r\n", strlen("\r\n\r\n"), need_len); 42 | if (get_len == 0) { 43 | break; 44 | } 45 | std::vector vec; 46 | int type = 0; 47 | std::string name; 48 | int code = NO_ERROR; 49 | if (!_parse_package->ParseType(recv_buf, get_len, type)) { 50 | if (_func_call_map.count(name)) { 51 | _func_call_map[name](PARAM_TYPE_ERROR, vec); 52 | } 53 | break; 54 | } 55 | if (type & FUNCTION_RET) { 56 | if (!_parse_package->ParseFuncRet(recv_buf + 2, get_len - 2, code, name, _func_map, vec)) { 57 | if (_func_call_map.count(name)) { 58 | _func_call_map[name](PARSE_FUNC_ERROR, vec); 59 | } 60 | break; 61 | } 62 | if (_func_call_map.count(name)) { 63 | _func_call_map[name](code, vec); 64 | } 65 | 66 | } else if (type & FUNCTION_INFO) { 67 | if (!_parse_package->ParseFuncList(recv_buf + 2, get_len - 2, _func_map)) { 68 | if (_func_call_map.count(name)) { 69 | _func_call_map[name](PARSE_FUNC_ERROR, vec); 70 | } 71 | break; 72 | 73 | } else { 74 | if (_func_call_map.count(name)) { 75 | _func_call_map[name](PARAM_TYPE_ERROR, vec); 76 | } 77 | break; 78 | } 79 | } 80 | } 81 | } 82 | 83 | void RPCClient::_DoWrite(cppnet::Handle handle, uint32_t len) { 84 | // do nothing 85 | } 86 | 87 | void RPCClient::_DoConnect(cppnet::Handle handle, uint32_t err) { 88 | if (err != cppnet::CEC_SUCCESS) { 89 | cppnet::LOG_ERROR("connect failed! err : %d", err); 90 | return; 91 | } 92 | _socket = handle; 93 | _connected = true; 94 | handle->Write("\r\n\r\n", strlen("\r\n\r\n")); 95 | } 96 | 97 | void RPCClient::_DoDisConnect(cppnet::Handle handle, uint32_t err) { 98 | if (err != cppnet::CEC_CLOSED) { 99 | _net.Connection(_ip, _port); 100 | } 101 | cppnet::LOG_ERROR("disconnect with server!"); 102 | } 103 | -------------------------------------------------------------------------------- /test/rpc/rpc_client.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_RPC_RPCCLIENT_HEADER 2 | #define TEST_RPC_RPCCLIENT_HEADER 3 | 4 | #include "common_struct.h" 5 | #include "parse_package.h" 6 | #include "include/cppnet.h" 7 | #include "include/cppnet_socket.h" 8 | #include "common/util/any.h" 9 | 10 | typedef std::function& ret)> Call_back; 11 | 12 | class InfoRouter; 13 | class ParsePackage; 14 | class RPCClient { 15 | public: 16 | RPCClient(); 17 | ~RPCClient(); 18 | //start work 19 | void Start(short port, std::string ip); 20 | //set call back when rpc server response called; 21 | void SetCallBack(const std::string& func_name, Call_back& func); 22 | template 23 | bool CallFunc(const std::string& func_name, Args&&...args); 24 | public: 25 | void _DoRead(cppnet::Handle handle, cppnet::BufferPtr data, 26 | uint32_t len); 27 | void _DoWrite(cppnet::Handle handle, uint32_t len); 28 | void _DoConnect(cppnet::Handle handle, uint32_t err); 29 | void _DoDisConnect(cppnet::Handle handle, uint32_t err); 30 | 31 | private: 32 | bool _connected; 33 | std::shared_ptr _info_router; 34 | std::shared_ptr _parse_package; 35 | 36 | cppnet::CppNet _net; 37 | std::string _ip; 38 | int _port; 39 | cppnet::Handle _socket; 40 | std::map _func_call_map; 41 | std::map _func_map; 42 | }; 43 | 44 | template 45 | bool RPCClient::CallFunc(const std::string& func_name, Args&&...args) { 46 | if (!_func_map.count(func_name)) { 47 | return false; 48 | } 49 | if (!_func_call_map.count(func_name)) { 50 | return false; 51 | } 52 | if (!_connected) { 53 | return false; 54 | } 55 | 56 | std::vector vec; 57 | _parse_package->ParseParam(vec, std::forward(args)...); 58 | 59 | char buf[8192] = { 0 }; 60 | int len = 8192; 61 | if (!_parse_package->PackageFuncCall(buf, len, func_name, _func_map, vec)) { 62 | return false; 63 | } 64 | _socket->Write(buf, len); 65 | return true; 66 | } 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /test/rpc/rpc_client.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/rpc/rpc_server.h: -------------------------------------------------------------------------------- 1 | #ifndef TEST_RPC_RPCSERVER_HEADER 2 | #define TEST_RPC_RPCSERVER_HEADER 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "common_struct.h" 10 | #include "include/cppnet.h" 11 | #include "common/alloter/alloter_interface.h" 12 | 13 | class InfoRouter; 14 | class ParsePackage; 15 | class RPCServer { 16 | public: 17 | RPCServer(); 18 | ~RPCServer(); 19 | //create func thread and add to router 20 | void Init(int thread); 21 | //Destroy func thread 22 | void Destroy(); 23 | //start work 24 | void Start(short port, std::string ip); 25 | 26 | bool RegisterFunc(std::string name, std::string func_str, const CommonFunc& func); 27 | bool RemoveFunc(std::string name); 28 | 29 | private: 30 | void _DoRead(cppnet::Handle handle, cppnet::BufferPtr data, 31 | uint32_t len); 32 | void _DoWrite(cppnet::Handle handle, uint32_t len); 33 | void _DoAccept(cppnet::Handle handle, uint32_t err); 34 | void _PackageAndSend(cppnet::Handle handle, FuncCallInfo* info, int code); 35 | 36 | private: 37 | std::shared_ptr _info_router; 38 | std::shared_ptr _parse_package; 39 | 40 | cppnet::CppNet _net; 41 | cppnet::AlloterWrap _pool; 42 | std::atomic_bool _need_mutex; 43 | std::mutex _mutex; 44 | std::map _func_map; 45 | }; 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /test/rpc/rpc_server.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/rpc/server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "rpc_server.h" 3 | #include "common/util/any.h" 4 | 5 | std::vector Add1(std::vector param) { 6 | int res = cppnet::any_cast(param[0]) + cppnet::any_cast(param[1]); 7 | std::vector ret; 8 | ret.push_back(cppnet::Any(res)); 9 | return ret; 10 | } 11 | 12 | int main() { 13 | RPCServer server; 14 | server.Init(4); 15 | server.RegisterFunc("Add1", "i(ii)", Add1); 16 | server.Start(8951, "0.0.0.0"); 17 | } 18 | -------------------------------------------------------------------------------- /test/sendfile/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | project(sendfileserver) 4 | add_executable(${PROJECT_NAME} send_file_server.cpp md5.cpp) 5 | 6 | if(WIN32) 7 | target_link_libraries(${PROJECT_NAME} cppnet) 8 | target_link_libraries(${PROJECT_NAME} ws2_32) 9 | else() 10 | target_link_libraries(${PROJECT_NAME} cppnet) 11 | target_link_libraries(${PROJECT_NAME} pthread) 12 | endif() 13 | 14 | 15 | 16 | project(sendfileclient) 17 | add_executable(${PROJECT_NAME} send_file_client.cpp md5.cpp) 18 | 19 | if(WIN32) 20 | target_link_libraries(${PROJECT_NAME} cppnet) 21 | target_link_libraries(${PROJECT_NAME} ws2_32) 22 | else() 23 | target_link_libraries(${PROJECT_NAME} cppnet) 24 | target_link_libraries(${PROJECT_NAME} pthread) 25 | endif() 26 | 27 | -------------------------------------------------------------------------------- /test/sendfile/common.h: -------------------------------------------------------------------------------- 1 | #include // for memset 2 | 3 | enum STATUS { 4 | hello, 5 | sending 6 | }; 7 | 8 | struct FileHeader { 9 | int _length; 10 | char _name[64]; 11 | char _md5[128]; 12 | 13 | FileHeader() { 14 | memset(_name, 0, 64); 15 | memset(_md5, 0, 128); 16 | } 17 | }; 18 | 19 | static const int __header_len = sizeof(FileHeader); 20 | static const int __read_len = 4096; -------------------------------------------------------------------------------- /test/sendfile/makefile: -------------------------------------------------------------------------------- 1 | SER = send_file_server.cpp md5.cpp 2 | CLI = send_file_client.cpp md5.cpp 3 | 4 | CC = g++ 5 | 6 | INCLUDES = -I../../ 7 | 8 | #debug -pg 9 | CCFLAGS = -lpthread -fPIC -m64 -g -std=c++11 -lstdc++ -pipe 10 | 11 | #CCFLAGS = -lpthread -fPIC -m64 -O2 -std=c++11 -lstdc++ -pipe -march=corei7 12 | 13 | TARGET = ../../libcppnet.a 14 | SERBIN = sendfileserver 15 | CLIBIN = sendfileclient 16 | 17 | all:$(SERBIN) $(CLIBIN) 18 | 19 | $(SERBIN):$(SER) $(TARGET) 20 | $(CC) $(SER) -o $@ $(TARGET) $(CCFLAGS) $(INCLUDES) 21 | 22 | $(CLIBIN):$(CLI) $(TARGET) 23 | $(CC) $(CLI) -o $@ $(TARGET) $(CCFLAGS) $(INCLUDES) 24 | 25 | clean: 26 | rm -rf $(SERBIN) $(CLIBIN) -------------------------------------------------------------------------------- /test/sendfile/md5.h: -------------------------------------------------------------------------------- 1 | #ifndef MD5_H 2 | #define MD5_H 3 | 4 | #include 5 | 6 | #define READ_DATA_SIZE 1024 7 | #define MD5_SIZE 16 8 | #define MD5_STR_LEN (MD5_SIZE * 2) 9 | 10 | typedef struct 11 | { 12 | unsigned int count[2]; 13 | unsigned int state[4]; 14 | unsigned char buffer[64]; 15 | } MD5_CTX; 16 | 17 | 18 | #define F(x,y,z) ((x & y) | (~x & z)) 19 | #define G(x,y,z) ((x & z) | (y & ~z)) 20 | #define H(x,y,z) (x^y^z) 21 | #define I(x,y,z) (y ^ (x | ~z)) 22 | #define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n))) 23 | 24 | #define FF(a,b,c,d,x,s,ac) \ 25 | { \ 26 | a += F(b,c,d) + x + ac; \ 27 | a = ROTATE_LEFT(a,s); \ 28 | a += b; \ 29 | } 30 | #define GG(a,b,c,d,x,s,ac) \ 31 | { \ 32 | a += G(b,c,d) + x + ac; \ 33 | a = ROTATE_LEFT(a,s); \ 34 | a += b; \ 35 | } 36 | #define HH(a,b,c,d,x,s,ac) \ 37 | { \ 38 | a += H(b,c,d) + x + ac; \ 39 | a = ROTATE_LEFT(a,s); \ 40 | a += b; \ 41 | } 42 | #define II(a,b,c,d,x,s,ac) \ 43 | { \ 44 | a += I(b,c,d) + x + ac; \ 45 | a = ROTATE_LEFT(a,s); \ 46 | a += b; \ 47 | } 48 | void MD5Init(MD5_CTX *context); 49 | void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputlen); 50 | void MD5Final(MD5_CTX *context, unsigned char digest[16]); 51 | void MD5Transform(unsigned int state[4], unsigned char block[64]); 52 | void MD5Encode(unsigned char *output, unsigned int *input, unsigned int len); 53 | void MD5Decode(unsigned int *output, unsigned char *input, unsigned int len); 54 | int Compute_file_md5(const char *file_path, char *md5_str); 55 | 56 | #endif 57 | 58 | -------------------------------------------------------------------------------- /test/simple/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(simpleserver) 2 | add_executable(${PROJECT_NAME} cppnet_server.cpp) 3 | 4 | if(WIN32) 5 | target_link_libraries(${PROJECT_NAME} cppnet) 6 | target_link_libraries(${PROJECT_NAME} ws2_32) 7 | else() 8 | target_link_libraries(${PROJECT_NAME} cppnet) 9 | target_link_libraries(${PROJECT_NAME} pthread) 10 | endif() 11 | 12 | 13 | project(simpleclient) 14 | add_executable(${PROJECT_NAME} cppnet_client.cpp) 15 | 16 | if(WIN32) 17 | target_link_libraries(${PROJECT_NAME} cppnet) 18 | target_link_libraries(${PROJECT_NAME} ws2_32) 19 | else() 20 | target_link_libraries(${PROJECT_NAME} cppnet) 21 | target_link_libraries(${PROJECT_NAME} pthread) 22 | endif() 23 | 24 | -------------------------------------------------------------------------------- /test/simple/client.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /test/simple/cppnet_client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "include/cppnet.h" 6 | #include "common/util/time.h" 7 | 8 | using namespace cppnet; 9 | 10 | int msg_index = 0; 11 | std::string msg = "test msg => "; 12 | 13 | std::string GetMsg() { 14 | msg_index++; 15 | return (msg + std::to_string(msg_index)); 16 | } 17 | 18 | void WriteFunc(Handle handle, uint32_t len) { 19 | std::cout << " [WriteFunc] length : " << len << std::endl; 20 | } 21 | 22 | 23 | void ReadFunc(Handle handle, std::shared_ptr data, uint32_t len) { 24 | std::cout << " [ReadFunc]" << std::endl; 25 | 26 | char buf[1024] = {0}; 27 | data->Read(buf, 1024); 28 | std::cout << "recv :"<< buf << std::endl; 29 | data->Clear(); 30 | 31 | std::cout << " Thread ID : " << std::this_thread::get_id() << std::endl; 32 | std::cout << " Read size : " << len << std::endl << std::endl; 33 | 34 | Sleep(1000); 35 | 36 | if (msg_index >= 5) { 37 | handle->Close(); 38 | return; 39 | } 40 | 41 | auto msg = GetMsg(); 42 | handle->Write(msg.c_str(), (uint32_t)msg.length()); 43 | } 44 | 45 | void ConnectFunc(Handle handle, uint32_t err) { 46 | if (err == CEC_SUCCESS) { 47 | std::string ip; 48 | uint16_t port; 49 | handle->GetAddress(ip, port); 50 | std::cout << " [ConnectFunc] : ip : " << ip << "port : " << port << std::endl; 51 | auto msg = GetMsg(); 52 | handle->Write(msg.c_str(), (uint32_t)msg.length()); 53 | 54 | } else { 55 | std::cout << " [ConnectFunc] some thing error : " << err << std::endl; 56 | } 57 | } 58 | 59 | void DisConnectionFunc(Handle handle, uint32_t err) { 60 | std::cout << " [DisConnectionFunc] : " << err << std::endl; 61 | } 62 | 63 | int main() { 64 | 65 | cppnet::CppNet net; 66 | net.Init(1); 67 | net.SetConnectionCallback(ConnectFunc); 68 | net.SetWriteCallback(WriteFunc); 69 | net.SetReadCallback(ReadFunc); 70 | net.SetDisconnectionCallback(DisConnectionFunc); 71 | 72 | net.Connection("127.0.0.1", 8999); 73 | 74 | Sleep(8000); 75 | } -------------------------------------------------------------------------------- /test/simple/cppnet_server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "include/cppnet.h" 7 | #include "common/util/time.h" 8 | 9 | using namespace cppnet; 10 | 11 | int msg_index = 0; 12 | std::string msg = "test msg => "; 13 | 14 | std::string GetMsg() { 15 | msg_index++; 16 | return (msg + std::to_string(msg_index)); 17 | } 18 | 19 | void WriteFunc(Handle handle, uint32_t len) { 20 | std::cout << "[WriteFunc] length : " << len << std::endl; 21 | } 22 | 23 | void ReadFunc(Handle handle, std::shared_ptr data, uint32_t len) { 24 | std::cout << "[ReadFunc]" << std::endl; 25 | 26 | char buf[1024] = {0}; 27 | data->Read(buf, 1024); 28 | std::cout << "recv :"<< buf << std::endl; 29 | data->Clear(); 30 | 31 | std::cout << "Thread ID : " << std::this_thread::get_id() << std::endl; 32 | std::cout << "Read size : " << len << std::endl << std::endl; 33 | 34 | auto msg = GetMsg(); 35 | handle->Write(msg.c_str(), (uint32_t)msg.length()); 36 | } 37 | 38 | void ConnectFunc(Handle handle, uint32_t err) { 39 | if (err == CEC_SUCCESS) { 40 | std::string ip; 41 | uint16_t port; 42 | handle->GetAddress(ip, port); 43 | std::cout << "[ConnectFunc] : ip: " << ip << "port: " << port << "listen port: " << handle->GetListenPort() << std::endl; 44 | 45 | auto msg = GetMsg(); 46 | handle->Write(msg.c_str(), (uint32_t)msg.length()); 47 | 48 | } else { 49 | std::cout << "[ConnectFunc] some thing error : " << err << std::endl; 50 | } 51 | } 52 | 53 | void DisConnectionFunc(Handle handle, uint32_t err) { 54 | std::cout << "[DisConnectionFunc] : " << err << std::endl; 55 | } 56 | 57 | int main() { 58 | 59 | cppnet::CppNet net; 60 | net.Init(1); 61 | 62 | net.SetAcceptCallback(ConnectFunc); 63 | net.SetWriteCallback(WriteFunc); 64 | net.SetReadCallback(ReadFunc); 65 | net.SetDisconnectionCallback(DisConnectionFunc); 66 | 67 | net.ListenAndAccept("0.0.0.0", 8999); 68 | 69 | net.Join(); 70 | } -------------------------------------------------------------------------------- /test/simple/makefile: -------------------------------------------------------------------------------- 1 | SER = cppnet_server.cpp 2 | CLI = cppnet_client.cpp 3 | 4 | CC = g++ 5 | 6 | INCLUDES = -I../../ 7 | 8 | #debug -pg 9 | CCFLAGS = -lpthread -fPIC -m64 -g -std=c++11 -lstdc++ -pipe 10 | 11 | #CCFLAGS = -lpthread -fPIC -m64 -O2 -std=c++11 -lstdc++ -pipe -march=corei7 12 | 13 | TARGET = ../../libcppnet.a 14 | SERBIN = server 15 | CLIBIN = client 16 | 17 | all:$(SERBIN) $(CLIBIN) 18 | 19 | $(SERBIN):$(SER) $(TARGET) 20 | $(CC) $(SER) -o $@ $(TARGET) $(CCFLAGS) $(INCLUDES) 21 | 22 | $(CLIBIN):$(CLI) $(TARGET) 23 | $(CC) $(CLI) -o $@ $(TARGET) $(CCFLAGS) $(INCLUDES) 24 | 25 | clean: 26 | rm -rf $(SERBIN) $(CLIBIN) 27 | -------------------------------------------------------------------------------- /test/simple/server.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | --------------------------------------------------------------------------------