├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── README.md ├── eddyserver ├── CMakeLists.txt ├── eddyserver.h └── eddyserver │ ├── id_generator.h │ ├── io_service_thread.cpp │ ├── io_service_thread.h │ ├── io_service_thread_manager.cpp │ ├── io_service_thread_manager.h │ ├── message_filter.cpp │ ├── message_filter.h │ ├── net_message.cpp │ ├── net_message.h │ ├── tcp_client.cpp │ ├── tcp_client.h │ ├── tcp_server.cpp │ ├── tcp_server.h │ ├── tcp_session.cpp │ ├── tcp_session.h │ ├── tcp_session_handler.cpp │ ├── tcp_session_handler.h │ ├── tcp_session_queue.cpp │ ├── tcp_session_queue.h │ ├── thread_pool.cpp │ ├── thread_pool.h │ └── types.h └── examples └── echo ├── CMakeLists.txt └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | build 3 | .vscode -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "asio"] 2 | path = asio 3 | url = https://github.com/chriskohlhoff/asio.git 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 最低版本 2 | cmake_minimum_required(VERSION 2.8) 3 | 4 | # 工程名称 5 | project(eddyserver C CXX) 6 | 7 | # 编译类型 8 | if(NOT CMAKE_BUILD_TYPE) 9 | set(CMAKE_BUILD_TYPE "Release") 10 | endif() 11 | 12 | # 编译选项 13 | if (LINUX) 14 | set(CMAKE_CXX_FLAGS 15 | -g 16 | -Wall 17 | -Wextra 18 | -Werror 19 | -Wconversion 20 | -Wno-unused-parameter 21 | -Wold-style-cast 22 | -Woverloaded-virtual 23 | -Wpointer-arith 24 | -Wshadow 25 | -Wwrite-strings 26 | -std=c++1y 27 | ) 28 | endif() 29 | 30 | # 输出目录 31 | set(BINARY_OUTPUT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/bin) 32 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BINARY_OUTPUT_DIR}) 33 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${BINARY_OUTPUT_DIR}) 34 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${BINARY_OUTPUT_DIR}) 35 | foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) 36 | string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG) 37 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${BINARY_OUTPUT_DIR}) 38 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${BINARY_OUTPUT_DIR}) 39 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${BINARY_OUTPUT_DIR}) 40 | endforeach(OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES) 41 | add_definitions(-DBINARY_OUTPUT_DIR="${BINARY_OUTPUT_DIR}") 42 | 43 | # 开启分组 44 | SET_PROPERTY(GLOBAL PROPERTY USE_FOLDERS ON) 45 | 46 | # 配置asio 47 | if (WIN32) 48 | add_definitions(-DASIO_MSVC) 49 | endif() 50 | add_definitions(-DASIO_STANDALONE) 51 | set(ASIO_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/asio/asio/include) 52 | 53 | # 配置eddyserver 54 | set(EDDYSERVER_LIBRARY eddyserver) 55 | set(EDDYSERVER_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/eddyserver) 56 | 57 | # 编译eddyserver 58 | add_subdirectory(eddyserver) 59 | 60 | # 编译示例代码 61 | add_subdirectory(examples/echo) 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 基于C++14和ASIO实现高并发TCP网络框架,基于[https://code.google.com/archive/p/eddyserver/](https://code.google.com/archive/p/eddyserver/)进行改进。 3 | 4 | ## 特点 5 | * 简单易用 6 | * IO多线程处理,逻辑主线程处理 7 | * 自动拆包和组包,可自定义拆包和组包策略 8 | 9 | ## 使用 10 | ``` 11 | git clone https://github.com/zhangpanyi/eddyserver 12 | git submodule update --init --recursive 13 | mkdir build && cd build 14 | cmake .. 15 | ``` 16 | 17 | ## 示例代码 18 | ```c++ 19 | #include 20 | #include 21 | 22 | class SessionHandle : public eddyserver::TCPSessionHandler 23 | { 24 | public: 25 | // 连接事件 26 | virtual void on_connected() override 27 | { 28 | std::cout << "on_connected" << std::endl; 29 | } 30 | 31 | // 接收消息事件 32 | virtual void on_message(eddyserver::NetMessage &message) override 33 | { 34 | std::cout << "on_message" << std::endl; 35 | send(message); 36 | } 37 | 38 | // 关闭事件 39 | virtual void on_closed() override 40 | { 41 | std::cout << "on_closed" << std::endl; 42 | } 43 | }; 44 | 45 | eddyserver::MessageFilterPointer CreateMessageFilter() 46 | { 47 | return std::make_shared(); 48 | } 49 | 50 | eddyserver::SessionHandlePointer CreateSessionHandler() 51 | { 52 | return std::make_shared(); 53 | } 54 | 55 | int main(int argc, char *argv[]) 56 | { 57 | eddyserver::IOServiceThreadManager io(4); 58 | asio::ip::tcp::endpoint ep(asio::ip::address_v4::from_string("127.0.0.1"), 4400); 59 | eddyserver::TCPServer server(ep, io, CreateSessionHandler, CreateMessageFilter); 60 | io.run(); 61 | 62 | return 0; 63 | } 64 | ``` 65 | -------------------------------------------------------------------------------- /eddyserver/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 工程名称 2 | set(CURRENT_PROJECT_NAME eddyserver) 3 | 4 | # 添加编译列表 5 | set(CURRENT_PROJECT_SRC_LISTS 6 | eddyserver/thread_pool.cpp 7 | eddyserver/net_message.cpp 8 | eddyserver/io_service_thread.cpp 9 | eddyserver/io_service_thread_manager.cpp 10 | eddyserver/message_filter.cpp 11 | eddyserver/tcp_client.cpp 12 | eddyserver/tcp_server.cpp 13 | eddyserver/tcp_session.cpp 14 | eddyserver/tcp_session_handler.cpp 15 | eddyserver/tcp_session_queue.cpp 16 | ) 17 | 18 | # 包含目录 19 | include_directories( 20 | ${ASIO_INCLUDE_DIRS} 21 | ) 22 | 23 | # 链接目录 24 | link_directories( 25 | ${BINARY_OUTPUT_DIR} 26 | ) 27 | 28 | # 配置生成库 29 | if (WIN32) 30 | add_library(${CURRENT_PROJECT_NAME} STATIC 31 | ${CURRENT_PROJECT_SRC_LISTS} 32 | ) 33 | else() 34 | add_library(${CURRENT_PROJECT_NAME} SHARED 35 | ${CURRENT_PROJECT_SRC_LISTS} 36 | ) 37 | endif() 38 | 39 | set_target_properties(${CURRENT_PROJECT_NAME} 40 | PROPERTIES 41 | OUTPUT_NAME ${EDDYSERVER_LIBRARY} 42 | ARCHIVE_OUTPUT_DIRECTORY ${BINARY_OUTPUT_DIR} 43 | LIBRARY_OUTPUT_DIRECTORY ${BINARY_OUTPUT_DIR} 44 | ) 45 | -------------------------------------------------------------------------------- /eddyserver/eddyserver.h: -------------------------------------------------------------------------------- 1 | #ifndef __EDDYSERVER_H__ 2 | #define __EDDYSERVER_H__ 3 | 4 | namespace eddyserver 5 | { 6 | class TCPClient; 7 | class TCPServer; 8 | class NetMessage; 9 | class MessageFilter; 10 | class IOServiceThread; 11 | class TCPSessionHandler; 12 | class IOServiceThreadManager; 13 | class MessageFilterInterface; 14 | } 15 | 16 | #include "eddyserver/tcp_client.h" 17 | #include "eddyserver/tcp_server.h" 18 | #include "eddyserver/net_message.h" 19 | #include "eddyserver/id_generator.h" 20 | #include "eddyserver/message_filter.h" 21 | #include "eddyserver/tcp_session_handler.h" 22 | #include "eddyserver/io_service_thread_manager.h" 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /eddyserver/eddyserver/id_generator.h: -------------------------------------------------------------------------------- 1 | #ifndef __ID_GENERATOR_H__ 2 | #define __ID_GENERATOR_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace eddyserver 9 | { 10 | template 11 | class IDGenerator final 12 | { 13 | static_assert(std::numeric_limits::is_integer, ""); 14 | 15 | public: 16 | IDGenerator(T min_id = (std::numeric_limits::min()), T max_id = (std::numeric_limits::max()), size_t threshold = 4096) 17 | : min_(min_id) 18 | , max_(max_id) 19 | , next_(min_id) 20 | , threshold_(threshold) 21 | { 22 | assert(min_id <= max_id); 23 | } 24 | 25 | bool get(T &result) 26 | { 27 | if (pools_.size() >= threshold_) 28 | { 29 | result = *pools_.begin(); 30 | pools_.erase(pools_.begin()); 31 | return true; 32 | } 33 | 34 | if (next_ <= max_) 35 | { 36 | result = next_; 37 | ++next_; 38 | return true; 39 | } 40 | return false; 41 | } 42 | 43 | void put(T id) 44 | { 45 | auto found = pools_.find(id); 46 | assert(found == pools_.end()); 47 | if (found == pools_.end()) 48 | { 49 | pools_.insert(id); 50 | } 51 | } 52 | 53 | private: 54 | const T min_; 55 | const T max_; 56 | T next_; 57 | const size_t threshold_; 58 | std::unordered_set pools_; 59 | }; 60 | } 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /eddyserver/eddyserver/io_service_thread.cpp: -------------------------------------------------------------------------------- 1 | #include "io_service_thread.h" 2 | #include 3 | #include 4 | #include "tcp_session.h" 5 | #include "io_service_thread_manager.h" 6 | 7 | namespace eddyserver 8 | { 9 | IOServiceThread::IOServiceThread(IOThreadID id, IOServiceThreadManager &td_manager) 10 | : td_id_(id) 11 | , timer_(io_service_) 12 | , td_manager_(td_manager) 13 | , wait_handler_(std::bind(&IOServiceThread::check_keep_alive, this, std::placeholders::_1)) 14 | { 15 | } 16 | 17 | // 线程执行函数 18 | void IOServiceThread::run() 19 | { 20 | if (io_work_ == nullptr) 21 | { 22 | io_work_ = std::make_unique(io_service_); 23 | } 24 | 25 | timer_.expires_from_now(std::chrono::seconds(1)); 26 | timer_.async_wait(wait_handler_); 27 | 28 | asio::error_code error_code; 29 | io_service_.run(error_code); 30 | if (error_code) 31 | { 32 | std::cerr << error_code.message() << std::endl; 33 | } 34 | } 35 | 36 | // 合并线程 37 | void IOServiceThread::join() 38 | { 39 | if (thread_ != nullptr) 40 | { 41 | thread_->join(); 42 | } 43 | } 44 | 45 | // 停止线程 46 | void IOServiceThread::stop() 47 | { 48 | if (io_work_ != nullptr) 49 | { 50 | io_work_.reset(); 51 | } 52 | } 53 | 54 | // 运行线程 55 | void IOServiceThread::run_thread() 56 | { 57 | if (thread_ == nullptr) 58 | { 59 | std::function cb = std::bind(&IOServiceThread::run, this); 60 | thread_ = std::make_unique(std::move(cb)); 61 | } 62 | } 63 | 64 | // 检查Session存活 65 | void IOServiceThread::check_keep_alive(asio::error_code error_code) 66 | { 67 | if (error_code) 68 | { 69 | std::cerr << error_code.message() << std::endl; 70 | } 71 | else 72 | { 73 | session_queue_.foreach([=](const SessionPointer &session) 74 | { 75 | if (!session->check_keep_alive()) 76 | { 77 | io_service_.post(std::bind(&TCPSession::close, session)); 78 | } 79 | }); 80 | timer_.expires_from_now(std::chrono::seconds(1)); 81 | timer_.async_wait(wait_handler_); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /eddyserver/eddyserver/io_service_thread.h: -------------------------------------------------------------------------------- 1 | #ifndef __IO_SERVICE_THREAD_H__ 2 | #define __IO_SERVICE_THREAD_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "tcp_session_queue.h" 9 | 10 | namespace eddyserver 11 | { 12 | class IOServiceThreadManager; 13 | 14 | class IOServiceThread final : public std::enable_shared_from_this< IOServiceThread > 15 | { 16 | friend class IOServiceThreadManager; 17 | typedef std::function WaitHandler; 18 | 19 | public: 20 | IOServiceThread(IOThreadID id, IOServiceThreadManager &td_manager); 21 | 22 | public: 23 | /** 24 | * 合并线程 25 | */ 26 | void join(); 27 | 28 | /** 29 | * 停止线程 30 | */ 31 | void stop(); 32 | 33 | /** 34 | * 运行线程 35 | */ 36 | void run_thread(); 37 | 38 | /** 39 | * 投递请求 40 | */ 41 | template 42 | void post(ASIO_MOVE_ARG(CompletionHandler) handler) 43 | { 44 | io_service_.post(handler); 45 | } 46 | 47 | public: 48 | /** 49 | * 获取线程id 50 | */ 51 | IOThreadID get_id() const 52 | { 53 | return td_id_; 54 | } 55 | 56 | /** 57 | * 获取Session队列 58 | * 此线程管辖的所有Session存放在此 59 | */ 60 | TCPSessionQueue& get_session_queue() 61 | { 62 | return session_queue_; 63 | } 64 | 65 | /** 66 | * 获取io_service 67 | */ 68 | asio::io_service& get_io_service() 69 | { 70 | return io_service_; 71 | } 72 | 73 | /** 74 | * 获取线程管理器 75 | */ 76 | IOServiceThreadManager& get_thread_manager() 77 | { 78 | return td_manager_; 79 | } 80 | 81 | private: 82 | /** 83 | * 线程执行函数 84 | */ 85 | void run(); 86 | 87 | /** 88 | * 检查Session存活 89 | */ 90 | void check_keep_alive(asio::error_code error_code); 91 | 92 | private: 93 | IOServiceThread(const IOServiceThread&) = delete; 94 | IOServiceThread& operator= (const IOServiceThread&) = delete; 95 | 96 | private: 97 | const IOThreadID td_id_; 98 | IOServiceThreadManager& td_manager_; 99 | asio::io_service io_service_; 100 | asio::steady_timer timer_; 101 | const WaitHandler wait_handler_; 102 | std::unique_ptr thread_; 103 | std::unique_ptr io_work_; 104 | TCPSessionQueue session_queue_; 105 | }; 106 | } 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /eddyserver/eddyserver/io_service_thread_manager.cpp: -------------------------------------------------------------------------------- 1 | #include "io_service_thread_manager.h" 2 | #include 3 | #include 4 | #include 5 | #include "tcp_session.h" 6 | #include "io_service_thread.h" 7 | #include "tcp_session_handler.h" 8 | 9 | namespace eddyserver 10 | { 11 | static const size_t kMainThreadIndex = 0; 12 | static_assert(kMainThreadIndex == 0, "kMainThreadIndex must be greater than 0"); 13 | 14 | IOServiceThreadManager::IOServiceThreadManager(size_t thread_num) 15 | : id_generator_(1) 16 | { 17 | assert(thread_num > kMainThreadIndex); 18 | if (thread_num == kMainThreadIndex) 19 | { 20 | throw std::runtime_error("thread number can not be less than 1!"); 21 | } 22 | 23 | threads_.resize(thread_num); 24 | thread_load_.resize(thread_num); 25 | for (size_t i = 0; i < threads_.size(); ++i) 26 | { 27 | threads_[i] = std::make_shared(i + 1, *this); 28 | } 29 | } 30 | 31 | IOServiceThreadManager::~IOServiceThreadManager() 32 | { 33 | stop(); 34 | } 35 | 36 | // 运行线程 37 | void IOServiceThreadManager::run() 38 | { 39 | if (threads_.empty()) 40 | { 41 | return; 42 | } 43 | 44 | for (size_t i = 0; i < threads_.size(); ++i) 45 | { 46 | if (i != kMainThreadIndex) 47 | { 48 | threads_[i]->run_thread(); 49 | } 50 | } 51 | threads_[kMainThreadIndex]->run(); 52 | } 53 | 54 | // 停止线程 55 | void IOServiceThreadManager::stop() 56 | { 57 | if (threads_.empty()) 58 | { 59 | return; 60 | } 61 | 62 | for (size_t i = 0; i < threads_.size(); ++i) 63 | { 64 | if (i != kMainThreadIndex) 65 | { 66 | threads_[i]->stop(); 67 | } 68 | } 69 | 70 | for (size_t i = 0; i < threads_.size(); ++i) 71 | { 72 | if (i != kMainThreadIndex) 73 | { 74 | threads_[i]->join(); 75 | } 76 | } 77 | 78 | threads_[kMainThreadIndex]->stop(); 79 | } 80 | 81 | // 获取主线程 82 | ThreadPointer& IOServiceThreadManager::get_main_thread() 83 | { 84 | return threads_[kMainThreadIndex]; 85 | } 86 | 87 | // 获取负载最小的线程 88 | ThreadPointer& IOServiceThreadManager::get_min_load_thread() 89 | { 90 | if (threads_.size() == 1) 91 | { 92 | return threads_[kMainThreadIndex]; 93 | } 94 | 95 | size_t min_load_index = kMainThreadIndex; 96 | size_t min_load_value = std::numeric_limits::max(); 97 | for (size_t i = 0; i < thread_load_.size(); ++i) 98 | { 99 | if (i != kMainThreadIndex && thread_load_[i] < min_load_value) 100 | { 101 | min_load_index = i; 102 | } 103 | } 104 | return threads_[min_load_index]; 105 | } 106 | 107 | // 根据线程id获取线程 108 | ThreadPointer IOServiceThreadManager::get_thread(IOThreadID id) 109 | { 110 | for (size_t i = 0; i < threads_.size(); ++i) 111 | { 112 | if (threads_[i]->get_id() == id) 113 | { 114 | return threads_[i]; 115 | } 116 | } 117 | return ThreadPointer(); 118 | } 119 | 120 | // Session连接 121 | void IOServiceThreadManager::on_session_connected(SessionPointer &session_ptr, SessionHandlePointer &handler_ptr) 122 | { 123 | uint32_t session_id = 0; 124 | if (!id_generator_.get(session_id)) 125 | { 126 | throw std::runtime_error("generator session id fail!"); 127 | } 128 | 129 | handler_ptr->init(session_id, 130 | session_ptr->get_io_thread()->get_id(), 131 | this, 132 | session_ptr->get_socket().remote_endpoint()); 133 | 134 | session_handler_map_.insert(std::make_pair(session_id, handler_ptr)); 135 | session_ptr->get_io_thread()->post(std::bind(&TCPSession::init, session_ptr, session_id)); 136 | handler_ptr->on_connected(); 137 | 138 | IOThreadID tid = handler_ptr->get_thread_id(); 139 | assert(tid > 0 && tid <= thread_load_.size()); 140 | if (tid > 0 && tid <= thread_load_.size()) 141 | { 142 | ++thread_load_[tid - 1]; 143 | } 144 | } 145 | 146 | // Session关闭 147 | void IOServiceThreadManager::on_session_closed(TCPSessionID id) 148 | { 149 | assert(id > 0); 150 | SessionHandlerMap::iterator found = session_handler_map_.find(id); 151 | if (found != session_handler_map_.end()) 152 | { 153 | SessionHandlePointer handler_ptr = found->second; 154 | IOThreadID tid = handler_ptr->get_thread_id(); 155 | if (handler_ptr != nullptr) 156 | { 157 | handler_ptr->on_closed(); 158 | handler_ptr->dispose(); 159 | } 160 | session_handler_map_.erase(found); 161 | 162 | assert(tid > 0 && tid <= thread_load_.size()); 163 | if (tid > 0 && tid <= thread_load_.size()) 164 | { 165 | assert(thread_load_[tid - 1] > 0); 166 | if (thread_load_[tid - 1] > 0) 167 | { 168 | --thread_load_[tid - 1]; 169 | } 170 | } 171 | } 172 | 173 | if (id > 0) 174 | { 175 | id_generator_.put(id); 176 | } 177 | } 178 | 179 | // 获取Session数量 180 | size_t IOServiceThreadManager::get_session_count() const 181 | { 182 | return session_handler_map_.size(); 183 | } 184 | 185 | // 获取Session处理器 186 | SessionHandlePointer IOServiceThreadManager::get_session_handler(TCPSessionID id) const 187 | { 188 | SessionHandlerMap::const_iterator found = session_handler_map_.find(id); 189 | if (found != session_handler_map_.end()) 190 | { 191 | return found->second; 192 | } 193 | return SessionHandlePointer(); 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /eddyserver/eddyserver/io_service_thread_manager.h: -------------------------------------------------------------------------------- 1 | #ifndef __IO_SERVICE_THREAD_MANAGER_H__ 2 | #define __IO_SERVICE_THREAD_MANAGER_H__ 3 | 4 | #include 5 | #include 6 | #include "types.h" 7 | #include "id_generator.h" 8 | 9 | namespace eddyserver 10 | { 11 | class IOServiceThreadManager final 12 | { 13 | typedef std::unordered_map SessionHandlerMap; 14 | 15 | public: 16 | explicit IOServiceThreadManager(size_t thread_num = 1); 17 | 18 | ~IOServiceThreadManager(); 19 | 20 | public: 21 | /** 22 | * 运行线程 23 | */ 24 | void run(); 25 | 26 | /** 27 | * 停止线程 28 | */ 29 | void stop(); 30 | 31 | /** 32 | * 获取主线程 33 | */ 34 | ThreadPointer& get_main_thread(); 35 | 36 | /** 37 | * 获取负载最小的线程 38 | */ 39 | ThreadPointer& get_min_load_thread(); 40 | 41 | /** 42 | * 根据线程id获取线程 43 | */ 44 | ThreadPointer get_thread(IOThreadID id); 45 | 46 | /** 47 | * Session连接 48 | */ 49 | void on_session_connected(SessionPointer &session_ptr, SessionHandlePointer &handler); 50 | 51 | /** 52 | * Session关闭 53 | */ 54 | void on_session_closed(TCPSessionID id); 55 | 56 | /** 57 | * 获取Session数量 58 | */ 59 | size_t get_session_count() const; 60 | 61 | /** 62 | * 获取Session处理器 63 | */ 64 | SessionHandlePointer get_session_handler(TCPSessionID id) const; 65 | 66 | private: 67 | IOServiceThreadManager(const IOServiceThreadManager&) = delete; 68 | IOServiceThreadManager& operator= (const IOServiceThreadManager&) = delete; 69 | 70 | private: 71 | std::vector threads_; 72 | std::vector thread_load_; 73 | SessionHandlerMap session_handler_map_; 74 | IDGenerator id_generator_; 75 | }; 76 | } 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /eddyserver/eddyserver/message_filter.cpp: -------------------------------------------------------------------------------- 1 | #include "message_filter.h" 2 | #include 3 | #include 4 | #include "net_message.h" 5 | 6 | namespace eddyserver 7 | { 8 | MessageFilter::MessageFilter() 9 | : header_read_(false) 10 | { 11 | } 12 | 13 | // 获取欲读取数据大小 14 | size_t MessageFilter::bytes_wanna_read() 15 | { 16 | return header_read_ ? header_ : MessageFilter::header_size; 17 | } 18 | 19 | // 获取欲写入数据大小 20 | size_t MessageFilter::bytes_wanna_write(const std::vector &messages_to_be_sent) 21 | { 22 | if (messages_to_be_sent.empty()) 23 | { 24 | return 0; 25 | } 26 | return std::accumulate(messages_to_be_sent.begin(), messages_to_be_sent.end(), 0, [](size_t sum, const NetMessage &message) 27 | { 28 | return sum + MessageFilter::header_size + message.readable(); 29 | }); 30 | } 31 | 32 | // 读取数据 33 | size_t MessageFilter::read(const ByteArrray &buffer, std::vector &messages_received) 34 | { 35 | if (!header_read_) 36 | { 37 | uint8_t *data = const_cast(buffer.data()); 38 | header_ = ntohs(*reinterpret_cast(data)); 39 | header_read_ = true; 40 | return MessageFilter::header_size; 41 | } 42 | else 43 | { 44 | NetMessage new_message(header_); 45 | new_message.write(buffer.data(), header_); 46 | messages_received.push_back(std::move(new_message)); 47 | header_read_ = false; 48 | return header_; 49 | } 50 | } 51 | 52 | // 写入数据 53 | size_t MessageFilter::write(const std::vector &messages_to_be_sent, ByteArrray &buffer) 54 | { 55 | size_t bytes = 0; 56 | for (size_t i = 0; i < messages_to_be_sent.size(); ++i) 57 | { 58 | const NetMessage &message = messages_to_be_sent[i]; 59 | MessageHeader header = htons(static_cast(message.readable())); 60 | buffer.insert(buffer.end(), 61 | reinterpret_cast(&header), 62 | reinterpret_cast(&header) + sizeof(MessageHeader)); 63 | buffer.insert(buffer.end(), message.data(), message.data() + message.readable()); 64 | bytes += MessageFilter::header_size + message.readable(); 65 | } 66 | return bytes; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /eddyserver/eddyserver/message_filter.h: -------------------------------------------------------------------------------- 1 | #ifndef __MESSAGE_FILTER_H__ 2 | #define __MESSAGE_FILTER_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace eddyserver 10 | { 11 | class NetMessage; 12 | 13 | /** 14 | * 消息过滤器接口 15 | */ 16 | class MessageFilterInterface 17 | { 18 | public: 19 | typedef std::vector ByteArrray; 20 | 21 | public: 22 | MessageFilterInterface() = default; 23 | 24 | public: 25 | /** 26 | * 表示读取任意字节数 27 | */ 28 | static size_t any_bytes() 29 | { 30 | return std::numeric_limits::max(); 31 | } 32 | 33 | public: 34 | /** 35 | * 获取欲读取数据大小 36 | */ 37 | virtual size_t bytes_wanna_read() = 0; 38 | 39 | /** 40 | * 获取欲写入数据大小 41 | * @param messages_to_be_sent 将被发送的消息列表 42 | */ 43 | virtual size_t bytes_wanna_write(const std::vector &messages_to_be_sent) = 0; 44 | 45 | /** 46 | * 读取数据 47 | * 将param1 buffer的数据写入param2 messages_received中 48 | * @param buffer 缓存区数据 49 | * @param messages_received 读取的消息列表 50 | * @return 读取字节数 51 | */ 52 | virtual size_t read(const ByteArrray &buffer, std::vector &messages_received) = 0; 53 | 54 | /** 55 | * 写入数据 56 | * 将param1 messages_to_be_sent的消息列表写入param2 buffer中 57 | * @param messages_to_be_sent 写入的消息列表 58 | * @param &buffer 缓存区 59 | * @return 写入字节数 60 | */ 61 | virtual size_t write(const std::vector &messages_to_be_sent, ByteArrray &buffer) = 0; 62 | 63 | private: 64 | MessageFilterInterface(const MessageFilterInterface&) = delete; 65 | MessageFilterInterface& operator= (const MessageFilterInterface&) = delete; 66 | }; 67 | 68 | /** 69 | * 消息过滤器默认实现 70 | */ 71 | class MessageFilter : public MessageFilterInterface 72 | { 73 | public: 74 | typedef uint16_t MessageHeader; 75 | static const size_t header_size = sizeof(MessageHeader); 76 | 77 | public: 78 | MessageFilter(); 79 | 80 | public: 81 | /** 82 | * 获取欲读取数据大小 83 | */ 84 | virtual size_t bytes_wanna_read(); 85 | 86 | /** 87 | * 获取欲写入数据大小 88 | * @param messages_to_be_sent 将被发送的消息列表 89 | */ 90 | virtual size_t bytes_wanna_write(const std::vector &messages_to_be_sent); 91 | 92 | /** 93 | * 读取数据 94 | * 将param1 buffer的数据写入param2 messages_received中 95 | * @param buffer 缓存区数据 96 | * @param messages_received 读取的消息列表 97 | * @return 读取字节数 98 | */ 99 | virtual size_t read(const ByteArrray &buffer, std::vector &messages_received); 100 | 101 | /** 102 | * 写入数据 103 | * 将param1 messages_to_be_sent的消息列表写入param2 buffer中 104 | * @param messages_to_be_sent 写入的消息列表 105 | * @param &buffer 缓存区 106 | * @return 写入字节数 107 | */ 108 | virtual size_t write(const std::vector &messages_to_be_sent, ByteArrray &buffer); 109 | 110 | private: 111 | MessageHeader header_; 112 | bool header_read_; 113 | }; 114 | } 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /eddyserver/eddyserver/net_message.cpp: -------------------------------------------------------------------------------- 1 | #include "net_message.h" 2 | 3 | namespace eddyserver 4 | { 5 | NetMessage::NetMessage() 6 | : reader_pos_(0) 7 | , writer_pos_(0) 8 | , is_dynmic_(false) 9 | { 10 | } 11 | 12 | NetMessage::NetMessage(size_t size) 13 | : reader_pos_(0) 14 | , writer_pos_(0) 15 | , is_dynmic_(false) 16 | { 17 | ensure_writable_bytes(size); 18 | } 19 | 20 | NetMessage::NetMessage(const char *data, size_t size) 21 | : reader_pos_(0) 22 | , writer_pos_(0) 23 | , is_dynmic_(false) 24 | { 25 | write(data, size); 26 | } 27 | 28 | NetMessage::NetMessage(const NetMessage &other) 29 | : is_dynmic_(other.is_dynmic()) 30 | , reader_pos_(other.reader_pos_) 31 | , writer_pos_(other.writer_pos_) 32 | { 33 | if (!other.is_dynmic()) 34 | { 35 | memcpy(static_data_, other.static_data_, kDynamicThreshold); 36 | } 37 | else 38 | { 39 | dynamic_data_ = std::make_unique(); 40 | *dynamic_data_ = *other.dynamic_data_; 41 | } 42 | } 43 | 44 | NetMessage::NetMessage(NetMessage &&other) 45 | : is_dynmic_(other.is_dynmic_) 46 | , reader_pos_(other.reader_pos_) 47 | , writer_pos_(other.writer_pos_) 48 | { 49 | if (!other.is_dynmic()) 50 | { 51 | memcpy(static_data_, other.static_data_, kDynamicThreshold); 52 | } 53 | else 54 | { 55 | dynamic_data_ = std::move(other.dynamic_data_); 56 | } 57 | 58 | other.reader_pos_ = 0; 59 | other.writer_pos_ = 0; 60 | other.is_dynmic_ = false; 61 | } 62 | 63 | NetMessage& NetMessage::operator= (NetMessage &&rhs) 64 | { 65 | if (std::addressof(rhs) != this) 66 | { 67 | is_dynmic_ = rhs.is_dynmic(); 68 | reader_pos_ = rhs.reader_pos_; 69 | writer_pos_ = rhs.writer_pos_; 70 | if (!rhs.is_dynmic()) 71 | { 72 | memcpy(static_data_, rhs.static_data_, kDynamicThreshold); 73 | } 74 | else 75 | { 76 | dynamic_data_ = std::move(rhs.dynamic_data_); 77 | } 78 | 79 | rhs.reader_pos_ = 0; 80 | rhs.writer_pos_ = 0; 81 | rhs.is_dynmic_ = false; 82 | } 83 | return *this; 84 | } 85 | 86 | NetMessage& NetMessage::operator= (const NetMessage &rhs) 87 | { 88 | if (std::addressof(rhs) != this) 89 | { 90 | is_dynmic_ = rhs.is_dynmic(); 91 | reader_pos_ = rhs.reader_pos_; 92 | writer_pos_ = rhs.writer_pos_; 93 | if (!rhs.is_dynmic()) 94 | { 95 | memcpy(static_data_, rhs.static_data_, kDynamicThreshold); 96 | } 97 | else 98 | { 99 | if (dynamic_data_ == nullptr) 100 | { 101 | dynamic_data_ = std::make_unique(); 102 | } 103 | *dynamic_data_ = *rhs.dynamic_data_; 104 | } 105 | } 106 | return *this; 107 | } 108 | 109 | // 交换数据 110 | void NetMessage::swap(NetMessage &other) 111 | { 112 | if (std::addressof(other) != this) 113 | { 114 | dynamic_data_.swap(other.dynamic_data_); 115 | std::swap(is_dynmic_, other.is_dynmic_); 116 | std::swap(reader_pos_, other.reader_pos_); 117 | std::swap(writer_pos_, other.writer_pos_); 118 | std::swap(static_data_, other.static_data_); 119 | } 120 | } 121 | 122 | // 清空 123 | void NetMessage::clear() 124 | { 125 | reader_pos_ = 0; 126 | writer_pos_ = 0; 127 | if (is_dynmic()) 128 | { 129 | dynamic_data_->clear(); 130 | } 131 | } 132 | 133 | // 设为动态数组 134 | void NetMessage::set_dynamic() 135 | { 136 | assert(!is_dynmic()); 137 | if (!is_dynmic()) 138 | { 139 | is_dynmic_ = true; 140 | const size_t content_size = readable(); 141 | dynamic_data_ = std::make_unique(content_size); 142 | dynamic_data_->insert(dynamic_data_->begin(), static_data_ + reader_pos_, static_data_ + writer_pos_); 143 | reader_pos_ = 0; 144 | writer_pos_ = content_size; 145 | assert(content_size == readable()); 146 | } 147 | } 148 | 149 | // 设置容量大小 150 | void NetMessage::reserve(size_t size) 151 | { 152 | if (!is_dynmic()) 153 | { 154 | if (size <= kDynamicThreshold) 155 | { 156 | return; 157 | } 158 | set_dynamic(); 159 | } 160 | dynamic_data_->reserve(size); 161 | } 162 | 163 | // 获取全部 164 | void NetMessage::retrieve_all() 165 | { 166 | reader_pos_ = 0; 167 | writer_pos_ = 0; 168 | } 169 | 170 | // 获取数据 171 | void NetMessage::retrieve(size_t size) 172 | { 173 | assert(readable() >= size); 174 | if (readable() > size) 175 | { 176 | reader_pos_ += size; 177 | } 178 | else 179 | { 180 | retrieve_all(); 181 | } 182 | } 183 | 184 | // 写入数据大小 185 | void NetMessage::has_written(size_t size) 186 | { 187 | assert(writeable() >= size); 188 | writer_pos_ += size; 189 | } 190 | 191 | // 分配空间 192 | void NetMessage::make_space(size_t size) 193 | { 194 | if (writeable() + prependable() < size) 195 | { 196 | if (!is_dynmic()) 197 | { 198 | set_dynamic(); 199 | } 200 | dynamic_data_->resize(writer_pos_ + size); 201 | } 202 | else 203 | { 204 | if (!is_dynmic()) 205 | { 206 | memmove(static_data_, static_data_ + reader_pos_, writer_pos_ - reader_pos_); 207 | } 208 | else 209 | { 210 | memmove(dynamic_data_->data(), dynamic_data_->data() + reader_pos_, writer_pos_ - reader_pos_); 211 | } 212 | 213 | const size_t readable_size = readable(); 214 | reader_pos_ = 0; 215 | writer_pos_ = readable_size; 216 | assert(readable_size == readable()); 217 | } 218 | } 219 | 220 | // 确保可写字节 221 | void NetMessage::ensure_writable_bytes(size_t size) 222 | { 223 | if (writeable() < size) 224 | { 225 | make_space(size); 226 | } 227 | assert(writeable() >= size); 228 | } 229 | 230 | // 读取字符串 231 | std::string NetMessage::read_string() 232 | { 233 | assert(readable() > 0); 234 | const uint8_t *eos = data(); 235 | while (*eos++); 236 | size_t lenght = eos - data() - 1; 237 | assert(readable() >= lenght); 238 | std::string value; 239 | if (lenght > 0) 240 | { 241 | value.resize(lenght); 242 | memcpy(const_cast(value.data()), data(), lenght); 243 | retrieve(lenght); 244 | } 245 | return value; 246 | } 247 | 248 | void NetMessage::read_string(std::string *out_value) 249 | { 250 | assert(readable() > 0); 251 | const uint8_t *eos = data(); 252 | while (*eos++); 253 | size_t lenght = eos - data() - 1; 254 | assert(readable() >= lenght); 255 | 256 | out_value->clear(); 257 | if (lenght > 0) 258 | { 259 | out_value->resize(lenght); 260 | memcpy(const_cast(out_value->data()), data(), lenght); 261 | retrieve(lenght); 262 | } 263 | } 264 | 265 | // 读取长度和字符串 266 | std::string NetMessage::read_lenght_and_string() 267 | { 268 | assert(readable() >= sizeof(uint32_t)); 269 | uint32_t lenght = 0; 270 | memcpy(&lenght, data(), sizeof(uint32_t)); 271 | retrieve(sizeof(uint32_t)); 272 | std::string value; 273 | if (lenght > 0) 274 | { 275 | value.resize(lenght); 276 | memcpy(const_cast(value.data()), data(), lenght); 277 | retrieve(lenght); 278 | } 279 | return value; 280 | } 281 | 282 | void NetMessage::read_lenght_and_string(std::string *out_value) 283 | { 284 | assert(readable() >= sizeof(uint32_t)); 285 | uint32_t lenght = 0; 286 | memcpy(&lenght, data(), sizeof(uint32_t)); 287 | retrieve(sizeof(uint32_t)); 288 | 289 | out_value->clear(); 290 | if (lenght > 0) 291 | { 292 | out_value->resize(lenght); 293 | memcpy(const_cast(out_value->data()), data(), lenght); 294 | retrieve(lenght); 295 | } 296 | } 297 | 298 | // 写入数据 299 | size_t NetMessage::write(const void *data, size_t size) 300 | { 301 | ensure_writable_bytes(size); 302 | if (!is_dynmic()) 303 | { 304 | memcpy(static_data_ + writer_pos_, data, size); 305 | } 306 | else 307 | { 308 | dynamic_data_->insert(dynamic_data_->begin() + writer_pos_, 309 | reinterpret_cast(data), 310 | reinterpret_cast(data)+size); 311 | } 312 | has_written(size); 313 | return size; 314 | } 315 | 316 | // 写入字符串 317 | void NetMessage::write_string(const std::string &value) 318 | { 319 | if (!value.empty()) 320 | { 321 | write(const_cast(value.data()), value.size()); 322 | } 323 | } 324 | 325 | // 写入长度和字符串 326 | void NetMessage::write_lenght_and_string(const std::string &value) 327 | { 328 | write_pod(value.size()); 329 | write_string(value); 330 | } 331 | } 332 | -------------------------------------------------------------------------------- /eddyserver/eddyserver/net_message.h: -------------------------------------------------------------------------------- 1 | #ifndef __EDDY_BUFFER_H__ 2 | #define __EDDY_BUFFER_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace eddyserver 12 | { 13 | class NetMessage 14 | { 15 | typedef std::vector DynamicVector; 16 | 17 | public: 18 | /* 动态临界值 */ 19 | static const size_t kDynamicThreshold = 128; 20 | static_assert(NetMessage::kDynamicThreshold >= 0, "kDynamicThreshold must be greater than 0"); 21 | 22 | public: 23 | NetMessage(); 24 | 25 | /** 26 | * 构造函数 27 | * 预先分配内存 28 | * @param size 内存大小 29 | */ 30 | explicit NetMessage(size_t size); 31 | 32 | /** 33 | * 构造函数 34 | * 将data指针后的size大小的内存写入message 35 | * @param data 数据地址 36 | * @param size 数据大小 37 | */ 38 | NetMessage(const char *data, size_t size); 39 | 40 | /** 41 | * 拷贝构造函数 42 | */ 43 | NetMessage(const NetMessage &other); 44 | 45 | /** 46 | * 移动构造函数 47 | */ 48 | NetMessage(NetMessage &&other); 49 | 50 | /** 51 | * 重载赋值运算符 52 | */ 53 | NetMessage& operator= (NetMessage &&rhs); 54 | NetMessage& operator= (const NetMessage &rhs); 55 | 56 | /** 57 | * 交换数据 58 | */ 59 | void swap(NetMessage &other); 60 | 61 | public: 62 | /** 63 | * 是否是动态数组 64 | */ 65 | bool is_dynmic() const 66 | { 67 | return is_dynmic_; 68 | } 69 | 70 | /** 71 | * 获取可读数据大小 72 | */ 73 | size_t readable() const 74 | { 75 | return writer_pos_ - reader_pos_; 76 | } 77 | 78 | /** 79 | * 获取头部空闲大小 80 | */ 81 | size_t prependable() const 82 | { 83 | return reader_pos_; 84 | } 85 | 86 | /** 87 | * 获取尾部空闲大小 88 | */ 89 | size_t writeable() const 90 | { 91 | return (is_dynmic() ? dynamic_data_->size() : kDynamicThreshold) - writer_pos_; 92 | } 93 | 94 | /** 95 | * 获取容量 96 | */ 97 | size_t capacity() const 98 | { 99 | return is_dynmic() ? dynamic_data_->capacity() : kDynamicThreshold; 100 | } 101 | 102 | /** 103 | * 是否为空 104 | */ 105 | bool empty() const 106 | { 107 | return readable() == 0; 108 | } 109 | 110 | /** 111 | * 获取数据地址 112 | */ 113 | uint8_t* data() 114 | { 115 | return (is_dynmic() ? dynamic_data_->data() : static_data_) + reader_pos_; 116 | } 117 | 118 | const uint8_t* data() const 119 | { 120 | return (is_dynmic() ? dynamic_data_->data() : static_data_) + reader_pos_; 121 | } 122 | 123 | public: 124 | /** 125 | * 清空 126 | */ 127 | void clear(); 128 | 129 | /** 130 | * 设为动态数组 131 | */ 132 | void set_dynamic(); 133 | 134 | /** 135 | * 设置容量大小(不影响数据大小) 136 | * @param size 数据大小 137 | */ 138 | void reserve(size_t size); 139 | 140 | /** 141 | * 获取全部(只会移动读写位置) 142 | */ 143 | void retrieve_all(); 144 | 145 | /** 146 | * 获取数据(只会移动读写位置) 147 | * @param size 数据大小 148 | */ 149 | void retrieve(size_t size); 150 | 151 | /** 152 | * 写入数据大小(只会移动读写位置) 153 | * @param size 数据大小 154 | */ 155 | void has_written(size_t size); 156 | 157 | /** 158 | * 确保可写字节 159 | * @param size 数据大小 160 | */ 161 | void ensure_writable_bytes(size_t size); 162 | 163 | /** 164 | * 读取POD类型 165 | */ 166 | template 167 | Type read_pod() 168 | { 169 | static_assert(std::is_pod::value, "expects an POD type"); 170 | assert(readable() >= sizeof(Type)); 171 | Type value = 0; 172 | memcpy(&value, data(), sizeof(Type)); 173 | retrieve(sizeof(Type)); 174 | return value; 175 | } 176 | 177 | /** 178 | * 读取字符串 179 | */ 180 | std::string read_string(); 181 | void read_string(std::string *out_value); 182 | 183 | /** 184 | * 读取长度和字符串 185 | */ 186 | std::string read_lenght_and_string(); 187 | void read_lenght_and_string(std::string *out_value); 188 | 189 | /** 190 | * 写入数据 191 | * @param data 数据地址 192 | * @param size 数据大小 193 | */ 194 | size_t write(const void *data, size_t size); 195 | 196 | /** 197 | * 写入POD类型 198 | */ 199 | template 200 | void write_pod(Type value) 201 | { 202 | static_assert(std::is_pod::value, "expects an POD type"); 203 | write(&value, sizeof(Type)); 204 | } 205 | 206 | /** 207 | * 写入字符串 208 | */ 209 | void write_string(const std::string &value); 210 | 211 | /** 212 | * 写入长度和字符串 213 | */ 214 | void write_lenght_and_string(const std::string &value); 215 | 216 | private: 217 | /** 218 | * 分配空间 219 | * @param size 数据大小 220 | */ 221 | void make_space(size_t size); 222 | 223 | private: 224 | bool is_dynmic_; 225 | size_t reader_pos_; 226 | size_t writer_pos_; 227 | std::unique_ptr dynamic_data_; 228 | uint8_t static_data_[kDynamicThreshold]; 229 | }; 230 | 231 | typedef std::vector NetMessageVector; 232 | } 233 | 234 | #endif 235 | -------------------------------------------------------------------------------- /eddyserver/eddyserver/tcp_client.cpp: -------------------------------------------------------------------------------- 1 | #include "tcp_client.h" 2 | #include 3 | #include "tcp_session.h" 4 | #include "io_service_thread.h" 5 | #include "tcp_session_handler.h" 6 | #include "io_service_thread_manager.h" 7 | 8 | namespace eddyserver 9 | { 10 | TCPClient::TCPClient(IOServiceThreadManager &io_thread_manager, 11 | const SessionHandlerCreator &handler_creator, 12 | const MessageFilterCreator &filter_creator) 13 | : io_thread_manager_(io_thread_manager) 14 | , session_handler_creator_(handler_creator) 15 | , message_filter_creator_(filter_creator) 16 | { 17 | } 18 | 19 | // 发起连接请求 20 | void TCPClient::connect(asio::ip::tcp::endpoint &endpoint, 21 | asio::error_code &error_code) 22 | { 23 | MessageFilterPointer filter_ptr = message_filter_creator_(); 24 | SessionPointer session_ptr = std::make_shared( 25 | io_thread_manager_.get_min_load_thread(), filter_ptr); 26 | session_ptr->get_socket().connect(endpoint, error_code); 27 | handle_connect(session_ptr, error_code); 28 | } 29 | 30 | // 发起异步连接请求 31 | void TCPClient::async_connect(asio::ip::tcp::endpoint &endpoint, 32 | const std::function &cb) 33 | { 34 | MessageFilterPointer filter_ptr = message_filter_creator_(); 35 | SessionPointer session_ptr = std::make_shared( 36 | io_thread_manager_.get_min_load_thread(), filter_ptr); 37 | session_ptr->get_socket().async_connect(endpoint, 38 | std::bind(&TCPClient::handle_async_connect, this, session_ptr, cb, std::placeholders::_1)); 39 | } 40 | 41 | // 处理连接结果 42 | void TCPClient::handle_connect(SessionPointer session_ptr, 43 | asio::error_code error_code) 44 | { 45 | if (error_code) 46 | { 47 | std::cerr << error_code.message() << std::endl; 48 | return; 49 | } 50 | 51 | SessionHandlePointer handle_ptr = session_handler_creator_(); 52 | io_thread_manager_.on_session_connected(session_ptr, handle_ptr); 53 | } 54 | 55 | // 异步连接结果 56 | void TCPClient::handle_async_connect(SessionPointer session_ptr, 57 | std::function cb, 58 | asio::error_code error_code) 59 | { 60 | handle_connect(session_ptr, error_code); 61 | if (cb != nullptr) 62 | { 63 | cb(error_code); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /eddyserver/eddyserver/tcp_client.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_CLIENT_H__ 2 | #define __TCP_CLIENT_H__ 3 | 4 | #include 5 | #include "types.h" 6 | 7 | namespace eddyserver 8 | { 9 | class IOServiceThreadManager; 10 | 11 | class TCPClient final 12 | { 13 | public: 14 | TCPClient(IOServiceThreadManager &io_thread_manager, 15 | const SessionHandlerCreator &handler_creator, 16 | const MessageFilterCreator &filter_creator); 17 | 18 | public: 19 | /** 20 | * 发起连接请求 21 | */ 22 | void connect(asio::ip::tcp::endpoint &endpoint, 23 | asio::error_code &error_code); 24 | 25 | /** 26 | * 发起异步连接请求 27 | */ 28 | void async_connect(asio::ip::tcp::endpoint &endpoint, 29 | const std::function &cb); 30 | 31 | private: 32 | /** 33 | * 处理连接结果 34 | */ 35 | void handle_connect(SessionPointer session_ptr, 36 | asio::error_code error_code); 37 | 38 | /** 39 | * 异步连接结果 40 | */ 41 | void handle_async_connect(SessionPointer session_ptr, 42 | std::function cb, 43 | asio::error_code error_code); 44 | 45 | private: 46 | TCPClient(const TCPClient&) = delete; 47 | TCPClient& operator= (const TCPClient&) = delete; 48 | 49 | private: 50 | IOServiceThreadManager& io_thread_manager_; 51 | SessionHandlerCreator session_handler_creator_; 52 | MessageFilterCreator message_filter_creator_; 53 | }; 54 | } 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /eddyserver/eddyserver/tcp_server.cpp: -------------------------------------------------------------------------------- 1 | #include "tcp_server.h" 2 | #include 3 | #include "tcp_session.h" 4 | #include "io_service_thread.h" 5 | #include "tcp_session_handler.h" 6 | #include "io_service_thread_manager.h" 7 | 8 | namespace eddyserver 9 | { 10 | TCPServer::TCPServer(asio::ip::tcp::endpoint &endpoint, 11 | IOServiceThreadManager &io_thread_manager, 12 | const SessionHandlerCreator &handler_creator, 13 | const MessageFilterCreator &filter_creator, 14 | uint32_t keep_alive_time) 15 | : keep_alive_time_(keep_alive_time) 16 | , io_thread_manager_(io_thread_manager) 17 | , session_handler_creator_(handler_creator) 18 | , message_filter_creator_(filter_creator) 19 | , acceptor_(io_thread_manager.get_main_thread()->get_io_service(), endpoint) 20 | { 21 | MessageFilterPointer filter_ptr = message_filter_creator_(); 22 | acceptor_.set_option(asio::ip::tcp::acceptor::reuse_address(true)); 23 | SessionPointer session_ptr = std::make_shared( 24 | io_thread_manager_.get_min_load_thread(), filter_ptr, keep_alive_time_); 25 | acceptor_.async_accept(session_ptr->get_socket(), 26 | std::bind(&TCPServer::handle_accept, this, session_ptr, std::placeholders::_1)); 27 | } 28 | 29 | // 处理接受事件 30 | void TCPServer::handle_accept(SessionPointer session_ptr, asio::error_code error_code) 31 | { 32 | if (error_code) 33 | { 34 | std::cerr << error_code.message() << std::endl; 35 | assert(false); 36 | return; 37 | } 38 | 39 | SessionHandlePointer handle_ptr = session_handler_creator_(); 40 | io_thread_manager_.on_session_connected(session_ptr, handle_ptr); 41 | 42 | ThreadPointer td = io_thread_manager_.get_min_load_thread(); 43 | MessageFilterPointer filter_ptr = message_filter_creator_(); 44 | SessionPointer new_session_ptr = std::make_shared( 45 | td, filter_ptr, keep_alive_time_); 46 | acceptor_.async_accept(new_session_ptr->get_socket(), 47 | std::bind(&TCPServer::handle_accept, this, new_session_ptr, std::placeholders::_1)); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /eddyserver/eddyserver/tcp_server.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_SERVER_H__ 2 | #define __TCP_SERVER_H__ 3 | 4 | #include 5 | #include "types.h" 6 | 7 | namespace eddyserver 8 | { 9 | class IOServiceThreadManager; 10 | 11 | class TCPServer final 12 | { 13 | public: 14 | TCPServer(asio::ip::tcp::endpoint &endpoint, 15 | IOServiceThreadManager &io_thread_manager, 16 | const SessionHandlerCreator &handler_creator, 17 | const MessageFilterCreator &filter_creator, 18 | uint32_t keep_alive_time = 0); 19 | 20 | public: 21 | /** 22 | * 获取本地端点信息 23 | */ 24 | asio::ip::tcp::endpoint get_local_endpoint() const 25 | { 26 | return acceptor_.local_endpoint(); 27 | } 28 | 29 | private: 30 | /** 31 | * 处理接受事件 32 | */ 33 | void handle_accept(SessionPointer session_ptr, asio::error_code error_code); 34 | 35 | private: 36 | TCPServer(const TCPServer&) = delete; 37 | TCPServer& operator= (const TCPServer&) = delete; 38 | 39 | private: 40 | const uint32_t keep_alive_time_; 41 | asio::ip::tcp::acceptor acceptor_; 42 | IOServiceThreadManager& io_thread_manager_; 43 | SessionHandlerCreator session_handler_creator_; 44 | MessageFilterCreator message_filter_creator_; 45 | }; 46 | } 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /eddyserver/eddyserver/tcp_session.cpp: -------------------------------------------------------------------------------- 1 | #include "tcp_session.h" 2 | #include 3 | #include 4 | #include 5 | #include "message_filter.h" 6 | #include "io_service_thread.h" 7 | #include "tcp_session_handler.h" 8 | #include "io_service_thread_manager.h" 9 | 10 | namespace eddyserver 11 | { 12 | namespace session_stuff 13 | { 14 | typedef std::shared_ptr< std::vector > NetMessageVecPointer; 15 | 16 | /** 17 | * 发送消息列表到SessionHandler 18 | */ 19 | void SendMessageListToHandler(IOServiceThreadManager &manager, 20 | TCPSessionID id, 21 | NetMessageVecPointer messages_received) 22 | { 23 | SessionHandlePointer handler_ptr = manager.get_session_handler(id); 24 | if (handler_ptr != nullptr) 25 | { 26 | for (size_t i = 0; i < messages_received->size(); ++i) 27 | { 28 | handler_ptr->on_message(messages_received->at(i)); 29 | } 30 | } 31 | } 32 | 33 | /** 34 | * 投递消息列表到主线程操作 35 | */ 36 | void PackMessageList(SessionPointer session_ptr) 37 | { 38 | if (!session_ptr->get_messages_received().empty()) 39 | { 40 | NetMessageVecPointer messages_received = std::make_shared< std::vector >(); 41 | *messages_received = std::move(session_ptr->get_messages_received()); 42 | session_ptr->get_io_thread()->get_thread_manager().get_main_thread()->post(std::bind( 43 | SendMessageListToHandler, 44 | std::ref(session_ptr->get_io_thread()->get_thread_manager()), 45 | session_ptr->get_id(), 46 | messages_received 47 | )); 48 | } 49 | } 50 | 51 | /** 52 | * 直接发送消息列表到SessionHandler 53 | */ 54 | void SendMessageListDirectly(SessionPointer session_ptr) 55 | { 56 | SessionHandlePointer handler_ptr = session_ptr->get_io_thread()->get_thread_manager().get_session_handler(session_ptr->get_id()); 57 | if (handler_ptr != nullptr) 58 | { 59 | std::vector &messages_received = session_ptr->get_messages_received(); 60 | for (size_t i = 0; i < messages_received.size(); ++i) 61 | { 62 | handler_ptr->on_message(messages_received[i]); 63 | } 64 | messages_received.clear(); 65 | } 66 | } 67 | } 68 | 69 | TCPSession::TCPSession(ThreadPointer &td, MessageFilterPointer &filter, uint32_t keep_alive_time) 70 | : closed_(true) 71 | , session_id_(0) 72 | , io_thread_(td) 73 | , msg_filter_(filter) 74 | , num_read_handlers_(0) 75 | , num_write_handlers_(0) 76 | , socket_(td->get_io_service()) 77 | , keep_alive_time_(keep_alive_time) 78 | , close_timer_(td->get_io_service()) 79 | { 80 | } 81 | 82 | // 初始化 83 | void TCPSession::init(TCPSessionID id) 84 | { 85 | assert(id > 0); 86 | 87 | closed_ = false; 88 | session_id_ = id; 89 | SessionPointer self = shared_from_this(); 90 | io_thread_->get_session_queue().add(self); 91 | last_activity_time_ = std::chrono::steady_clock::now(); 92 | 93 | asio::ip::tcp::no_delay option(true); 94 | socket_.set_option(option); 95 | 96 | size_t bytes_wanna_read = msg_filter_->bytes_wanna_read(); 97 | if (bytes_wanna_read == 0) 98 | { 99 | return; 100 | } 101 | 102 | ++num_read_handlers_; 103 | if (bytes_wanna_read == MessageFilterInterface::any_bytes()) 104 | { 105 | buffer_receiving_.resize(NetMessage::kDynamicThreshold); 106 | socket_.async_read_some(asio::buffer(buffer_receiving_.data(), buffer_receiving_.size()), 107 | std::bind(&TCPSession::handle_read, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); 108 | } 109 | else 110 | { 111 | buffer_receiving_.resize(bytes_wanna_read); 112 | asio::async_read(socket_, asio::buffer(buffer_receiving_.data(), bytes_wanna_read), 113 | std::bind(&TCPSession::handle_read, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); 114 | } 115 | } 116 | 117 | // 处理关闭 118 | void TCPSession::hanlde_close() 119 | { 120 | if (num_write_handlers_ > 0) 121 | { 122 | return; 123 | } 124 | 125 | if (io_thread_->get_session_queue().get(get_id()) != nullptr) 126 | { 127 | io_thread_->get_thread_manager().get_main_thread()->post( 128 | std::bind(&IOServiceThreadManager::on_session_closed, &io_thread_->get_thread_manager(), get_id())); 129 | 130 | asio::error_code error_code; 131 | socket_.shutdown(asio::ip::tcp::socket::shutdown_send, error_code); 132 | if (error_code && error_code != asio::error::not_connected) 133 | { 134 | std::cerr << error_code.message() << std::endl; 135 | } 136 | io_thread_->get_session_queue().remove(get_id()); 137 | 138 | buffer_receiving_.resize(NetMessage::kDynamicThreshold); 139 | socket_.async_read_some(asio::buffer(buffer_receiving_.data(), buffer_receiving_.size()), 140 | std::bind(&TCPSession::handle_safe_close, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); 141 | 142 | close_timer_.expires_from_now(std::chrono::seconds(5)); 143 | close_timer_.async_wait([=](asio::error_code error) 144 | { 145 | if (error != asio::error::operation_aborted) 146 | { 147 | socket_.cancel(); 148 | socket_.close(); 149 | } 150 | }); 151 | } 152 | } 153 | 154 | // 关闭会话 155 | void TCPSession::close() 156 | { 157 | if (closed_) 158 | { 159 | return; 160 | } 161 | closed_ = true; 162 | hanlde_close(); 163 | } 164 | 165 | // 检查Session存活 166 | bool TCPSession::check_keep_alive() 167 | { 168 | if (keep_alive_time_.count() == 0) 169 | { 170 | return true; 171 | } 172 | return std::chrono::steady_clock::now() - last_activity_time_ < keep_alive_time_; 173 | } 174 | 175 | // 投递消息列表 176 | void TCPSession::post_message_list(const std::vector &messages) 177 | { 178 | if (closed_ || messages.empty()) 179 | { 180 | return; 181 | } 182 | 183 | size_t bytes_wanna_write = msg_filter_->bytes_wanna_write(messages); 184 | if (bytes_wanna_write == 0) 185 | { 186 | return; 187 | } 188 | 189 | buffer_to_be_sent_.reserve(buffer_to_be_sent_.size() + bytes_wanna_write); 190 | msg_filter_->write(messages, buffer_to_be_sent_); 191 | 192 | if (buffer_sending_.empty()) 193 | { 194 | ++num_write_handlers_; 195 | buffer_sending_.swap(buffer_to_be_sent_); 196 | asio::async_write(socket_, asio::buffer(buffer_sending_.data(), bytes_wanna_write), 197 | std::bind(&TCPSession::hanlde_write, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); 198 | } 199 | } 200 | 201 | // 处理读 202 | void TCPSession::handle_read(asio::error_code error_code, size_t bytes_transferred) 203 | { 204 | --num_read_handlers_; 205 | assert(num_read_handlers_ >= 0); 206 | 207 | if (error_code || closed_) 208 | { 209 | closed_ = true; 210 | hanlde_close(); 211 | return; 212 | } 213 | 214 | bool wanna_post = messages_received_.empty(); 215 | size_t bytes_read = msg_filter_->read(buffer_receiving_, messages_received_); 216 | assert(bytes_read == bytes_transferred); 217 | if (bytes_read != bytes_transferred) 218 | { 219 | std::cerr << "bytes_read: " << bytes_read << " bytes_transferred: " << bytes_transferred << std::endl; 220 | } 221 | 222 | buffer_receiving_.clear(); 223 | wanna_post = wanna_post && !messages_received_.empty(); 224 | 225 | if (wanna_post) 226 | { 227 | if (io_thread_->get_id() == io_thread_->get_thread_manager().get_main_thread()->get_id()) 228 | { 229 | io_thread_->post(std::bind(session_stuff::SendMessageListDirectly, shared_from_this())); 230 | } 231 | else 232 | { 233 | io_thread_->post(std::bind(session_stuff::PackMessageList, shared_from_this())); 234 | } 235 | last_activity_time_ = std::chrono::steady_clock::now(); 236 | } 237 | 238 | size_t bytes_wanna_read = msg_filter_->bytes_wanna_read(); 239 | if (bytes_wanna_read == 0) 240 | { 241 | return; 242 | } 243 | 244 | ++num_read_handlers_; 245 | if (bytes_wanna_read == MessageFilterInterface::any_bytes()) 246 | { 247 | buffer_receiving_.resize(NetMessage::kDynamicThreshold); 248 | socket_.async_read_some(asio::buffer(&*buffer_receiving_.begin(), buffer_receiving_.size()), 249 | std::bind(&TCPSession::handle_read, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); 250 | } 251 | else 252 | { 253 | buffer_receiving_.resize(bytes_wanna_read); 254 | asio::async_read(socket_, asio::buffer(buffer_receiving_.data(), bytes_wanna_read), 255 | std::bind(&TCPSession::handle_read, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); 256 | } 257 | } 258 | 259 | // 处理写 260 | void TCPSession::hanlde_write(asio::error_code error_code, size_t bytes_transferred) 261 | { 262 | --num_write_handlers_; 263 | assert(num_write_handlers_ >= 0); 264 | 265 | if (error_code || closed_) 266 | { 267 | closed_ = true; 268 | hanlde_close(); 269 | return; 270 | } 271 | 272 | buffer_sending_.clear(); 273 | 274 | if (buffer_to_be_sent_.empty()) 275 | { 276 | return; 277 | } 278 | 279 | ++num_write_handlers_; 280 | buffer_sending_.swap(buffer_to_be_sent_); 281 | asio::async_write(socket_, asio::buffer(buffer_sending_.data(), buffer_sending_.size()), 282 | std::bind(&TCPSession::hanlde_write, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); 283 | } 284 | 285 | // 处理安全关闭 286 | void TCPSession::handle_safe_close(asio::error_code error_code, size_t bytes_transferred) 287 | { 288 | if (bytes_transferred == 0) 289 | { 290 | if (error_code != asio::error::operation_aborted) 291 | { 292 | close_timer_.cancel(); 293 | socket_.close(); 294 | } 295 | } 296 | else 297 | { 298 | buffer_receiving_.resize(NetMessage::kDynamicThreshold); 299 | socket_.async_read_some(asio::buffer(buffer_receiving_.data(), buffer_receiving_.size()), 300 | std::bind(&TCPSession::handle_safe_close, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); 301 | } 302 | } 303 | } 304 | -------------------------------------------------------------------------------- /eddyserver/eddyserver/tcp_session.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_SESSION_H__ 2 | #define __TCP_SESSION_H__ 3 | 4 | #include 5 | #include 6 | #include "types.h" 7 | #include "net_message.h" 8 | 9 | namespace eddyserver 10 | { 11 | class TCPSession final : public std::enable_shared_from_this< TCPSession > 12 | { 13 | friend class IOServiceThread; 14 | friend class IOServiceThreadManager; 15 | 16 | typedef asio::ip::tcp::socket SocketType; 17 | typedef std::chrono::steady_clock::time_point TimePoint; 18 | 19 | public: 20 | TCPSession(ThreadPointer &td, MessageFilterPointer &filter, uint32_t keep_alive_time = 0); 21 | 22 | public: 23 | /** 24 | * 获取socket 25 | */ 26 | SocketType& get_socket() 27 | { 28 | return socket_; 29 | } 30 | 31 | /** 32 | * 获取Session ID 33 | */ 34 | TCPSessionID get_id() const 35 | { 36 | return session_id_; 37 | } 38 | 39 | /** 40 | * 获取线程 41 | */ 42 | ThreadPointer& get_io_thread() 43 | { 44 | return io_thread_; 45 | } 46 | 47 | /** 48 | * 获取收到的消息列表 49 | */ 50 | std::vector& get_messages_received() 51 | { 52 | return messages_received_; 53 | } 54 | 55 | /** 56 | * 投递消息列表 57 | */ 58 | void post_message_list(const std::vector &messages); 59 | 60 | /** 61 | * 关闭Session 62 | */ 63 | void close(); 64 | 65 | private: 66 | /** 67 | * 初始化 68 | */ 69 | void init(TCPSessionID id); 70 | 71 | /** 72 | * 检查Session存活 73 | */ 74 | bool check_keep_alive(); 75 | 76 | private: 77 | /** 78 | * 处理读 79 | */ 80 | void handle_read(asio::error_code error_code, size_t bytes_transferred); 81 | 82 | /** 83 | * 处理写 84 | */ 85 | void hanlde_write(asio::error_code error_code, size_t bytes_transferred); 86 | 87 | /** 88 | * 处理关闭 89 | */ 90 | void hanlde_close(); 91 | 92 | /** 93 | * 处理安全关闭 94 | */ 95 | void handle_safe_close(asio::error_code error_code, size_t bytes_transferred); 96 | 97 | private: 98 | TCPSession(const TCPSession&) = delete; 99 | TCPSession& operator= (const TCPSession&) = delete; 100 | 101 | private: 102 | bool closed_; 103 | int num_read_handlers_; 104 | int num_write_handlers_; 105 | TCPSessionID session_id_; 106 | SocketType socket_; 107 | ThreadPointer io_thread_; 108 | asio::steady_timer close_timer_; 109 | MessageFilterPointer msg_filter_; 110 | TimePoint last_activity_time_; 111 | std::vector buffer_receiving_; 112 | std::vector buffer_sending_; 113 | std::vector buffer_to_be_sent_; 114 | NetMessageVector messages_received_; 115 | const std::chrono::seconds keep_alive_time_; 116 | }; 117 | } 118 | 119 | #endif 120 | -------------------------------------------------------------------------------- /eddyserver/eddyserver/tcp_session_handler.cpp: -------------------------------------------------------------------------------- 1 | #include "tcp_session_handler.h" 2 | #include "net_message.h" 3 | #include "tcp_session.h" 4 | #include "io_service_thread.h" 5 | #include "io_service_thread_manager.h" 6 | 7 | namespace eddyserver 8 | { 9 | namespace session_handler_stuff 10 | { 11 | typedef std::shared_ptr< std::vector > NetMessageVecPointer; 12 | 13 | /** 14 | * 关闭Session 15 | */ 16 | void CloseSession(ThreadPointer thread_ptr, TCPSessionID id) 17 | { 18 | SessionPointer session_ptr = thread_ptr->get_session_queue().get(id); 19 | if (session_ptr != nullptr) 20 | { 21 | session_ptr->close(); 22 | } 23 | } 24 | 25 | /** 26 | * 发送消息列表到Session 27 | */ 28 | void SendMessageListToSession(ThreadPointer thread_ptr, TCPSessionID id, NetMessageVecPointer messages) 29 | { 30 | SessionPointer session_ptr = thread_ptr->get_session_queue().get(id); 31 | if (session_ptr != nullptr) 32 | { 33 | session_ptr->post_message_list(*messages); 34 | } 35 | } 36 | 37 | /** 38 | * 投递消息列表到线程操作 39 | */ 40 | void PackMessageList(SessionHandlePointer session_handle_ptr) 41 | { 42 | if (!session_handle_ptr->messages_to_be_sent().empty()) 43 | { 44 | ThreadPointer thread_ptr = session_handle_ptr->get_thread_manager()->get_thread(session_handle_ptr->get_thread_id()); 45 | if (thread_ptr != nullptr) 46 | { 47 | NetMessageVecPointer messages_to_be_sent = std::make_shared< std::vector >(); 48 | *messages_to_be_sent = std::move(session_handle_ptr->messages_to_be_sent()); 49 | thread_ptr->post(std::bind( 50 | SendMessageListToSession, thread_ptr, session_handle_ptr->get_session_id(), messages_to_be_sent)); 51 | } 52 | } 53 | } 54 | 55 | /** 56 | * 直接发送消息列表 57 | */ 58 | void SendMessageListDirectly(SessionHandlePointer session_handle_ptr) 59 | { 60 | ThreadPointer thread_ptr = session_handle_ptr->get_thread_manager()->get_thread(session_handle_ptr->get_thread_id()); 61 | if (thread_ptr != nullptr) 62 | { 63 | SessionPointer session_ptr = thread_ptr->get_session_queue().get(session_handle_ptr->get_session_id()); 64 | if (session_ptr != nullptr) 65 | { 66 | session_ptr->post_message_list(session_handle_ptr->messages_to_be_sent()); 67 | session_handle_ptr->messages_to_be_sent().clear(); 68 | } 69 | } 70 | } 71 | } 72 | 73 | TCPSessionHandler::TCPSessionHandler() 74 | : session_id_(0) 75 | { 76 | } 77 | 78 | // 初始化 79 | void TCPSessionHandler::init(TCPSessionID sid, 80 | IOThreadID tid, 81 | IOServiceThreadManager *manager, 82 | const asio::ip::tcp::endpoint &remote_endpoint) 83 | { 84 | thread_id_ = tid; 85 | session_id_ = sid; 86 | io_thread_manager_ = manager; 87 | remote_endpoint_ = remote_endpoint; 88 | } 89 | 90 | // 处置连接 91 | void TCPSessionHandler::dispose() 92 | { 93 | session_id_ = 0; 94 | } 95 | 96 | // 关闭连接 97 | void TCPSessionHandler::close() 98 | { 99 | if (is_closed()) 100 | { 101 | return; 102 | } 103 | 104 | session_handler_stuff::PackMessageList(shared_from_this()); 105 | 106 | ThreadPointer thread_ptr = get_thread_manager()->get_thread(thread_id_); 107 | if (thread_ptr != nullptr) 108 | { 109 | thread_ptr->post(std::bind(session_handler_stuff::CloseSession, thread_ptr, session_id_)); 110 | } 111 | } 112 | 113 | // 发送消息 114 | void TCPSessionHandler::send(const NetMessage &message) 115 | { 116 | if (is_closed()) 117 | { 118 | return; 119 | } 120 | 121 | if (message.empty()) 122 | { 123 | return; 124 | } 125 | 126 | bool wanna_send = messages_to_be_sent_.empty(); 127 | messages_to_be_sent_.push_back(message); 128 | 129 | if (wanna_send) 130 | { 131 | if (thread_id_ == io_thread_manager_->get_main_thread()->get_id()) 132 | { 133 | io_thread_manager_->get_main_thread()->post( 134 | std::bind(session_handler_stuff::SendMessageListDirectly, shared_from_this())); 135 | } 136 | else 137 | { 138 | io_thread_manager_->get_main_thread()->post( 139 | std::bind(session_handler_stuff::PackMessageList, shared_from_this())); 140 | } 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /eddyserver/eddyserver/tcp_session_handler.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_SESSION_HANDLE_H__ 2 | #define __TCP_SESSION_HANDLE_H__ 3 | 4 | #include 5 | #include 6 | #include "types.h" 7 | #include "net_message.h" 8 | 9 | namespace eddyserver 10 | { 11 | class IOServiceThreadManager; 12 | 13 | class TCPSessionHandler : public std::enable_shared_from_this < TCPSessionHandler > 14 | { 15 | friend class IOServiceThreadManager; 16 | 17 | public: 18 | TCPSessionHandler(); 19 | virtual ~TCPSessionHandler() = default; 20 | 21 | public: 22 | /** 23 | * 连接事件 24 | */ 25 | virtual void on_connected() = 0; 26 | 27 | /** 28 | * 接收消息事件 29 | */ 30 | virtual void on_message(NetMessage &message) = 0; 31 | 32 | /** 33 | * 关闭事件 34 | */ 35 | virtual void on_closed() = 0; 36 | 37 | public: 38 | /** 39 | * 是否已关闭 40 | */ 41 | bool is_closed() const 42 | { 43 | return session_id_ == 0; 44 | } 45 | 46 | /** 47 | * 获取线程id 48 | */ 49 | IOThreadID get_thread_id() const 50 | { 51 | return thread_id_; 52 | } 53 | 54 | /** 55 | * 获取Session ID 56 | */ 57 | TCPSessionID get_session_id() const 58 | { 59 | return session_id_; 60 | } 61 | 62 | /** 63 | * 获取线程管理器 64 | */ 65 | IOServiceThreadManager* get_thread_manager() 66 | { 67 | return io_thread_manager_; 68 | } 69 | 70 | /** 71 | * 获取将被发送的消息列表 72 | */ 73 | std::vector& messages_to_be_sent() 74 | { 75 | return messages_to_be_sent_; 76 | } 77 | 78 | /** 79 | * 获取对端端点信息 80 | */ 81 | const asio::ip::tcp::endpoint& remote_endpoint() const 82 | { 83 | return remote_endpoint_; 84 | } 85 | 86 | public: 87 | /** 88 | * 发送消息 89 | */ 90 | void send(const NetMessage &message); 91 | 92 | /** 93 | * 关闭连接 94 | */ 95 | void close(); 96 | 97 | /** 98 | * 处置连接 99 | */ 100 | void dispose(); 101 | 102 | private: 103 | /** 104 | * 初始化 105 | */ 106 | void init(TCPSessionID sid, 107 | IOThreadID tid, 108 | IOServiceThreadManager *manager, 109 | const asio::ip::tcp::endpoint &remote_endpoint); 110 | 111 | private: 112 | TCPSessionHandler(const TCPSessionHandler&) = delete; 113 | TCPSessionHandler& operator= (const TCPSessionHandler&) = delete; 114 | 115 | private: 116 | TCPSessionID session_id_; 117 | IOThreadID thread_id_; 118 | asio::ip::tcp::endpoint remote_endpoint_; 119 | IOServiceThreadManager* io_thread_manager_; 120 | std::vector messages_to_be_sent_; 121 | }; 122 | } 123 | 124 | #endif 125 | -------------------------------------------------------------------------------- /eddyserver/eddyserver/tcp_session_queue.cpp: -------------------------------------------------------------------------------- 1 | #include "tcp_session_queue.h" 2 | #include "tcp_session.h" 3 | 4 | namespace eddyserver 5 | { 6 | // 获取Session数量 7 | size_t TCPSessionQueue::size() const 8 | { 9 | return session_queue_.size(); 10 | } 11 | 12 | // 添加Session入队列 13 | void TCPSessionQueue::add(SessionPointer &session) 14 | { 15 | session_queue_.insert(std::make_pair(session->get_id(), session)); 16 | } 17 | 18 | // 通过id获取Session 19 | SessionPointer TCPSessionQueue::get(TCPSessionID id) 20 | { 21 | auto found = session_queue_.find(id); 22 | if (found != session_queue_.end()) 23 | { 24 | return found->second; 25 | } 26 | return SessionPointer(); 27 | } 28 | 29 | // 移除指定id的Session 30 | void TCPSessionQueue::remove(TCPSessionID id) 31 | { 32 | session_queue_.erase(id); 33 | } 34 | 35 | // 清空整个队列 36 | void TCPSessionQueue::clear() 37 | { 38 | session_queue_.clear(); 39 | } 40 | 41 | // 遍历Session队列 42 | void TCPSessionQueue::foreach(const std::function &cb) 43 | { 44 | auto itr = session_queue_.begin(); 45 | while (itr != session_queue_.end()) 46 | { 47 | cb(itr->second); 48 | ++itr; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /eddyserver/eddyserver/tcp_session_queue.h: -------------------------------------------------------------------------------- 1 | #ifndef __TCP_SESSION_QUEUE_H__ 2 | #define __TCP_SESSION_QUEUE_H__ 3 | 4 | #include 5 | #include "types.h" 6 | 7 | namespace eddyserver 8 | { 9 | class TCPSessionQueue final 10 | { 11 | public: 12 | TCPSessionQueue() = default; 13 | 14 | public: 15 | /** 16 | * 获取Session数量 17 | */ 18 | size_t size() const; 19 | 20 | /** 21 | * 添加Session入队列 22 | */ 23 | void add(SessionPointer &session); 24 | 25 | /** 26 | * 通过id获取Session 27 | */ 28 | SessionPointer get(TCPSessionID id); 29 | 30 | /** 31 | * 移除指定id的Session 32 | */ 33 | void remove(TCPSessionID id); 34 | 35 | /** 36 | * 清空整个队列 37 | */ 38 | void clear(); 39 | 40 | /** 41 | * 遍历Session队列 42 | * @param cb 回调函数 43 | */ 44 | void foreach(const std::function &cb); 45 | 46 | private: 47 | TCPSessionQueue(const TCPSessionQueue&) = delete; 48 | TCPSessionQueue& operator= (const TCPSessionQueue&) = delete; 49 | 50 | private: 51 | std::unordered_map session_queue_; 52 | }; 53 | } 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /eddyserver/eddyserver/thread_pool.cpp: -------------------------------------------------------------------------------- 1 | #include "thread_pool.h" 2 | #include 3 | #include 4 | #include 5 | 6 | Thread::Thread() 7 | : finished_(false) 8 | { 9 | std::function worker = std::bind(&Thread::run_loop, this); 10 | thread_ = std::make_unique(std::move(worker)); 11 | } 12 | 13 | // 合并线程 14 | void Thread::join() 15 | { 16 | termminiate(); 17 | thread_->join(); 18 | } 19 | 20 | // 终止线程 21 | void Thread::termminiate() 22 | { 23 | if (!finished_) 24 | { 25 | finished_ = true; 26 | condition_incoming_task_.notify_one(); 27 | } 28 | } 29 | 30 | // 获取负载 31 | size_t Thread::load() const 32 | { 33 | size_t count = 0; 34 | { 35 | std::lock_guard lock(queue_task_mutex_); 36 | count = queue_task_.size(); 37 | } 38 | return count; 39 | } 40 | 41 | // 等待到空闲 42 | void Thread::wait_for_idle() 43 | { 44 | while (load() > 0) 45 | { 46 | std::this_thread::sleep_for(std::chrono::milliseconds(1)); 47 | } 48 | } 49 | 50 | // 添加任务 51 | size_t Thread::append(Callback &&cb) 52 | { 53 | size_t size = 0; 54 | if (!finished_) 55 | { 56 | { 57 | std::lock_guard lock(queue_task_mutex_); 58 | queue_task_.push_back(std::forward(cb)); 59 | size = queue_task_.size(); 60 | } 61 | 62 | if (size == 1) 63 | { 64 | condition_incoming_task_.notify_one(); 65 | } 66 | } 67 | return size; 68 | } 69 | 70 | size_t Thread::append(const Callback &cb) 71 | { 72 | size_t size = 0; 73 | if (!finished_) 74 | { 75 | { 76 | std::lock_guard lock(queue_task_mutex_); 77 | queue_task_.push_back(cb); 78 | size = queue_task_.size(); 79 | } 80 | 81 | if (size == 1) 82 | { 83 | condition_incoming_task_.notify_one(); 84 | } 85 | } 86 | return size; 87 | } 88 | 89 | // 线程循环 90 | void Thread::run_loop() 91 | { 92 | while (!finished_) 93 | { 94 | { 95 | std::unique_lock lock(queue_task_mutex_); 96 | while (queue_task_.empty()) 97 | { 98 | if (finished_) 99 | { 100 | break; 101 | } 102 | condition_incoming_task_.wait(lock); 103 | } 104 | } 105 | 106 | if (finished_) 107 | { 108 | break; 109 | } 110 | 111 | Callback cb; 112 | { 113 | std::lock_guard lock(queue_task_mutex_); 114 | if (!queue_task_.empty()) 115 | { 116 | cb = std::move(queue_task_.front()); 117 | } 118 | } 119 | 120 | if (cb != nullptr) 121 | { 122 | try 123 | { 124 | cb(); 125 | } 126 | catch (const std::exception &e) 127 | { 128 | std::cerr << e.what() << std::endl; 129 | } 130 | std::lock_guard lock(queue_task_mutex_); 131 | queue_task_.pop_front(); 132 | } 133 | } 134 | } 135 | 136 | /************************************************************************/ 137 | /************************************************************************/ 138 | 139 | namespace thread_pool_stuff 140 | { 141 | struct min_load_cmp 142 | { 143 | bool operator() (const ThreadPool::ThreadPointer &lhs, 144 | const ThreadPool::ThreadPointer &rhs) const 145 | { 146 | return lhs->load() < rhs->load(); 147 | } 148 | }; 149 | } 150 | 151 | ThreadPool::ThreadPool(size_t thread_num) 152 | { 153 | assert(thread_num > 0); 154 | if (thread_num > 0) 155 | { 156 | for (size_t i = 0; i < thread_num; ++i) 157 | { 158 | vector_thread_.push_back(std::make_shared()); 159 | } 160 | } 161 | } 162 | 163 | // 获取线程数量 164 | size_t ThreadPool::count() const 165 | { 166 | return vector_thread_.size(); 167 | } 168 | 169 | // 合并线程 170 | void ThreadPool::join() 171 | { 172 | for (size_t i = 0; i < vector_thread_.size(); ++i) 173 | { 174 | vector_thread_[i]->join(); 175 | } 176 | } 177 | 178 | // 终止线程 179 | void ThreadPool::termminiate() 180 | { 181 | for (size_t i = 0; i < vector_thread_.size(); ++i) 182 | { 183 | vector_thread_[i]->termminiate(); 184 | } 185 | } 186 | 187 | // 获取负载 188 | size_t ThreadPool::load(size_t index) const 189 | { 190 | return index < vector_thread_.size() ? vector_thread_[index]->load() : 0; 191 | } 192 | 193 | // 等待到空闲 194 | void ThreadPool::wait_for_idle() 195 | { 196 | for (size_t i = 0; i < vector_thread_.size(); ++i) 197 | { 198 | vector_thread_[i]->wait_for_idle(); 199 | } 200 | } 201 | 202 | // 添加任务 203 | void ThreadPool::append(Thread::Callback &&task) 204 | { 205 | assert(!vector_thread_.empty()); 206 | if (!vector_thread_.empty()) 207 | { 208 | std::vector::iterator itr; 209 | { 210 | std::lock_guard lock(mutex_); 211 | itr = std::min_element(vector_thread_.begin(), vector_thread_.end(), thread_pool_stuff::min_load_cmp()); 212 | } 213 | (*itr)->append(std::forward(task)); 214 | } 215 | } 216 | 217 | void ThreadPool::append(const Thread::Callback &task) 218 | { 219 | assert(!vector_thread_.empty()); 220 | if (!vector_thread_.empty()) 221 | { 222 | std::vector::iterator itr; 223 | { 224 | std::lock_guard lock(mutex_); 225 | itr = std::min_element(vector_thread_.begin(), vector_thread_.end(), thread_pool_stuff::min_load_cmp()); 226 | } 227 | (*itr)->append(task); 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /eddyserver/eddyserver/thread_pool.h: -------------------------------------------------------------------------------- 1 | #ifndef __THREADPOOL_H__ 2 | #define __THREADPOOL_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | class Thread final 14 | { 15 | public: 16 | typedef std::function Callback; 17 | typedef std::unique_ptr ThreadPointer; 18 | 19 | public: 20 | Thread(); 21 | 22 | public: 23 | /** 24 | * 合并线程 25 | */ 26 | void join(); 27 | 28 | /** 29 | * 终止线程 30 | */ 31 | void termminiate(); 32 | 33 | /** 34 | * 获取负载 35 | */ 36 | size_t load() const; 37 | 38 | /** 39 | * 等待到空闲 40 | */ 41 | void wait_for_idle(); 42 | 43 | /** 44 | * 添加任务 45 | */ 46 | size_t append(Callback &&cb); 47 | size_t append(const Callback &cb); 48 | 49 | private: 50 | /** 51 | * 线程循环 52 | */ 53 | void run_loop(); 54 | 55 | private: 56 | Thread(const Thread&) = delete; 57 | Thread& operator= (const Thread&) = delete; 58 | 59 | private: 60 | std::atomic_bool finished_; 61 | ThreadPointer thread_; 62 | std::list queue_task_; 63 | mutable std::mutex queue_task_mutex_; 64 | std::condition_variable condition_incoming_task_; 65 | }; 66 | 67 | class ThreadPool final 68 | { 69 | public: 70 | typedef std::shared_ptr ThreadPointer; 71 | 72 | public: 73 | ThreadPool(size_t thread_num); 74 | 75 | public: 76 | /** 77 | * 获取线程数量 78 | */ 79 | size_t count() const; 80 | 81 | /** 82 | * 合并线程 83 | */ 84 | void join(); 85 | 86 | /** 87 | * 终止线程 88 | */ 89 | void termminiate(); 90 | 91 | /** 92 | * 获取负载 93 | */ 94 | size_t load(size_t index) const; 95 | 96 | /** 97 | * 等待到空闲 98 | */ 99 | void wait_for_idle(); 100 | 101 | /** 102 | * 添加任务 103 | */ 104 | void append(Thread::Callback &&cb); 105 | void append(const Thread::Callback &cb); 106 | 107 | private: 108 | ThreadPool(const ThreadPool&) = delete; 109 | ThreadPool& operator= (const ThreadPool&) = delete; 110 | 111 | private: 112 | mutable std::mutex mutex_; 113 | std::vector vector_thread_; 114 | }; 115 | 116 | #endif 117 | -------------------------------------------------------------------------------- /eddyserver/eddyserver/types.h: -------------------------------------------------------------------------------- 1 | #ifndef __EDDY_TYPES_H__ 2 | #define __EDDY_TYPES_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace eddyserver 9 | { 10 | typedef uint32_t IOThreadID; 11 | typedef uint32_t TCPSessionID; 12 | 13 | class TCPSession; 14 | class IOServiceThread; 15 | class TCPSessionHandler; 16 | class MessageFilterInterface; 17 | 18 | typedef std::shared_ptr SessionPointer; 19 | typedef std::shared_ptr ThreadPointer; 20 | typedef std::shared_ptr SessionHandlePointer; 21 | typedef std::shared_ptr MessageFilterPointer; 22 | 23 | typedef std::function SessionHandlerCreator; 24 | typedef std::function MessageFilterCreator; 25 | } 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /examples/echo/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 设置工程名 2 | set(CURRENT_PROJECT_NAME echo) 3 | 4 | # 添加编译列表 5 | set(CURRENT_PROJECT_SRC_LISTS 6 | main.cpp 7 | ) 8 | 9 | # 包含目录 10 | include_directories( 11 | ${ASIO_INCLUDE_DIRS} 12 | ${EDDYSERVER_INCLUDE_DIRS} 13 | ) 14 | 15 | # 链接目录 16 | link_directories( 17 | ${BINARY_OUTPUT_DIR} 18 | ) 19 | 20 | # 生成可执行文件 21 | file(GLOB_RECURSE CURRENT_HEADERS *.h *.hpp) 22 | source_group("Header Files" FILES ${CURRENT_HEADERS}) 23 | add_executable(${CURRENT_PROJECT_NAME} ${CURRENT_HEADERS} ${CURRENT_PROJECT_SRC_LISTS}) 24 | 25 | set_target_properties(${CURRENT_PROJECT_NAME} 26 | PROPERTIES 27 | RUNTIME_OUTPUT_DIRECTORY 28 | "${BINARY_OUTPUT_DIR}" 29 | ) 30 | 31 | # 链接库配置 32 | target_link_libraries(${CURRENT_PROJECT_NAME} 33 | ${EDDYSERVER_LIBRARY} 34 | ) 35 | 36 | # 设置分组 37 | SET_PROPERTY(TARGET ${CURRENT_PROJECT_NAME} PROPERTY FOLDER "examples") 38 | -------------------------------------------------------------------------------- /examples/echo/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class SessionHandle : public eddyserver::TCPSessionHandler 5 | { 6 | public: 7 | // 连接事件 8 | virtual void on_connected() override 9 | { 10 | std::cout << "on_connected" << std::endl; 11 | } 12 | 13 | // 接收消息事件 14 | virtual void on_message(eddyserver::NetMessage &message) override 15 | { 16 | std::cout << "on_message" << std::endl; 17 | send(message); 18 | } 19 | 20 | // 关闭事件 21 | virtual void on_closed() override 22 | { 23 | std::cout << "on_closed" << std::endl; 24 | } 25 | }; 26 | 27 | eddyserver::MessageFilterPointer CreateMessageFilter() 28 | { 29 | return std::make_shared(); 30 | } 31 | 32 | eddyserver::SessionHandlePointer CreateSessionHandler() 33 | { 34 | return std::make_shared(); 35 | } 36 | 37 | int main(int argc, char *argv[]) 38 | { 39 | eddyserver::IOServiceThreadManager io(4); 40 | asio::ip::tcp::endpoint ep(asio::ip::address_v4::from_string("127.0.0.1"), 4400); 41 | eddyserver::TCPServer server(ep, io, CreateSessionHandler, CreateMessageFilter); 42 | io.run(); 43 | 44 | return 0; 45 | } 46 | --------------------------------------------------------------------------------