├── .gitignore ├── LICENSE ├── README.md ├── client ├── client.cpp ├── client.vcproj └── makefile ├── concurrent_client ├── concurrent_client.cpp ├── concurrent_client.vcproj └── makefile ├── concurrent_server ├── concurrent_server.cpp ├── concurrent_server.vcproj └── makefile ├── config.mk ├── doc └── overall ├── echo_client ├── echo_client.cpp ├── echo_client.vcproj └── makefile ├── echo_server ├── echo_server.cpp ├── echo_server.vcproj └── makefile ├── file_client ├── file_client.cpp ├── file_client.h ├── file_client.vcproj └── makefile ├── file_common ├── common.h ├── file_buffer.h └── unpacker.h ├── file_server ├── file_server.cpp ├── file_server.vcproj ├── file_socket.cpp ├── file_socket.h └── makefile ├── include ├── base.h ├── config.h ├── container.h ├── executor.h ├── ext │ ├── callbacks.h │ ├── client.h │ ├── ext.h │ ├── packer.h │ ├── reliable_udp.h │ ├── server.h │ ├── ssl.h │ ├── ssl_websocket.h │ ├── tcp.h │ ├── udp.h │ ├── unpacker.h │ └── websocket.h ├── object_pool.h ├── old_class_names.h ├── service_pump.h ├── single_service_pump.h ├── socket.h ├── socket_service.h ├── tcp │ ├── alias.h │ ├── client.h │ ├── client_socket.h │ ├── proxy │ │ └── socks.h │ ├── server.h │ ├── server_socket.h │ ├── socket.h │ ├── ssl │ │ ├── alias.h │ │ └── ssl.h │ └── websocket │ │ ├── ssl │ │ └── ssl.h │ │ └── websocket.h ├── timer.h ├── tracked_executor.h └── udp │ ├── alias.h │ ├── reliable_socket.h │ ├── socket.h │ └── socket_service.h ├── makefile ├── pingpong_client ├── makefile ├── pingpong_client.cpp └── pingpong_client.vcproj ├── pingpong_server ├── makefile ├── pingpong_server.cpp └── pingpong_server.vcproj ├── socket_management ├── client.h ├── makefile ├── server.h ├── socket_management.cpp └── socket_management.vcproj ├── ssl_test ├── certs │ ├── dh2048.pem │ ├── server.crt │ └── server.key ├── client_certs │ ├── dh2048.pem │ ├── server.crt │ └── server.key ├── makefile ├── ssl_test.cpp └── ssl_test.vcproj ├── ssl_websocket_test ├── certs │ ├── dh2048.pem │ ├── server.crt │ └── server.key ├── client_certs │ ├── dh2048.pem │ ├── server.crt │ └── server.key ├── makefile ├── ssl_websocket_test.cpp └── ssl_websocket_test.vcproj ├── st_asio_wrapper_vc2008.sln ├── udp_test ├── makefile ├── udp_test.cpp └── udp_test.vcproj ├── unix_socket ├── makefile └── unix_socket.cpp ├── unix_udp_test ├── makefile └── unix_udp_test.cpp └── websocket_test ├── makefile ├── websocket_test.cpp └── websocket_test.vcproj /.gitignore: -------------------------------------------------------------------------------- 1 | Debug/ 2 | debug/ 3 | Release/ 4 | release/ 5 | *.mk 6 | !config.mk 7 | Makefile 8 | *.txt 9 | *.exe 10 | *.project 11 | *.workspace 12 | .* 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | st_asio_wrapper 2 | =============== 3 | Overview 4 | - 5 | st_asio_wrapper is an asynchronous c/s framework based on Boost.Asio, besides all benefits brought by Boost and Boost.Asio, it also contains:
6 | 1. Based on message just like UDP with several couple of build-in packer and unpacker;
7 | 2. Support packer and unpacker customization, and replacing packer and unpacker at run-time;
8 | 3. Automatically reconnect to the server after link broken;
9 | 4. Support object pool, object reusing and restoration;
10 | 5. Worker thread management;
11 | 6. Support message buffer;
12 | 7. Widely support timers;
13 | 8. Support TCP/UDP and Unix domin TCP/UDP;
14 | 9. Support reliable UDP (base on KCP -- https://github.com/skywind3000/kcp);
15 | 10. Support ssl;
16 | 17 | Quick start: 18 | - 19 | ### server: 20 | Derive your own socket from `server_socket_base`, you must at least re-write `on_msg_handle` virtual function and handle messages in it;
21 | Create a `service_pump` object, create a `server_base` object, call `service_pump::start_service`;
22 | Call `server_socket_base::send_msg` or `server_base::broadcast_msg` when you have messages need to send.
23 | ### client: 24 | Derive your own socket from `client_socket_base`, you must at least re-write the `on_msg` or `on_msg_handle` virtual function and handle messages in it;
25 | Create a `service_pump` object, create a `multi_client_base` object, add some socket via `multi_client_base::add_socket`, call `service_pump::start_service`;
26 | Call `client_socket_base::send_msg` or `multi_client_base::broadcast_msg` when you have messages need to send.
27 | 28 | Directory structure: 29 | - 30 | All source codes are placed in directory `include`, other directories hold demos, for documents, please refer to this project https://github.com/youngwolf-project/ascs/ .
31 | 32 | Demos: 33 | - 34 | ### echo_server: 35 | Demonstrate how to implement tcp servers, it cantains two servers, one is the simplest server (normal server), which just send characters from keyboard to all clients (from `client` demo), and receive messages from all clients (from `client` demo), then display them; the other is echo server, which send every received message from `echo_client` demo back.
36 | ### client: 37 | Demonstrate how to implement tcp client, it simply send characters from keyboard to normal server in `echo_server`, and receive messages from normal server in `echo_server`, then display them.
38 | ### echo_client: 39 | Used to test `st_asio_wrapper`'s performance (whith `echo server`).
40 | ### file_server: 41 | A file transfer server.
42 | ### file_client: 43 | A file transfer client, use `get [file name2] [...]` to fetch files from `file_server`.
44 | ### udp_client: 45 | Demonstrate how to implement UDP communication.
46 | ### ssl_test: 47 | Demonstrate how to implement TCP communication with ssl.
48 | 49 | Compiler requirement: 50 | - 51 | No special limitations, just need you to compile boost successfully.
52 | 53 | Boost requirement: 54 | - 55 | 1.49 or highter.
56 | 57 | email: mail2tao@163.com 58 | - 59 | Community on QQ: 198941541 60 | - 61 | -------------------------------------------------------------------------------- /client/client.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | //configuration 5 | #define ST_ASIO_SERVER_PORT 9528 6 | #define ST_ASIO_SYNC_SEND 7 | #define ST_ASIO_SYNC_RECV 8 | //#define ST_ASIO_PASSIVE_RECV //because we not defined this macro, this demo will use mix model to receive messages, which means 9 | //some messages will be dispatched via on_msg_handle(), some messages will be returned via sync_recv_msg(), 10 | //if the server send messages quickly enough, you will see them cross together. 11 | #define ST_ASIO_HIDE_WARNINGS 12 | #define ST_ASIO_ALIGNED_TIMER 13 | #define ST_ASIO_CUSTOM_LOG 14 | #define ST_ASIO_DEFAULT_UNPACKER non_copy_unpacker 15 | //#define ST_ASIO_DEFAULT_UNPACKER stream_unpacker 16 | 17 | //the following two macros demonstrate how to support huge msg(exceed 65535 - 2). 18 | #define ST_ASIO_HUGE_MSG 19 | #define ST_ASIO_MSG_BUFFER_SIZE 1000000 20 | #define ST_ASIO_HEARTBEAT_INTERVAL 5 //if use stream_unpacker, heartbeat messages will be treated as normal messages, 21 | //because stream_unpacker doesn't support heartbeat 22 | //configuration 23 | 24 | //demonstrate how to use custom log system: 25 | //use your own code to replace the following all_out_helper2 macros, then you can record logs according to your wishes. 26 | //custom log should be defined(or included) before including any st_asio_wrapper header files except base.h 27 | //notice: please don't forget to define the ST_ASIO_CUSTOM_LOG macro. 28 | #include "../include/base.h" 29 | using namespace st_asio_wrapper; 30 | 31 | class unified_out 32 | { 33 | public: 34 | static void fatal_out(const char* fmt, ...) {all_out_helper2("fatal");} 35 | static void error_out(const char* fmt, ...) {all_out_helper2("error");} 36 | static void warning_out(const char* fmt, ...) {all_out_helper2("warning");} 37 | static void info_out(const char* fmt, ...) {all_out_helper2("info");} 38 | static void debug_out(const char* fmt, ...) {all_out_helper2("debug");} 39 | }; 40 | 41 | #include "../include/ext/tcp.h" 42 | #include "../include/ext/callbacks.h" 43 | using namespace st_asio_wrapper; 44 | //using namespace st_asio_wrapper::tcp; 45 | using namespace st_asio_wrapper::ext; 46 | using namespace st_asio_wrapper::ext::tcp; 47 | using namespace st_asio_wrapper::ext::tcp::proxy; 48 | 49 | #define QUIT_COMMAND "quit" 50 | #define RESTART_COMMAND "restart" 51 | #define RECONNECT "reconnect" 52 | #define STATISTIC "statistic" 53 | 54 | //we only want close reconnecting mechanism on these sockets, so it cannot be done by defining macro ST_ASIO_RECONNECT to false 55 | ///* 56 | //method 1 57 | class short_client : public st_asio_wrapper::tcp::multi_client_base > 58 | { 59 | public: 60 | short_client(service_pump& service_pump_) : multi_client_base >(service_pump_) {set_server_addr(ST_ASIO_SERVER_PORT);} 61 | 62 | void set_server_addr(unsigned short _port, const std::string& _ip = ST_ASIO_SERVER_IP) {port = _port; ip = _ip;} 63 | bool send_msg(const std::string& msg) {return send_msg(msg, port, ip);} 64 | bool send_msg(std::string& msg) {return send_msg(msg, port, ip);} 65 | bool send_msg(const std::string& msg, unsigned short port, const std::string& ip) {std::string unused(msg); return send_msg(unused, port, ip);} 66 | bool send_msg(std::string& msg, unsigned short port, const std::string& ip) 67 | { 68 | BOOST_AUTO(socket_ptr, add_socket(port, ip)); 69 | if (!socket_ptr) 70 | return false; 71 | 72 | //register event callback from outside of the socket, it also can be done from inside of the socket, see echo_server for more details 73 | socket_ptr->register_on_connect(boost::bind(&socks4::client_socket::set_reconnect, boost::placeholders::_1, false), true); //close reconnection mechanism 74 | 75 | //without following setting, socks4::client_socket will be downgraded to normal client_socket 76 | //socket_ptr->set_target_addr(9527, "172.27.0.14"); //target server address, original server address becomes SOCK4 server address 77 | return socket_ptr->send_msg(msg); 78 | } 79 | 80 | private: 81 | unsigned short port; 82 | std::string ip; 83 | }; 84 | //*/ 85 | //method 2 86 | /* 87 | typedef multi_client_base > > short_client_base; 88 | class short_client : public short_client_base 89 | { 90 | public: 91 | short_client(service_pump& service_pump_) : short_client_base(service_pump_) {set_server_addr(ST_ASIO_SERVER_PORT);} 92 | 93 | void set_server_addr(unsigned short _port, const std::string& _ip = ST_ASIO_SERVER_IP) {port = _port; ip = _ip;} 94 | bool send_msg(const std::string& msg) {return send_msg(msg, port, ip);} 95 | bool send_msg(std::string& msg) {return send_msg(msg, port, ip);} 96 | bool send_msg(const std::string& msg, unsigned short port, const std::string& ip) {std::string unused(msg); return send_msg(unused, port, ip);} 97 | bool send_msg(std::string& msg, unsigned short port, const std::string& ip) 98 | { 99 | BOOST_AUTO(socket_ptr, add_socket(port, ip)); 100 | if (!socket_ptr) 101 | return false; 102 | 103 | //we now can not call register_on_connect on socket_ptr, since socket_ptr is not wrapped by callbacks::c_socket 104 | //register event callback from outside of the socket, it also can be done from inside of the socket, see echo_server for more details 105 | //socket_ptr->register_on_connect(boost::bind(&socks4::client_socket::set_reconnect, boost::placeholders::_1, false), true); //close reconnection mechanism 106 | 107 | //without following setting, socks4::client_socket will be downgraded to normal client_socket 108 | //socket_ptr->set_target_addr(9527, "172.27.0.14"); //target server address, original server address becomes SOCK4 server address 109 | return socket_ptr->send_msg(msg); 110 | } 111 | 112 | private: 113 | unsigned short port; 114 | std::string ip; 115 | }; 116 | void on_create(object_pool* op, object_pool::object_ctype& socket_ptr) {socket_ptr->set_reconnect(false);} 117 | */ 118 | 119 | void sync_recv_thread(client_socket& client) 120 | { 121 | ST_ASIO_DEFAULT_UNPACKER::container_type msg_can; 122 | sync_call_result re = SUCCESS; 123 | do 124 | { 125 | re = client.sync_recv_msg(msg_can, 50); //st_asio_wrapper will not maintain messages in msg_can anymore after sync_recv_msg return, please note. 126 | if (SUCCESS == re) 127 | { 128 | for (BOOST_AUTO(iter, msg_can.begin()); iter != msg_can.end(); ++iter) 129 | printf("sync recv(" ST_ASIO_SF ") : %s\n", iter->size(), iter->data()); 130 | msg_can.clear(); //sync_recv_msg just append new message(s) to msg_can, please note. 131 | } 132 | } while (SUCCESS == re || TIMEOUT == re); 133 | puts("sync recv end."); 134 | } 135 | 136 | int main(int argc, const char* argv[]) 137 | { 138 | printf("usage: %s [ [ip=%s]]\n", argv[0], ST_ASIO_SERVER_PORT + 100, ST_ASIO_SERVER_IP); 139 | if (argc >= 2 && (0 == strcmp(argv[1], "--help") || 0 == strcmp(argv[1], "-h"))) 140 | return 0; 141 | else 142 | puts("type " QUIT_COMMAND " to end."); 143 | 144 | //demonstrate how to use single_service_pump 145 | single_service_pump client; 146 | //single_service_pump also is a service_pump, this let us control client2 via client 147 | short_client client2(client); //without single_client, we need to define ST_ASIO_AVOID_AUTO_STOP_SERVICE macro to forbid service_pump stopping services automatically 148 | //method 2 149 | /* 150 | //close reconnection mechanism, 2 approaches 151 | client2.register_on_create(boost::bind(on_create, boost::placeholders::_1, boost::placeholders::_2)); 152 | client2.register_on_create(on_create); 153 | */ 154 | //method 2 155 | 156 | // argv[2] = "::1" //ipv6 157 | // argv[2] = "127.0.0.1" //ipv4 158 | unsigned short port = ST_ASIO_SERVER_PORT + 100; 159 | std::string ip = ST_ASIO_SERVER_IP; 160 | if (argc > 1) 161 | port = (unsigned short) atoi(argv[1]); 162 | if (argc > 2) 163 | ip = argv[2]; 164 | 165 | client.set_server_addr(port, ip); 166 | //without following setting, socks5::single_client will be downgraded to normal single_client 167 | //client.set_target_addr(9527, "172.27.0.14"); //target server address, original server address becomes SOCK5 server address 168 | //client.set_auth("st_asio_wrapper", "st_asio_wrapper"); //can be omitted if the SOCKS5 server support non-auth 169 | client2.set_server_addr(port + 100, ip); 170 | 171 | client.start_service(); 172 | boost::thread t = boost::thread(boost::bind(&sync_recv_thread, boost::ref(client))); 173 | while(client.is_running()) 174 | { 175 | std::string str; 176 | std::cin >> str; 177 | if (QUIT_COMMAND == str) 178 | { 179 | client.stop_service(); 180 | t.join(); 181 | } 182 | else if (RESTART_COMMAND == str) 183 | { 184 | client.stop_service(); 185 | t.join(); 186 | 187 | t = boost::thread(boost::bind(&sync_recv_thread, boost::ref(client))); 188 | client.start_service(); 189 | } 190 | else if (RECONNECT == str) 191 | client.graceful_shutdown(true); 192 | else if (STATISTIC == str) 193 | puts(client.get_statistic().to_string().data()); 194 | else 195 | { 196 | std::string tmp_str = str + " (from short client)"; //make a backup of str first, because it will be moved into client 197 | 198 | //each of following 4 tests is exclusive from other 3, because str will be moved into client (to reduce one memory replication) 199 | //to avoid this, call other overloads that accept const references. 200 | //we also have another 4 tests that send native messages (if the server used stream_unpacker) not listed, you can try to complete them. 201 | //test #1 202 | std::string msg2(" (from normal client)"); 203 | sync_call_result re = client.sync_safe_send_msg(str, msg2, 100); //new feature introduced in 2.2.0 204 | if (SUCCESS != re) 205 | printf("sync send result: %d\n", re); 206 | //test #2 207 | //client.sync_send_msg(str, msg2, 100); //new feature introduced in 2.2.0 208 | //test #3 209 | //client.safe_send_msg(str, msg2); //new feature introduced in 2.2.0 210 | //test #4 211 | //client.send_msg(str, msg2); //new feature introduced in 2.2.0 212 | 213 | client2.send_msg(tmp_str); 214 | } 215 | } 216 | 217 | return 0; 218 | } 219 | -------------------------------------------------------------------------------- /client/client.vcproj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngwolf-project/st_asio_wrapper/3e060755ca6a8fc2ebfed8ccc41c561ad783a211/client/client.vcproj -------------------------------------------------------------------------------- /client/makefile: -------------------------------------------------------------------------------- 1 | 2 | module = client 3 | 4 | include ../config.mk 5 | 6 | -------------------------------------------------------------------------------- /concurrent_client/concurrent_client.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | //configuration 6 | #define ST_ASIO_SERVER_PORT 9527 7 | #define ST_ASIO_MAX_OBJECT_NUM 102400 8 | #define ST_ASIO_REUSE_OBJECT //use objects pool 9 | #define ST_ASIO_DELAY_CLOSE 5 //define this to avoid hooks for async call (and slightly improve performance) 10 | #define ST_ASIO_MSG_BUFFER_SIZE 1024 11 | #define ST_ASIO_SYNC_DISPATCH 12 | #ifdef ST_ASIO_SYNC_DISPATCH 13 | #define ST_ASIO_INPUT_QUEUE non_lock_queue 14 | #define ST_ASIO_OUTPUT_QUEUE non_lock_queue 15 | #endif 16 | #define ST_ASIO_DECREASE_THREAD_AT_RUNTIME 17 | //configuration 18 | 19 | #include "../include/ext/tcp.h" 20 | using namespace st_asio_wrapper; 21 | //using namespace st_asio_wrapper::tcp; 22 | using namespace st_asio_wrapper::ext::tcp; 23 | 24 | #define QUIT_COMMAND "quit" 25 | #define STATUS "status" 26 | #define STATISTIC "statistic" 27 | #define LIST_ALL_CLIENT "list all client" 28 | #define INCREASE_THREAD "increase thread" 29 | #define DECREASE_THREAD "decrease thread" 30 | 31 | class echo_socket : public client_socket 32 | { 33 | public: 34 | echo_socket(i_matrix& matrix_) : client_socket(matrix_), max_delay(1.f), msg_len(ST_ASIO_MSG_BUFFER_SIZE - ST_ASIO_HEAD_LEN) {unpacker()->stripped(false);} 35 | void begin(float max_delay_, size_t msg_len_) {max_delay = max_delay_; msg_len = msg_len_;} 36 | 37 | protected: 38 | bool check_delay(bool restart_timer) 39 | { 40 | boost::lock_guard lock(mutex); 41 | if (is_connected() && (double) last_send_time.elapsed().wall / 1000000000 > max_delay) 42 | { 43 | force_shutdown(); 44 | return false; 45 | } 46 | else if (restart_timer) 47 | { 48 | last_send_time.stop(); 49 | last_send_time.start(); 50 | } 51 | 52 | return true; 53 | } 54 | 55 | virtual void on_connect() 56 | { 57 | boost::asio::ip::tcp::no_delay option(true); 58 | lowest_layer().set_option(option); 59 | 60 | char* buff = new char[msg_len]; 61 | memset(buff, '$', msg_len); //what should we send? 62 | 63 | last_send_time.stop(); 64 | last_send_time.start(); 65 | send_msg(buff, msg_len, true); 66 | 67 | delete[] buff; 68 | set_timer(TIMER_END, 5000, boost::lambda::if_then_else_return(boost::lambda::bind(&echo_socket::check_delay, this, false), true, false)); 69 | 70 | client_socket::on_connect(); 71 | } 72 | 73 | //msg handling 74 | #ifdef ST_ASIO_SYNC_DISPATCH 75 | virtual size_t on_msg(list& msg_can) 76 | { 77 | st_asio_wrapper::do_something_to_all(msg_can, boost::bind(&echo_socket::handle_msg, this, boost::placeholders::_1)); 78 | msg_can.clear(); 79 | 80 | return 1; 81 | } 82 | #endif 83 | #ifdef ST_ASIO_DISPATCH_BATCH_MSG 84 | virtual size_t on_msg_handle(out_queue_type& msg_can) 85 | { 86 | assert(!msg_can.empty()); 87 | out_container_type tmp_can; 88 | msg_can.swap(tmp_can); 89 | 90 | st_asio_wrapper::do_something_to_all(tmp_can, boost::bind(&echo_socket::handle_msg, this, boost::placeholders::_1)); 91 | return tmp_can.size(); 92 | } 93 | #else 94 | virtual bool on_msg_handle(out_msg_type& msg) {handle_msg(msg); return true;} 95 | #endif 96 | //msg handling end 97 | 98 | private: 99 | void handle_msg(out_msg_type& msg) {if (check_delay(true)) direct_send_msg(msg, true);} 100 | 101 | private: 102 | float max_delay; 103 | size_t msg_len; 104 | 105 | boost::timer::cpu_timer last_send_time; 106 | boost::mutex mutex; 107 | }; 108 | 109 | class echo_client : public st_asio_wrapper::tcp::multi_client_base 110 | { 111 | public: 112 | echo_client(service_pump& service_pump_) : multi_client_base(service_pump_) {} 113 | void begin(float max_delay, size_t msg_len) {do_something_to_all(boost::bind(&echo_socket::begin, boost::placeholders::_1, max_delay, msg_len));} 114 | }; 115 | 116 | int main(int argc, const char* argv[]) 117 | { 118 | printf("usage: %s [ [ [ [ [ [link num=16]]]]]]\n", 119 | argv[0], ST_ASIO_MSG_BUFFER_SIZE - ST_ASIO_HEAD_LEN, 1.f, ST_ASIO_SERVER_PORT, ST_ASIO_SERVER_IP); 120 | if (argc >= 2 && (0 == strcmp(argv[1], "--help") || 0 == strcmp(argv[1], "-h"))) 121 | return 0; 122 | else 123 | puts("type " QUIT_COMMAND " to end."); 124 | 125 | /////////////////////////////////////////////////////////// 126 | size_t link_num = 16; 127 | if (argc > 6) 128 | link_num = std::min(ST_ASIO_MAX_OBJECT_NUM, std::max(atoi(argv[6]), 1)); 129 | 130 | printf("exec: concurrent_client with " ST_ASIO_SF " links\n", link_num); 131 | /////////////////////////////////////////////////////////// 132 | 133 | service_pump sp; 134 | echo_client client(sp); 135 | 136 | // argv[5] = "::1" //ipv6 137 | // argv[5] = "127.0.0.1" //ipv4 138 | std::string ip = argc > 5 ? argv[5] : ST_ASIO_SERVER_IP; 139 | unsigned short port = argc > 4 ? atoi(argv[4]) : ST_ASIO_SERVER_PORT; 140 | 141 | int thread_num = 1; 142 | if (argc > 3) 143 | thread_num = std::min(16, std::max(thread_num, atoi(argv[3]))); 144 | //add one thread will seriously impact IO throughput when doing performance benchmark, this is because the business logic is very simple (send original messages back, 145 | //or just add up total message size), under this scenario, just one service thread without receiving buffer will obtain the best IO throughput. 146 | //the server has such behavior too. 147 | 148 | for (size_t i = 0; i < link_num; ++i) 149 | client.add_socket(port, ip); 150 | 151 | float max_delay = 1.f; 152 | if (argc > 2) 153 | max_delay = std::max(.1f, (float) atof(argv[2])); 154 | 155 | size_t msg_len = ST_ASIO_MSG_BUFFER_SIZE - ST_ASIO_HEAD_LEN; 156 | if (argc > 1) 157 | msg_len = std::max((size_t) 1, std::min(msg_len, (size_t) atoi(argv[1]))); 158 | client.begin(max_delay, msg_len); 159 | 160 | sp.start_service(thread_num); 161 | while(sp.is_running()) 162 | { 163 | std::string str; 164 | std::getline(std::cin, str); 165 | if (str.empty()) 166 | ; 167 | else if (QUIT_COMMAND == str) 168 | sp.stop_service(); 169 | else if (STATISTIC == str) 170 | { 171 | printf("link #: " ST_ASIO_SF ", valid links: " ST_ASIO_SF ", invalid links: " ST_ASIO_SF "\n\n", client.size(), client.valid_size(), client.invalid_object_size()); 172 | puts(client.get_statistic().to_string().data()); 173 | } 174 | else if (STATUS == str) 175 | client.list_all_status(); 176 | else if (LIST_ALL_CLIENT == str) 177 | client.list_all_object(); 178 | else if (INCREASE_THREAD == str) 179 | sp.add_service_thread(1); 180 | else if (DECREASE_THREAD == str) 181 | sp.del_service_thread(1); 182 | } 183 | 184 | return 0; 185 | } 186 | -------------------------------------------------------------------------------- /concurrent_client/concurrent_client.vcproj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngwolf-project/st_asio_wrapper/3e060755ca6a8fc2ebfed8ccc41c561ad783a211/concurrent_client/concurrent_client.vcproj -------------------------------------------------------------------------------- /concurrent_client/makefile: -------------------------------------------------------------------------------- 1 | 2 | module = concurrent_client 3 | ext_libs = -lboost_timer 4 | 5 | include ../config.mk 6 | 7 | -------------------------------------------------------------------------------- /concurrent_server/concurrent_server.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | //configuration 5 | #define ST_ASIO_SERVER_PORT 9527 6 | #define ST_ASIO_MAX_OBJECT_NUM 102400 7 | #define ST_ASIO_ASYNC_ACCEPT_NUM 1024 //pre-create 1024 server socket, this is very useful if creating server socket is very expensive 8 | #define ST_ASIO_REUSE_OBJECT //use objects pool 9 | #define ST_ASIO_DELAY_CLOSE 5 //define this to avoid hooks for async call (and slightly improve performance) 10 | #define ST_ASIO_MSG_BUFFER_SIZE 1024 11 | #define ST_ASIO_SYNC_DISPATCH 12 | #ifdef ST_ASIO_SYNC_DISPATCH 13 | #define ST_ASIO_INPUT_QUEUE non_lock_queue 14 | #define ST_ASIO_OUTPUT_QUEUE non_lock_queue 15 | #endif 16 | #define ST_ASIO_DECREASE_THREAD_AT_RUNTIME 17 | //configuration 18 | 19 | #include "../include/ext/tcp.h" 20 | using namespace st_asio_wrapper; 21 | //using namespace st_asio_wrapper::tcp; 22 | using namespace st_asio_wrapper::ext::tcp; 23 | 24 | #define QUIT_COMMAND "quit" 25 | #define STATUS "status" 26 | #define STATISTIC "statistic" 27 | #define LIST_ALL_CLIENT "list all client" 28 | #define INCREASE_THREAD "increase thread" 29 | #define DECREASE_THREAD "decrease thread" 30 | 31 | class echo_socket : public server_socket 32 | { 33 | public: 34 | echo_socket(st_asio_wrapper::tcp::i_server& server_) : server_socket(server_) {unpacker()->stripped(false);} 35 | //other heavy things can be done in the constructor too, because we pre-created ST_ASIO_ASYNC_ACCEPT_NUM echo_socket objects 36 | 37 | protected: 38 | //msg handling 39 | #ifdef ST_ASIO_SYNC_DISPATCH 40 | virtual size_t on_msg(list& msg_can) 41 | { 42 | for (BOOST_AUTO(iter, msg_can.begin()); iter != msg_can.end(); ++iter) direct_send_msg(*iter, true); 43 | msg_can.clear(); 44 | 45 | return 1; 46 | } 47 | #endif 48 | #ifdef ST_ASIO_DISPATCH_BATCH_MSG 49 | virtual size_t on_msg_handle(out_queue_type& msg_can) 50 | { 51 | assert(!msg_can.empty()); 52 | out_container_type tmp_can; 53 | msg_can.swap(tmp_can); 54 | 55 | for (BOOST_AUTO(iter, tmp_can.begin()); iter != tmp_can.end(); ++iter) direct_send_msg(*iter, true); 56 | return tmp_can.size(); 57 | } 58 | #else 59 | virtual bool on_msg_handle(out_msg_type& msg) {direct_send_msg(msg, true); return true;} 60 | #endif 61 | //msg handling end 62 | }; 63 | 64 | class echo_server : public st_asio_wrapper::tcp::server_base 65 | { 66 | public: 67 | echo_server(service_pump& service_pump_) : server_base(service_pump_) {} 68 | 69 | protected: 70 | virtual bool on_accept(object_ctype& socket_ptr) {boost::asio::ip::tcp::no_delay option(true); socket_ptr->lowest_layer().set_option(option); return true;} 71 | virtual void start_next_accept() 72 | { 73 | //after we accepted ST_ASIO_ASYNC_ACCEPT_NUM - 10 connections, we start to create new echo_socket objects (one echo_socket per one accepting) 74 | if (size() + 10 >= ST_ASIO_ASYNC_ACCEPT_NUM) //only left 10 async accepting operations 75 | server_base::start_next_accept(); 76 | else 77 | puts("stopped one async accepting."); 78 | } 79 | }; 80 | 81 | int main(int argc, const char* argv[]) 82 | { 83 | printf("usage: %s [ [ [ip=0.0.0.0]]]\n", argv[0], ST_ASIO_SERVER_PORT); 84 | if (argc >= 2 && (0 == strcmp(argv[1], "--help") || 0 == strcmp(argv[1], "-h"))) 85 | return 0; 86 | else 87 | puts("type " QUIT_COMMAND " to end."); 88 | 89 | service_pump sp; 90 | echo_server echo_server_(sp); 91 | 92 | if (argc > 3) 93 | echo_server_.set_server_addr(atoi(argv[2]), argv[3]); 94 | else if (argc > 2) 95 | echo_server_.set_server_addr(atoi(argv[2])); 96 | 97 | int thread_num = 1; 98 | if (argc > 1) 99 | thread_num = std::min(16, std::max(thread_num, atoi(argv[1]))); 100 | 101 | sp.start_service(thread_num); 102 | while(sp.is_running()) 103 | { 104 | std::string str; 105 | std::getline(std::cin, str); 106 | if (str.empty()) 107 | ; 108 | else if (QUIT_COMMAND == str) 109 | sp.stop_service(); 110 | else if (STATISTIC == str) 111 | { 112 | printf("link #: " ST_ASIO_SF ", invalid links: " ST_ASIO_SF "\n\n", echo_server_.size(), echo_server_.invalid_object_size()); 113 | puts(echo_server_.get_statistic().to_string().data()); 114 | } 115 | else if (STATUS == str) 116 | echo_server_.list_all_status(); 117 | else if (LIST_ALL_CLIENT == str) 118 | echo_server_.list_all_object(); 119 | else if (INCREASE_THREAD == str) 120 | sp.add_service_thread(1); 121 | else if (DECREASE_THREAD == str) 122 | sp.del_service_thread(1); 123 | } 124 | 125 | return 0; 126 | } 127 | -------------------------------------------------------------------------------- /concurrent_server/concurrent_server.vcproj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngwolf-project/st_asio_wrapper/3e060755ca6a8fc2ebfed8ccc41c561ad783a211/concurrent_server/concurrent_server.vcproj -------------------------------------------------------------------------------- /concurrent_server/makefile: -------------------------------------------------------------------------------- 1 | 2 | module = concurrent_server 3 | 4 | include ../config.mk 5 | 6 | -------------------------------------------------------------------------------- /config.mk: -------------------------------------------------------------------------------- 1 | 2 | # If your compiler cannot find boost, please specify it explicitly like this: 3 | #boost_include_dir = -I/usr/local/include/ 4 | #boost_lib_dir = -L/usr/local/lib/ 5 | 6 | ifeq (, ${STD}) 7 | STD = c++98 8 | endif 9 | 10 | cflag = -Wall -fexceptions -std=${STD} 11 | ifeq (${MAKECMDGOALS}, debug) 12 | cflag += -g -DDEBUG 13 | dir = debug 14 | else 15 | cflag += -O2 -DNDEBUG 16 | lflag = -s 17 | dir = release 18 | endif 19 | cflag += -DBOOST_ASIO_NO_DEPRECATED -DBOOST_CHRONO_HEADER_ONLY 20 | common_libs = -lboost_system -lboost_thread 21 | 22 | target_machine = ${shell ${CXX} -dumpmachine} 23 | ifneq (, ${findstring solaris, ${target_machine}}) 24 | cflag += -pthreads 25 | lflag += -pthreads -lsocket -lnsl 26 | else 27 | cflag += -pthread 28 | lflag += -pthread 29 | ifneq (, ${findstring freebsd, ${target_machine}}) 30 | common_libs += -lboost_atomic 31 | #here maybe still have other machines need to be separated out 32 | endif 33 | endif 34 | 35 | cflag += ${ext_cflag} ${boost_include_dir} 36 | lflag += ${boost_lib_dir} ${common_libs} ${ext_libs} 37 | 38 | target = ${dir}/${module} 39 | objects = ${patsubst %.cpp,${dir}/%.o,${wildcard *.cpp}} 40 | deps = ${patsubst %.o,%.d,${objects}} 41 | ${shell mkdir -p ${dir}} 42 | 43 | release debug : ${target} 44 | -include ${deps} 45 | ${target} : ${objects} 46 | ${CXX} -o $@ $^ ${lflag} 47 | ${objects} : ${dir}/%.o : %.cpp 48 | ${CXX} ${cflag} -E -MMD -w -MT '$@' -MF ${patsubst %.cpp,%.d,${dir}/$<} $< 1>/dev/null 49 | ${CXX} ${cflag} -c $< -o $@ 50 | 51 | .PHONY : clean 52 | clean: 53 | -rm -rf debug release 54 | 55 | -------------------------------------------------------------------------------- /doc/overall: -------------------------------------------------------------------------------- 1 |  2 | 所有宏都在原来的基本上增加了前辍ST_ASIO_,除了: 3 | RE_CONNECT_INTERVAL被改成了ST_ASIO_RECONNECT_INTERVAL 4 | ST_SERVICE_THREAD_NUM被改成了ST_ASIO_SERVICE_THREAD_NUM 5 | size_t_format被改成了ST_ASIO_SF 6 | 7 | 每个直接或者间接从timer继承的类中,都定义了TIMER_BEGIN和TIMER_END两个静态常量, 8 | 用户自定义定时器ID必须从父类的TIMER_END开始。 9 | 10 | 其它所有文档请参看ascs的开发文档,主要的不同点仅三个: 11 | 1. 最外层的命名空间是st_asio_wrapper而非ascs; 12 | 2. 类atomic仅在st_asio_wrapper中存在; 13 | 3. 类cpu_timer仅在ascs中存在; -------------------------------------------------------------------------------- /echo_client/echo_client.vcproj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngwolf-project/st_asio_wrapper/3e060755ca6a8fc2ebfed8ccc41c561ad783a211/echo_client/echo_client.vcproj -------------------------------------------------------------------------------- /echo_client/makefile: -------------------------------------------------------------------------------- 1 | 2 | module = echo_client 3 | ext_libs = -lboost_timer 4 | 5 | include ../config.mk 6 | 7 | -------------------------------------------------------------------------------- /echo_server/echo_server.vcproj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngwolf-project/st_asio_wrapper/3e060755ca6a8fc2ebfed8ccc41c561ad783a211/echo_server/echo_server.vcproj -------------------------------------------------------------------------------- /echo_server/makefile: -------------------------------------------------------------------------------- 1 | 2 | module = echo_server 3 | 4 | include ../config.mk 5 | 6 | -------------------------------------------------------------------------------- /file_client/file_client.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | //configuration 6 | #define ST_ASIO_SERVER_PORT 5051 7 | #define ST_ASIO_DELAY_CLOSE 5 //define this to avoid hooks for async call (and slightly improve performance) 8 | #define ST_ASIO_PASSIVE_RECV 9 | #ifndef ST_ASIO_DECREASE_THREAD_AT_RUNTIME 10 | #define ST_ASIO_AVOID_AUTO_STOP_SERVICE 11 | #endif 12 | #define ST_ASIO_RECV_BUFFER_TYPE std::vector //scatter-gather buffer, it's very useful under certain situations (for example, ring buffer). 13 | #define ST_ASIO_SCATTERED_RECV_BUFFER //used by unpackers, not belongs to st_asio_wrapper 14 | #define ST_ASIO_WANT_MSG_SEND_NOTIFY 15 | #define ST_ASIO_DEFAULT_PACKER packer2<> 16 | //configuration 17 | 18 | #include "file_client.h" 19 | 20 | #define QUIT_COMMAND "quit" 21 | #define RESTART_COMMAND "restart" 22 | #define STATUS "status" 23 | #define STATISTIC "statistic" 24 | #define LIST_ALL_CLIENT "list all client" 25 | #define GET_FILE "get" 26 | #define PUT_FILE "put" 27 | 28 | int link_num = 1; 29 | fl_type file_size; 30 | atomic_size transmit_size; 31 | 32 | void add_socket(file_client& client, int argc, const char* argv[]) 33 | { 34 | for (int i = 0; i < link_num; ++i) 35 | { 36 | // argv[2] = "::1" //ipv6 37 | // argv[2] = "127.0.0.1" //ipv4 38 | if (argc > 2) 39 | client.add_socket(atoi(argv[1]), argv[2])->set_index(i); 40 | else if (argc > 1) 41 | client.add_socket(atoi(argv[1]))->set_index(i); 42 | else 43 | client.add_socket()->set_index(i); 44 | } 45 | } 46 | 47 | int main(int argc, const char* argv[]) 48 | { 49 | puts("this is a file transmission client."); 50 | printf("usage: %s [ [ [link num=1]]]\n", argv[0], ST_ASIO_SERVER_PORT, ST_ASIO_SERVER_IP); 51 | if (argc >= 2 && (0 == strcmp(argv[1], "--help") || 0 == strcmp(argv[1], "-h"))) 52 | return 0; 53 | else 54 | puts("type " QUIT_COMMAND " to end."); 55 | 56 | service_pump sp; 57 | #ifndef ST_ASIO_DECREASE_THREAD_AT_RUNTIME 58 | //if you want to decrease service thread at runtime, then you cannot use multiple io_context, if somebody indeed needs it, please let me know. 59 | //with multiple io_context, the number of service thread must be bigger than or equal to the number of io_context, please note. 60 | //with multiple io_context, please also define macro ST_ASIO_AVOID_AUTO_STOP_SERVICE. 61 | sp.set_io_context_num(4); 62 | #endif 63 | file_client client(sp); 64 | 65 | if (argc > 3) 66 | link_num = std::min(256, std::max(atoi(argv[3]), 1)); //link number cannot exceed 500, because file_server's macro ST_ASIO_START_OBJECT_ID is defined as 500 67 | 68 | add_socket(client, argc, argv); 69 | 70 | sp.start_service(); 71 | while(sp.is_running()) 72 | { 73 | std::string str; 74 | std::getline(std::cin, str); 75 | if (str.empty()) 76 | ; 77 | else if (QUIT_COMMAND == str) 78 | sp.stop_service(); 79 | else if (RESTART_COMMAND == str) 80 | { 81 | sp.stop_service(); 82 | 83 | //add all clients back 84 | add_socket(client, argc, argv); 85 | sp.start_service(); 86 | } 87 | else if (STATISTIC == str) 88 | { 89 | printf("link #: " ST_ASIO_SF ", valid links: " ST_ASIO_SF ", invalid links: " ST_ASIO_SF "\n\n", client.size(), client.valid_size(), client.invalid_object_size()); 90 | puts(client.get_statistic().to_string().data()); 91 | } 92 | else if (STATUS == str) 93 | client.list_all_status(); 94 | else if (LIST_ALL_CLIENT == str) 95 | client.list_all_object(); 96 | else if (str.size() > sizeof(GET_FILE) && !strncmp(GET_FILE, str.data(), sizeof(GET_FILE) - 1) && isspace(str[sizeof(GET_FILE) - 1])) 97 | { 98 | str.erase(0, sizeof(GET_FILE)); 99 | 100 | boost::char_separator sep(" \t"); 101 | boost::tokenizer > tok(str, sep); 102 | 103 | boost::container::list file_list; 104 | for (BOOST_AUTO(iter, tok.begin()); iter != tok.end(); ++iter) 105 | file_list.push_back(*iter); 106 | 107 | client.get_file(file_list); 108 | } 109 | else if (str.size() > sizeof(PUT_FILE) && !strncmp(PUT_FILE, str.data(), sizeof(PUT_FILE) - 1) && isspace(str[sizeof(PUT_FILE) - 1])) 110 | { 111 | str.erase(0, sizeof(PUT_FILE)); 112 | 113 | boost::char_separator sep(" \t"); 114 | boost::tokenizer > tok(str, sep); 115 | 116 | boost::container::list file_list; 117 | for (BOOST_AUTO(iter, tok.begin()); iter != tok.end(); ++iter) 118 | file_list.push_back(*iter); 119 | 120 | client.put_file(file_list); 121 | } 122 | else 123 | client.at(0)->talk(str); 124 | } 125 | 126 | return 0; 127 | } 128 | -------------------------------------------------------------------------------- /file_client/file_client.vcproj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngwolf-project/st_asio_wrapper/3e060755ca6a8fc2ebfed8ccc41c561ad783a211/file_client/file_client.vcproj -------------------------------------------------------------------------------- /file_client/makefile: -------------------------------------------------------------------------------- 1 | 2 | module = file_client 3 | ext_cflag = -D_FILE_OFFSET_BITS=64 4 | ext_libs = -lboost_timer 5 | 6 | include ../config.mk 7 | 8 | -------------------------------------------------------------------------------- /file_common/common.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H_ 2 | #define COMMON_H_ 3 | 4 | #include 5 | 6 | #include "../include/base.h" 7 | using namespace st_asio_wrapper; 8 | //using namespace st_asio_wrapper::tcp; 9 | 10 | #ifdef _MSC_VER 11 | #define fseeko _fseeki64 12 | #define ftello _ftelli64 13 | #define fl_type __int64 14 | #else 15 | #define fl_type off_t 16 | #endif 17 | 18 | #if BOOST_VERSION >= 105300 19 | #define atomic_size boost::atomic_int_fast64_t 20 | #else 21 | #define atomic_size atomic 22 | #endif 23 | 24 | #define ORDER_LEN sizeof(char) 25 | #define OFFSET_LEN sizeof(fl_type) 26 | #define DATA_LEN OFFSET_LEN 27 | 28 | /* 29 | protocol: 30 | head(1 byte) + body 31 | 32 | if head equal to: 33 | 0: body is a filename 34 | request the file length, client->server->client 35 | return: same head + file length(8 bytes) 36 | 1: body is file offset(8 bytes) + data length(8 bytes) 37 | request the file content, client->server->client 38 | return: file content(no-protocol), repeat until all data requested by client been sent(client only need to request one time) 39 | 2: body is talk content 40 | talk, client->server. please note that server cannot talk to client, this is because server never knows whether 41 | it is going to transmit a file or not. 42 | return: na 43 | 3: body is object id(8 bytes) 44 | change file server's object ids, demonstrate how to use macro ST_ASIO_RESTORE_OBJECT. 45 | return: na 46 | 47 | 10:body is a filename 48 | request to create or truncate the file on the server, client->server->client 49 | return: same head + status(1 byte, 0 - success, !0 - failed) + filename 50 | 11:body is offset(8 bytes) + data length(8 bytes) + filename 51 | request to upload the file, client->server->client 52 | return: same head + data length(8 bytes) + status(1 byte, 0 - success, !0 - failed), then file content(no-protocol), repeat until all data been sent 53 | */ 54 | 55 | class base_socket 56 | { 57 | public: 58 | base_socket() : state(TRANS_IDLE), file(NULL) {} 59 | 60 | protected: 61 | enum TRANS_STATE {TRANS_IDLE, TRANS_PREPARE, TRANS_BUSY}; 62 | TRANS_STATE state; 63 | FILE* file; 64 | }; 65 | 66 | #endif // COMMON_H_ 67 | -------------------------------------------------------------------------------- /file_common/file_buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef FILE_BUFFER_H_ 2 | #define FILE_BUFFER_H_ 3 | 4 | #include "common.h" 5 | 6 | class file_buffer : public i_buffer, public boost::noncopyable 7 | { 8 | public: 9 | file_buffer(FILE* file, fl_type total_len_, atomic_size* transmit_size_ = NULL) : _file(file), total_len(total_len_), transmit_size(transmit_size_) 10 | { 11 | assert(NULL != _file); 12 | 13 | buffer = new char[boost::asio::detail::default_max_transfer_size]; 14 | assert(NULL != buffer); 15 | 16 | good = read(); 17 | } 18 | ~file_buffer() {delete[] buffer;} 19 | 20 | public: 21 | virtual bool empty() const {return 0 == data_len;} 22 | virtual size_t size() const {return data_len;} 23 | virtual const char* data() const {return buffer;} 24 | 25 | bool is_good() const {return good;} 26 | bool read() 27 | { 28 | if (total_len <= 0) 29 | data_len = 0; 30 | else 31 | { 32 | data_len = total_len > boost::asio::detail::default_max_transfer_size ? boost::asio::detail::default_max_transfer_size : (size_t) total_len; 33 | total_len -= data_len; 34 | if (data_len != fread(buffer, 1, data_len, _file)) 35 | { 36 | printf("fread(" ST_ASIO_SF ") error!\n", data_len); 37 | data_len = 0; 38 | 39 | return (good = false); 40 | } 41 | else if (NULL != transmit_size) 42 | *transmit_size += data_len; 43 | } 44 | 45 | return true; 46 | } 47 | 48 | protected: 49 | bool good; 50 | FILE* _file; 51 | char* buffer; 52 | size_t data_len; 53 | 54 | fl_type total_len; 55 | atomic_size* transmit_size; 56 | }; 57 | 58 | #endif //FILE_BUFFER_H_ 59 | -------------------------------------------------------------------------------- /file_common/unpacker.h: -------------------------------------------------------------------------------- 1 | #ifndef UNPACKER_H_ 2 | #define UNPACKER_H_ 3 | 4 | #include "common.h" 5 | 6 | class file_unpacker : public i_unpacker, public boost::noncopyable 7 | { 8 | public: 9 | file_unpacker(FILE* file, fl_type total_len_, atomic_size* transmit_size_ = NULL) : _file(file), total_len(total_len_), transmit_size(transmit_size_) 10 | { 11 | assert(NULL != _file); 12 | 13 | buffer = new char[boost::asio::detail::default_max_transfer_size]; 14 | assert(NULL != buffer); 15 | } 16 | ~file_unpacker() {delete[] buffer;} 17 | 18 | bool is_finished() const {return 0 == total_len;} 19 | 20 | virtual void reset() {_file = NULL; delete[] buffer; buffer = NULL; total_len = 0;} 21 | virtual bool parse_msg(size_t bytes_transferred, container_type& msg_can) 22 | { 23 | assert(total_len >= (fl_type) bytes_transferred && bytes_transferred > 0); 24 | 25 | total_len -= bytes_transferred; 26 | if (NULL != transmit_size) 27 | *transmit_size += bytes_transferred; 28 | 29 | if (bytes_transferred == fwrite(buffer, 1, bytes_transferred, _file)) 30 | return true; 31 | 32 | printf("fwrite(" ST_ASIO_SF ") error!\n", bytes_transferred); 33 | return false; 34 | } 35 | 36 | virtual size_t completion_condition(const boost::system::error_code& ec, size_t bytes_transferred) {return ec ? 0 : boost::asio::detail::default_max_transfer_size;} 37 | virtual buffer_type prepare_next_recv() 38 | { 39 | size_t data_len = total_len > boost::asio::detail::default_max_transfer_size ? boost::asio::detail::default_max_transfer_size : (size_t) total_len; 40 | #ifdef ST_ASIO_SCATTERED_RECV_BUFFER 41 | return buffer_type(1, boost::asio::buffer(buffer, data_len)); 42 | #else 43 | return boost::asio::buffer(buffer, data_len); 44 | #endif 45 | } 46 | 47 | protected: 48 | FILE* _file; 49 | char* buffer; 50 | 51 | fl_type total_len; 52 | atomic_size* transmit_size; 53 | }; 54 | 55 | #endif //UNPACKER_H_ 56 | -------------------------------------------------------------------------------- /file_server/file_server.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | //configuration 5 | #define ST_ASIO_DEFAULT_PACKER packer2<> 6 | //#define ST_ASIO_RECV_BUFFER_TYPE std::vector //scatter-gather buffer, it's very useful under certain situations (for example, ring buffer). 7 | //#define ST_ASIO_SCATTERED_RECV_BUFFER //used by unpackers, not belongs to st_asio_wrapper 8 | //note, these two macro are not requisite, I'm just showing how to use them. 9 | 10 | //all other definitions are in the makefile, because we have two cpp files, defining them in more than one place is risky ( 11 | // we may define them to different values between the two cpp files) 12 | //configuration 13 | 14 | #include "file_socket.h" 15 | 16 | #define QUIT_COMMAND "quit" 17 | #define RESTART_COMMAND "restart" 18 | #define STATUS "status" 19 | #define STATISTIC "statistic" 20 | #define LIST_ALL_CLIENT "list all client" 21 | 22 | #if !defined(_MSC_VER) && !defined(__MINGW64__) && !defined(__MINGW32__) 23 | void signal_handler(service_pump& sp, boost::asio::signal_set& signal_receiver, const boost::system::error_code& ec, int signal_number) 24 | { 25 | if (!ec) 26 | return sp.end_service(); 27 | 28 | signal_receiver.async_wait(boost::bind(&signal_handler, boost::ref(sp), boost::ref(signal_receiver), boost::placeholders::_1, boost::placeholders::_2)); 29 | } 30 | #endif 31 | 32 | int main(int argc, const char* argv[]) 33 | { 34 | puts("this is a file transmission server."); 35 | #if defined(_MSC_VER) || defined(__MINGW64__) || defined(__MINGW32__) 36 | printf("usage: %s [ [ip=0.0.0.0]]\n", argv[0], ST_ASIO_SERVER_PORT); 37 | #else 38 | printf("usage: %s [-d] [ [ip=0.0.0.0]]\n", argv[0], ST_ASIO_SERVER_PORT); 39 | #endif 40 | 41 | if (argc >= 2 && (0 == strcmp(argv[1], "--help") || 0 == strcmp(argv[1], "-h"))) 42 | return 0; 43 | else 44 | puts("type " QUIT_COMMAND " to end."); 45 | 46 | int index = 0; 47 | if (argc >= 2 && 0 == strcmp(argv[1], "-d")) 48 | { 49 | #if defined(_MSC_VER) || defined(__MINGW64__) || defined(__MINGW32__) 50 | puts("on windows, -d is not supported!"); 51 | return 1; 52 | #endif 53 | index = 1; 54 | } 55 | 56 | service_pump sp; 57 | #ifndef ST_ASIO_DECREASE_THREAD_AT_RUNTIME 58 | //if you want to decrease service thread at runtime, then you cannot use multiple io_context, if somebody indeed needs it, please let me know. 59 | //with multiple io_context, the number of service thread must be bigger than or equal to the number of io_context, please note. 60 | //with multiple io_context, please also define macro ST_ASIO_AVOID_AUTO_STOP_SERVICE. 61 | sp.set_io_context_num(8); 62 | #endif 63 | tcp::server_base file_server_(sp); 64 | 65 | if (argc > 2 + index) 66 | file_server_.set_server_addr(atoi(argv[1 + index]), argv[2 + index]); 67 | else if (argc > 1 + index) 68 | file_server_.set_server_addr(atoi(argv[1 + index])); 69 | 70 | #if !defined(_MSC_VER) && !defined(__MINGW64__) && !defined(__MINGW32__) 71 | if (1 == index) 72 | { 73 | boost::asio::signal_set signal_receiver(sp.assign_io_context(), SIGINT, SIGTERM); 74 | signal_receiver.async_wait(boost::bind(&signal_handler, boost::ref(sp), boost::ref(signal_receiver), boost::placeholders::_1, boost::placeholders::_2)); 75 | 76 | sp.run_service(); 77 | return 0; 78 | } 79 | #endif 80 | 81 | sp.start_service(); 82 | while(sp.is_running()) 83 | { 84 | std::string str; 85 | std::getline(std::cin, str); 86 | if (str.empty()) 87 | ; 88 | else if (QUIT_COMMAND == str) 89 | sp.stop_service(); 90 | else if (RESTART_COMMAND == str) 91 | { 92 | sp.stop_service(); 93 | sp.start_service(); 94 | } 95 | else if (STATISTIC == str) 96 | { 97 | printf("link #: " ST_ASIO_SF ", invalid links: " ST_ASIO_SF "\n\n", file_server_.size(), file_server_.invalid_object_size()); 98 | puts(file_server_.get_statistic().to_string().data()); 99 | } 100 | else if (STATUS == str) 101 | file_server_.list_all_status(); 102 | else if (LIST_ALL_CLIENT == str) 103 | file_server_.list_all_object(); 104 | } 105 | 106 | return 0; 107 | } 108 | -------------------------------------------------------------------------------- /file_server/file_server.vcproj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngwolf-project/st_asio_wrapper/3e060755ca6a8fc2ebfed8ccc41c561ad783a211/file_server/file_server.vcproj -------------------------------------------------------------------------------- /file_server/file_socket.cpp: -------------------------------------------------------------------------------- 1 | 2 | //configuration 3 | #define ST_ASIO_DEFAULT_PACKER packer2<> 4 | //#define ST_ASIO_RECV_BUFFER_TYPE std::vector //scatter-gather buffer, it's very useful under certain situations (for example, ring buffer). 5 | //#define ST_ASIO_SCATTERED_RECV_BUFFER //used by unpackers, not belongs to st_asio_wrapper 6 | //note, these two macro are not requisite, I'm just showing how to use them. 7 | 8 | //all other definitions are in the makefile, because we have two cpp files, defining them in more than one place is risky ( 9 | // we may define them to different values between the two cpp files) 10 | //configuration 11 | 12 | #include "../file_common/file_buffer.h" 13 | #include "../file_common/unpacker.h" 14 | 15 | #include "file_socket.h" 16 | 17 | file_socket::file_socket(tcp::i_server& server_) : server_socket(server_) {} 18 | file_socket::~file_socket() {clear();} 19 | 20 | void file_socket::reset() {trans_end(); server_socket::reset();} 21 | 22 | //socket_ptr actually is a pointer of file_socket, use boost::dynamic_pointer_cast to convert it. 23 | void file_socket::take_over(boost::shared_ptr socket_ptr) 24 | {printf("restore user data from invalid object (" ST_ASIO_LLF ").\n", socket_ptr->id());} 25 | //this works too, but brings warnings with -Woverloaded-virtual option. 26 | //void file_socket::take_over(boost::shared_ptr socket_ptr) {printf("restore user data from invalid object (" ST_ASIO_LLF ").\n", socket_ptr->id());} 27 | 28 | //msg handling 29 | bool file_socket::on_msg_handle(out_msg_type& msg) {handle_msg(msg); if (0 == get_pending_recv_msg_size()) recv_msg(); return true;} 30 | //msg handling end 31 | 32 | #ifdef ST_ASIO_WANT_MSG_SEND_NOTIFY 33 | void file_socket::on_msg_send(in_msg_type& msg) 34 | { 35 | file_buffer* buffer = dynamic_cast(&*msg.raw_buffer()); 36 | if (NULL != buffer) 37 | { 38 | if (!buffer->read()) 39 | trans_end(false); 40 | else if (buffer->empty()) 41 | { 42 | puts("file sending end successfully"); 43 | trans_end(false); 44 | } 45 | else 46 | direct_send_msg(msg, true); 47 | } 48 | } 49 | #endif 50 | 51 | void file_socket::clear() 52 | { 53 | if (NULL != file) 54 | { 55 | fclose(file); 56 | file = NULL; 57 | } 58 | } 59 | 60 | void file_socket::trans_end(bool reset_unpacker) 61 | { 62 | clear(); 63 | 64 | stop_timer(server_socket::TIMER_END); 65 | if (reset_unpacker) 66 | unpacker(boost::make_shared()); 67 | state = TRANS_IDLE; 68 | } 69 | 70 | void file_socket::handle_msg(out_msg_ctype& msg) 71 | { 72 | if (TRANS_BUSY == state) 73 | { 74 | assert(msg.empty()); 75 | 76 | BOOST_AUTO(unp, boost::dynamic_pointer_cast(unpacker())); 77 | if (!unp) 78 | trans_end(); 79 | else if (unp->is_finished()) 80 | { 81 | puts("file accepting end successfully"); 82 | trans_end(); 83 | } 84 | 85 | return; 86 | } 87 | else if (msg.size() <= ORDER_LEN) 88 | { 89 | printf("wrong order length: " ST_ASIO_SF ".\n", msg.size()); 90 | return; 91 | } 92 | 93 | switch (*msg.data()) 94 | { 95 | case 0: 96 | //let client control the life cycle of file transmission, so we don't care the state 97 | //avoid accessing the send queue concurrently, because we use non_lock_queue 98 | if (/*TRANS_IDLE == state && */!is_sending()) 99 | { 100 | trans_end(); 101 | 102 | char buffer[ORDER_LEN + DATA_LEN]; 103 | *buffer = 0; //head 104 | 105 | const char* file_name = boost::next(msg.data(), ORDER_LEN); 106 | printf("prepare to send file %s\n", file_name); 107 | file = fopen(file_name, "rb"); 108 | if (NULL != file) 109 | { 110 | fseeko(file, 0, SEEK_END); 111 | fl_type length = ftello(file); 112 | memcpy(boost::next(buffer, ORDER_LEN), &length, DATA_LEN); 113 | state = TRANS_PREPARE; 114 | } 115 | else 116 | { 117 | memset(boost::next(buffer, ORDER_LEN), -1, DATA_LEN); 118 | printf("can not open file %s!\n", file_name); 119 | } 120 | 121 | send_msg(buffer, sizeof(buffer), true); 122 | } 123 | break; 124 | case 1: 125 | if (TRANS_PREPARE == state && NULL != file && ORDER_LEN + OFFSET_LEN + DATA_LEN == msg.size()) 126 | { 127 | fl_type offset; 128 | memcpy(&offset, boost::next(msg.data(), ORDER_LEN), OFFSET_LEN); 129 | fl_type length; 130 | memcpy(&length, boost::next(msg.data(), ORDER_LEN + OFFSET_LEN), DATA_LEN); 131 | if (offset >= 0 && length > 0 && offset + length <= ftello(file)) 132 | { 133 | printf("start to send the file from " ST_ASIO_LLF " with length " ST_ASIO_LLF "\n", offset, length); 134 | 135 | state = TRANS_BUSY; 136 | fseeko(file, offset, SEEK_SET); 137 | BOOST_AUTO(buffer, new file_buffer(file, length)); 138 | if (buffer->is_good()) 139 | { 140 | in_msg_type msg(buffer); 141 | direct_send_msg(msg, true); 142 | } 143 | else 144 | { 145 | delete buffer; 146 | trans_end(); 147 | } 148 | } 149 | else 150 | trans_end(); 151 | } 152 | break; 153 | case 10: 154 | //let client control the life cycle of file transmission, so we don't care the state 155 | //avoid accessing the send queue concurrently, because we use non_lock_queue 156 | if (/*TRANS_IDLE == state && */!is_sending()) 157 | { 158 | trans_end(); 159 | 160 | std::string order(ORDER_LEN, (char) 10); 161 | const char* file_name = boost::next(msg.data(), ORDER_LEN); 162 | file = fopen(file_name, "w+b"); 163 | if (NULL != file) 164 | { 165 | clear(); 166 | 167 | order += '\0'; 168 | printf("file %s been created or truncated\n", file_name); 169 | } 170 | else 171 | { 172 | order += '\1'; 173 | printf("can not create or truncate file %s!\n", file_name); 174 | } 175 | order += file_name; 176 | 177 | send_msg(order, true); 178 | } 179 | break; 180 | case 11: 181 | //let client control the life cycle of file transmission, so we don't care the state 182 | //avoid accessing the send queue concurrently, because we use non_lock_queue 183 | if (/*TRANS_IDLE == state && */msg.size() > ORDER_LEN + OFFSET_LEN + DATA_LEN && !is_sending()) 184 | { 185 | trans_end(); 186 | 187 | fl_type offset; 188 | memcpy(&offset, boost::next(msg.data(), ORDER_LEN), OFFSET_LEN); 189 | fl_type length; 190 | memcpy(&length, boost::next(msg.data(), ORDER_LEN + OFFSET_LEN), DATA_LEN); 191 | 192 | char buffer[ORDER_LEN + DATA_LEN + 1]; 193 | *buffer = 11; //head 194 | memcpy(boost::next(buffer, ORDER_LEN), &length, DATA_LEN); 195 | 196 | const char* file_name = boost::next(msg.data(), ORDER_LEN + OFFSET_LEN + DATA_LEN); 197 | file = fopen(file_name, "r+b"); 198 | if (NULL == file) 199 | { 200 | printf("can not open file %s\n", file_name); 201 | *boost::next(buffer, ORDER_LEN + DATA_LEN) = '\1'; 202 | } 203 | else 204 | { 205 | printf("start to accept file %s from " ST_ASIO_LLF " with length " ST_ASIO_LLF "\n", file_name, offset, length); 206 | *boost::next(buffer, ORDER_LEN + DATA_LEN) = '\0'; 207 | 208 | state = TRANS_BUSY; 209 | fseeko(file, offset, SEEK_SET); 210 | unpacker(boost::make_shared(file, length)); //replace the unpacker first, then response put file request 211 | } 212 | 213 | send_msg(buffer, sizeof(buffer), true); 214 | } 215 | break; 216 | case 2: 217 | printf("client says: %s\n", boost::next(msg.data(), ORDER_LEN)); 218 | break; 219 | case 3: 220 | if (ORDER_LEN + sizeof(boost::uint_fast64_t) == msg.size()) 221 | { 222 | boost::uint_fast64_t id; 223 | memcpy(&id, boost::next(msg.data(), ORDER_LEN), sizeof(boost::uint_fast64_t)); 224 | if (!get_server().restore_socket(ST_THIS shared_from_this(), id, false)) //client restores the peer socket on the server 225 | get_server().restore_socket(ST_THIS shared_from_this(), id, true); //client controls the id of peer socket on the server 226 | //although you always want socket restoration, you must set the id of peer socket for the first time 227 | } 228 | default: 229 | break; 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /file_server/file_socket.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef FILE_SOCKET_H_ 3 | #define FILE_SOCKET_H_ 4 | 5 | #include "../include/ext/tcp.h" 6 | //using namespace st_asio_wrapper::tcp; 7 | using namespace st_asio_wrapper::ext::tcp; 8 | 9 | #include "../file_common/common.h" 10 | 11 | class file_socket : public base_socket, public server_socket 12 | { 13 | public: 14 | file_socket(tcp::i_server& server_); 15 | virtual ~file_socket(); 16 | 17 | public: 18 | //because we don't use objects pool(we don't defined ST_ASIO_REUSE_OBJECT), so this virtual function will 19 | //not be invoked, and can be omitted, but we keep it for the possibility of using it in the future 20 | virtual void reset(); 21 | virtual void take_over(boost::shared_ptr socket_ptr); //move socket_ptr into this socket 22 | // virtual void take_over(boost::shared_ptr socket_ptr); //this works too, but brings warnings with -Woverloaded-virtual option. 23 | 24 | protected: 25 | //msg handling 26 | virtual bool on_msg_handle(out_msg_type& msg); 27 | //msg handling end 28 | 29 | #ifdef ST_ASIO_WANT_MSG_SEND_NOTIFY 30 | virtual void on_msg_send(in_msg_type& msg); 31 | #endif 32 | 33 | private: 34 | void clear(); 35 | void trans_end(bool reset_unpacker = true); 36 | void handle_msg(out_msg_ctype& msg); 37 | }; 38 | 39 | #endif //#ifndef FILE_SOCKET_H_ 40 | -------------------------------------------------------------------------------- /file_server/makefile: -------------------------------------------------------------------------------- 1 | 2 | module = file_server 3 | ext_cflag = -DST_ASIO_RESTORE_OBJECT -DST_ASIO_SERVER_PORT=5051 -DST_ASIO_START_OBJECT_ID=500 -DST_ASIO_PASSIVE_RECV -DST_ASIO_WANT_MSG_SEND_NOTIFY -DST_ASIO_AVOID_AUTO_STOP_SERVICE -DST_ASIO_INPUT_QUEUE=non_lock_queue 4 | ext_cflag += -DST_ASIO_RECV_BUFFER_TYPE=std::vector\ -DST_ASIO_SCATTERED_RECV_BUFFER -D_FILE_OFFSET_BITS=64 5 | 6 | include ../config.mk 7 | 8 | -------------------------------------------------------------------------------- /include/container.h: -------------------------------------------------------------------------------- 1 | /* 2 | * container.h 3 | * 4 | * Created on: 2016-10-12 5 | * Author: youngwolf 6 | * email: mail2tao@163.com 7 | * QQ: 676218192 8 | * Community on QQ: 198941541 9 | * 10 | * containers. 11 | */ 12 | 13 | #ifndef ST_ASIO_CONTAINER_H_ 14 | #define ST_ASIO_CONTAINER_H_ 15 | 16 | #include "base.h" 17 | 18 | namespace st_asio_wrapper 19 | { 20 | 21 | class dummy_lockable 22 | { 23 | public: 24 | typedef boost::lock_guard lock_guard; 25 | 26 | //lockable, dummy 27 | bool is_lockable() const {return false;} 28 | void lock() const {} 29 | void unlock() const {} 30 | }; 31 | 32 | class lockable 33 | { 34 | public: 35 | typedef boost::lock_guard lock_guard; 36 | 37 | //lockable 38 | bool is_lockable() const {return true;} 39 | void lock() {mutex.lock();} 40 | void unlock() {mutex.unlock();} 41 | 42 | private: 43 | boost::mutex mutex; //boost::mutex is more efficient than boost::shared_mutex 44 | }; 45 | 46 | //Container must at least has the following functions (like boost::container::list): 47 | // Container() constructor 48 | // empty 49 | // clear 50 | // swap 51 | // emplace_back(), must return the reference of the new item 52 | // emplace_front(), must return the reference of the new item 53 | // splice(iter, Container&) 54 | // splice(iter, Container&, iter, iter) 55 | // front 56 | // pop_front 57 | // back 58 | // begin 59 | // end 60 | template //thread safety depends on Container or Lockable 61 | class queue : private Container, public Lockable 62 | { 63 | public: 64 | typedef typename Container::value_type value_type; 65 | typedef typename Container::size_type size_type; 66 | typedef typename Container::reference reference; 67 | typedef typename Container::const_reference const_reference; 68 | //since boost::container::list::size() has constant complexity, we expose this size() function, st_asio_wrapper will not use this function. 69 | using Container::size; 70 | 71 | queue() : total_size(0) {} 72 | 73 | //thread safe 74 | bool is_thread_safe() const {return Lockable::is_lockable();} 75 | size_t size_in_byte() const {return total_size;} 76 | #ifdef ST_ASIO_CAN_EMPTY_NOT_SAFE //container's empty() function is not thread safe 77 | bool empty() {typename Lockable::lock_guard lock(*this); return Container::empty();} 78 | #else 79 | using Container::empty; //almost all implementations of list::empty() in the world are thread safe (not means correctness, but just no memory access violation) 80 | #endif 81 | void clear() {typename Lockable::lock_guard lock(*this); Container::clear(); total_size = 0;} 82 | void swap(Container& can) 83 | { 84 | size_t size_in_byte = st_asio_wrapper::get_size_in_byte(can); 85 | 86 | typename Lockable::lock_guard lock(*this); 87 | Container::swap(can); 88 | total_size = size_in_byte; 89 | } 90 | 91 | template bool enqueue(const T& item) {typename Lockable::lock_guard lock(*this); return enqueue_(item);} 92 | template bool enqueue(T& item) {typename Lockable::lock_guard lock(*this); return enqueue_(item);} 93 | void move_items_in(Container& src, size_t size_in_byte = 0) {typename Lockable::lock_guard lock(*this); move_items_in_(src, size_in_byte);} 94 | template bool enqueue_front(const T& item) {typename Lockable::lock_guard lock(*this); return enqueue_front_(item);} 95 | template bool enqueue_front(T& item) {typename Lockable::lock_guard lock(*this); return enqueue_front_(item);} 96 | void move_items_in_front(Container& src, size_t size_in_byte = 0) {typename Lockable::lock_guard lock(*this); move_items_in_front_(src, size_in_byte);} 97 | bool try_dequeue(reference item) {typename Lockable::lock_guard lock(*this); return try_dequeue_(item);} 98 | void move_items_out(Container& dest, size_t max_item_num = -1) {typename Lockable::lock_guard lock(*this); move_items_out_(dest, max_item_num);} 99 | void move_items_out(size_t max_size_in_byte, Container& dest) {typename Lockable::lock_guard lock(*this); move_items_out_(max_size_in_byte, dest);} 100 | template void do_something_to_all(const _Predicate& __pred) {typename Lockable::lock_guard lock(*this); do_something_to_all_(__pred);} 101 | template void do_something_to_one(const _Predicate& __pred) {typename Lockable::lock_guard lock(*this); do_something_to_one_(__pred);} 102 | //thread safe 103 | 104 | //not thread safe 105 | template bool enqueue_(const T& item) 106 | { 107 | try 108 | { 109 | ST_THIS emplace_back(item); 110 | total_size += item.size(); 111 | } 112 | catch (const std::exception& e) 113 | { 114 | unified_out::error_out("cannot hold more objects (%s)", e.what()); 115 | return false; 116 | } 117 | 118 | return true; 119 | } 120 | 121 | template bool enqueue_(T& item) //after this, item will becomes empty, please note. 122 | { 123 | try 124 | { 125 | size_t size = item.size(); 126 | ST_THIS emplace_back().swap(item); //with c++0x, this can be emplace_back(item) 127 | total_size += size; 128 | } 129 | catch (const std::exception& e) 130 | { 131 | unified_out::error_out("cannot hold more objects (%s)", e.what()); 132 | return false; 133 | } 134 | 135 | return true; 136 | } 137 | 138 | void move_items_in_(Container& src, size_t size_in_byte = 0) 139 | { 140 | if (0 == size_in_byte) 141 | size_in_byte = st_asio_wrapper::get_size_in_byte(src); 142 | else 143 | assert(st_asio_wrapper::get_size_in_byte(src) == size_in_byte); 144 | 145 | ST_THIS splice(ST_THIS end(), src); 146 | total_size += size_in_byte; 147 | } 148 | 149 | template bool enqueue_front_(const T& item) 150 | { 151 | try 152 | { 153 | ST_THIS emplace_front(item); 154 | total_size += item.size(); 155 | } 156 | catch (const std::exception& e) 157 | { 158 | unified_out::error_out("cannot hold more objects (%s)", e.what()); 159 | return false; 160 | } 161 | 162 | return true; 163 | } 164 | 165 | template bool enqueue_front_(T& item) //after this, item will becomes empty, please note. 166 | { 167 | try 168 | { 169 | size_t size = item.size(); 170 | ST_THIS emplace_front().swap(item); //with c++0x, this can be emplace_back(item) 171 | total_size += size; 172 | } 173 | catch (const std::exception& e) 174 | { 175 | unified_out::error_out("cannot hold more objects (%s)", e.what()); 176 | return false; 177 | } 178 | 179 | return true; 180 | } 181 | 182 | void move_items_in_front_(Container& src, size_t size_in_byte = 0) 183 | { 184 | if (0 == size_in_byte) 185 | size_in_byte = st_asio_wrapper::get_size_in_byte(src); 186 | else 187 | assert(st_asio_wrapper::get_size_in_byte(src) == size_in_byte); 188 | 189 | ST_THIS splice(ST_THIS begin(), src); 190 | total_size += size_in_byte; 191 | } 192 | 193 | bool try_dequeue_(reference item) {if (Container::empty()) return false; item.swap(ST_THIS front()); ST_THIS pop_front(); total_size -= item.size(); return true;} 194 | 195 | void move_items_out_(Container& dest, size_t max_item_num = -1) 196 | { 197 | if ((size_t) -1 == max_item_num) 198 | { 199 | dest.splice(dest.end(), *this); 200 | total_size = 0; 201 | } 202 | else if (max_item_num > 0) 203 | { 204 | size_t size = 0, index = 0; 205 | BOOST_AUTO(end_iter, ST_THIS begin()); 206 | for (; end_iter != ST_THIS end() && index++ < max_item_num; ++end_iter) 207 | size += end_iter->size(); 208 | 209 | move_items_out(dest, end_iter, size); 210 | } 211 | } 212 | 213 | void move_items_out_(size_t max_size_in_byte, Container& dest) 214 | { 215 | if ((size_t) -1 == max_size_in_byte) 216 | move_items_out_(dest); 217 | else 218 | { 219 | size_t size = 0; 220 | BOOST_AUTO(end_iter, ST_THIS begin()); 221 | while (end_iter != ST_THIS end()) 222 | { 223 | size += end_iter++->size(); 224 | if (size >= max_size_in_byte) 225 | break; 226 | } 227 | 228 | move_items_out(dest, end_iter, size); 229 | } 230 | } 231 | 232 | template 233 | void do_something_to_all_(const _Predicate& __pred) {for (BOOST_AUTO(iter, ST_THIS begin()); iter != ST_THIS end(); ++iter) __pred(*iter);} 234 | template 235 | void do_something_to_all_(const _Predicate& __pred) const {for (BOOST_AUTO(iter, ST_THIS begin()); iter != ST_THIS end(); ++iter) __pred(*iter);} 236 | 237 | template 238 | void do_something_to_one_(const _Predicate& __pred) {for (BOOST_AUTO(iter, ST_THIS begin()); iter != ST_THIS end(); ++iter) if (__pred(*iter)) break;} 239 | template 240 | void do_something_to_one_(const _Predicate& __pred) const {for (BOOST_AUTO(iter, ST_THIS begin()); iter != ST_THIS end(); ++iter) if (__pred(*iter)) break;} 241 | //not thread safe 242 | 243 | protected: 244 | void move_items_out(Container& dest, typename Container::const_iterator end_iter, size_t size) 245 | { 246 | if (end_iter == ST_THIS end()) 247 | dest.splice(dest.end(), *this); 248 | else 249 | dest.splice(dest.end(), *this, ST_THIS begin(), end_iter); 250 | 251 | total_size -= size; 252 | } 253 | 254 | private: 255 | size_t total_size; 256 | }; 257 | 258 | //st_asio_wrapper requires that queue must take one and only one template argument 259 | template class non_lock_queue : public queue //thread safety depends on Container 260 | { 261 | public: 262 | non_lock_queue() {} 263 | non_lock_queue(size_t capacity) : queue(capacity) {} 264 | }; 265 | template class lock_queue : public queue 266 | { 267 | public: 268 | lock_queue() {} 269 | lock_queue(size_t capacity) : queue(capacity) {} 270 | }; 271 | 272 | } //namespace 273 | 274 | #endif /* ST_ASIO_CONTAINER_H_ */ 275 | -------------------------------------------------------------------------------- /include/executor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * executor.h 3 | * 4 | * Created on: 2016-6-11 5 | * Author: youngwolf 6 | * email: mail2tao@163.com 7 | * QQ: 676218192 8 | * Community on QQ: 198941541 9 | * 10 | * the top class 11 | */ 12 | 13 | #ifndef _ST_ASIO_EXECUTOR_H_ 14 | #define _ST_ASIO_EXECUTOR_H_ 15 | 16 | #include 17 | 18 | #include 19 | 20 | #include "config.h" 21 | 22 | namespace st_asio_wrapper 23 | { 24 | 25 | class executor 26 | { 27 | protected: 28 | virtual ~executor() {} 29 | executor(boost::asio::io_context& _io_context_) : io_context_(_io_context_) {} 30 | 31 | public: 32 | bool stopped() const {return io_context_.stopped();} 33 | 34 | #if BOOST_ASIO_VERSION >= 101100 35 | template void post(const F& handler) {boost::asio::post(io_context_, handler);} 36 | template void defer(const F& handler) {boost::asio::defer(io_context_, handler);} 37 | template void dispatch(const F& handler) {boost::asio::dispatch(io_context_, handler);} 38 | template void post_strand(boost::asio::io_context::strand& strand, const F& handler) {boost::asio::post(strand, handler);} 39 | template void defer_strand(boost::asio::io_context::strand& strand, const F& handler) {boost::asio::defer(strand, handler);} 40 | template void dispatch_strand(boost::asio::io_context::strand& strand, const F& handler) {boost::asio::dispatch(strand, handler);} 41 | #else 42 | template void post(const F& handler) {io_context_.post(handler);} 43 | template void dispatch(const F& handler) {io_context_.dispatch(handler);} 44 | template void post_strand(boost::asio::io_context::strand& strand, const F& handler) {strand.post(handler);} 45 | template void dispatch_strand(boost::asio::io_context::strand& strand, const F& handler) {strand.dispatch(handler);} 46 | #endif 47 | 48 | template inline const F& make_handler_error(const F& f) const {return f;} 49 | template inline const F& make_handler_error_size(const F& f) const {return f;} 50 | 51 | protected: 52 | boost::asio::io_context& io_context_; 53 | }; 54 | 55 | } //namespace 56 | 57 | #endif /* _ST_ASIO_EXECUTOR_H_ */ 58 | -------------------------------------------------------------------------------- /include/ext/client.h: -------------------------------------------------------------------------------- 1 | //just for compatiblity 2 | #include "tcp.h" 3 | -------------------------------------------------------------------------------- /include/ext/reliable_udp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * reliable_udp.h 3 | * 4 | * Created on: 2021-9-3 5 | * Author: youngwolf 6 | * email: mail2tao@163.com 7 | * QQ: 676218192 8 | * Community on QQ: 198941541 9 | * 10 | * reliable udp related conveniences. 11 | */ 12 | 13 | #ifndef ST_ASIO_EXT_RELIABLE_UDP_H_ 14 | #define ST_ASIO_EXT_RELIABLE_UDP_H_ 15 | 16 | #include "packer.h" 17 | #include "unpacker.h" 18 | #include "../udp/reliable_socket.h" 19 | #include "../udp/socket_service.h" 20 | #include "../single_service_pump.h" 21 | 22 | #ifndef ST_ASIO_DEFAULT_PACKER 23 | #define ST_ASIO_DEFAULT_PACKER st_asio_wrapper::ext::packer<> 24 | #endif 25 | 26 | #ifndef ST_ASIO_DEFAULT_UDP_UNPACKER 27 | #define ST_ASIO_DEFAULT_UDP_UNPACKER st_asio_wrapper::ext::udp_unpacker 28 | #endif 29 | 30 | namespace st_asio_wrapper { namespace ext { namespace udp { 31 | 32 | typedef st_asio_wrapper::udp::reliable_socket_base reliable_socket; 33 | template 34 | class reliable_socket2 : public st_asio_wrapper::udp::reliable_socket_base 35 | { 36 | private: 37 | typedef st_asio_wrapper::udp::reliable_socket_base super; 38 | 39 | public: 40 | reliable_socket2(boost::asio::io_context& io_context_) : super(io_context_) {} 41 | reliable_socket2(Matrix& matrix_) : super(matrix_) {} 42 | }; 43 | typedef st_asio_wrapper::udp::single_socket_service_base single_reliable_socket_service; 44 | typedef st_asio_wrapper::udp::multi_socket_service_base multi_reliable_socket_service; 45 | template 46 | class multi_reliable_socket_service2 : public st_asio_wrapper::udp::multi_socket_service_base, Matrix> 47 | { 48 | private: 49 | typedef st_asio_wrapper::udp::multi_socket_service_base, Matrix> super; 50 | 51 | public: 52 | multi_reliable_socket_service2(service_pump& service_pump_) : super(service_pump_) {} 53 | }; 54 | typedef multi_reliable_socket_service reliable_socket_service; 55 | 56 | }}} //namespace 57 | 58 | #endif /* ST_ASIO_EXT_RELIABLE_UDP_H_ */ 59 | -------------------------------------------------------------------------------- /include/ext/server.h: -------------------------------------------------------------------------------- 1 | //just for compatiblity 2 | #include "tcp.h" 3 | -------------------------------------------------------------------------------- /include/ext/ssl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ssl.h 3 | * 4 | * Created on: 2016-7-30 5 | * Author: youngwolf 6 | * email: mail2tao@163.com 7 | * QQ: 676218192 8 | * Community on QQ: 198941541 9 | * 10 | * ssl related conveniences. 11 | */ 12 | 13 | #ifndef ST_ASIO_EXT_SSL_H_ 14 | #define ST_ASIO_EXT_SSL_H_ 15 | 16 | #include "packer.h" 17 | #include "unpacker.h" 18 | #include "../tcp/ssl/ssl.h" 19 | #include "../single_service_pump.h" 20 | 21 | #ifndef ST_ASIO_DEFAULT_PACKER 22 | #define ST_ASIO_DEFAULT_PACKER st_asio_wrapper::ext::packer<> 23 | #endif 24 | 25 | #ifndef ST_ASIO_DEFAULT_UNPACKER 26 | #define ST_ASIO_DEFAULT_UNPACKER st_asio_wrapper::ext::unpacker<> 27 | #endif 28 | 29 | namespace st_asio_wrapper { namespace ext { namespace ssl { 30 | 31 | typedef st_asio_wrapper::ssl::client_socket_base client_socket; 32 | template 33 | class client_socket2 : public st_asio_wrapper::ssl::client_socket_base 34 | { 35 | private: 36 | typedef st_asio_wrapper::ssl::client_socket_base super; 37 | 38 | public: 39 | client_socket2(boost::asio::io_context& io_context_, boost::asio::ssl::context& ctx_) : super(io_context_, ctx_) {} 40 | client_socket2(Matrix& matrix_, boost::asio::ssl::context& ctx_) : super(matrix_, ctx_) {} 41 | }; 42 | typedef client_socket connector; 43 | typedef st_asio_wrapper::ssl::single_client_base single_client; 44 | typedef st_asio_wrapper::ssl::multi_client_base multi_client; 45 | template 46 | class multi_client2 : public st_asio_wrapper::ssl::multi_client_base, Matrix> 47 | { 48 | private: 49 | typedef st_asio_wrapper::ssl::multi_client_base, Matrix> super; 50 | 51 | public: 52 | multi_client2(service_pump& service_pump_, const boost::asio::ssl::context::method& m) : super(service_pump_, m) {} 53 | }; 54 | typedef multi_client client; 55 | 56 | typedef st_asio_wrapper::ssl::server_socket_base server_socket; 57 | template 58 | class server_socket2 : public st_asio_wrapper::ssl::server_socket_base 59 | { 60 | private: 61 | typedef st_asio_wrapper::ssl::server_socket_base super; 62 | 63 | public: 64 | server_socket2(Server& server_, boost::asio::ssl::context& ctx) : super(server_, ctx) {} 65 | }; 66 | typedef st_asio_wrapper::ssl::server_base server; 67 | template 68 | class server2 : public st_asio_wrapper::ssl::server_base, Server> 69 | { 70 | private: 71 | typedef st_asio_wrapper::ssl::server_base, Server> super; 72 | 73 | public: 74 | server2(service_pump& service_pump_, const boost::asio::ssl::context::method& m) : super(service_pump_, m) {} 75 | }; 76 | 77 | }}} //namespace 78 | 79 | #endif /* ST_ASIO_EXT_SSL_H_ */ 80 | -------------------------------------------------------------------------------- /include/ext/ssl_websocket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ssl_websocket.h 3 | * 4 | * Created on: 2022-6-9 5 | * Author: youngwolf 6 | * email: mail2tao@163.com 7 | * QQ: 676218192 8 | * Community on QQ: 198941541 9 | * 10 | * ssl websocket related conveniences. 11 | */ 12 | 13 | #ifndef ST_ASIO_EXT_SSL_WEBSOCKET_H_ 14 | #define ST_ASIO_EXT_SSL_WEBSOCKET_H_ 15 | 16 | #include "packer.h" 17 | #include "../tcp/ssl/ssl.h" 18 | #include "../tcp/websocket/ssl/ssl.h" 19 | #include "../single_service_pump.h" 20 | 21 | #ifndef ST_ASIO_DEFAULT_PACKER 22 | #define ST_ASIO_DEFAULT_PACKER st_asio_wrapper::ext::packer<> 23 | #endif 24 | 25 | #ifndef ST_ASIO_DEFAULT_UNPACKER 26 | #define ST_ASIO_DEFAULT_UNPACKER st_asio_wrapper::dummy_unpacker 27 | #endif 28 | 29 | namespace st_asio_wrapper { namespace ext { namespace websocket { namespace ssl { 30 | 31 | typedef st_asio_wrapper::websocket::ssl::client_socket_base client_socket; 32 | template using client_socket2 = st_asio_wrapper::websocket::ssl::client_socket_base; 33 | typedef client_socket connector; 34 | typedef st_asio_wrapper::ssl::single_client_base single_client; 35 | typedef st_asio_wrapper::ssl::multi_client_base multi_client; 36 | template using multi_client2 = st_asio_wrapper::ssl::multi_client_base, Matrix>; 37 | typedef multi_client client; 38 | 39 | typedef st_asio_wrapper::websocket::ssl::server_socket_base server_socket; 40 | template using server_socket2 = st_asio_wrapper::websocket::ssl::server_socket_base; 41 | typedef st_asio_wrapper::ssl::server_base server; 42 | template using server2 = st_asio_wrapper::ssl::server_base, Server>; 43 | 44 | }}}} //namespace 45 | 46 | #endif /* ST_ASIO_EXT_SSL_WEBSOCKET_H_ */ 47 | -------------------------------------------------------------------------------- /include/ext/tcp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * tcp.h 3 | * 4 | * Created on: 2016-7-30 5 | * Author: youngwolf 6 | * email: mail2tao@163.com 7 | * QQ: 676218192 8 | * Community on QQ: 198941541 9 | * 10 | * TCP related conveniences. 11 | */ 12 | 13 | #ifndef ST_ASIO_EXT_TCP_H_ 14 | #define ST_ASIO_EXT_TCP_H_ 15 | 16 | #include "packer.h" 17 | #include "unpacker.h" 18 | #include "../tcp/client_socket.h" 19 | #include "../tcp/proxy/socks.h" 20 | #include "../tcp/client.h" 21 | #include "../tcp/server_socket.h" 22 | #include "../tcp/server.h" 23 | #include "../single_service_pump.h" 24 | 25 | #ifndef ST_ASIO_DEFAULT_PACKER 26 | #define ST_ASIO_DEFAULT_PACKER st_asio_wrapper::ext::packer<> 27 | #endif 28 | 29 | #ifndef ST_ASIO_DEFAULT_UNPACKER 30 | #define ST_ASIO_DEFAULT_UNPACKER st_asio_wrapper::ext::unpacker<> 31 | #endif 32 | 33 | namespace st_asio_wrapper { namespace ext { namespace tcp { 34 | 35 | typedef st_asio_wrapper::tcp::client_socket_base client_socket; 36 | template 37 | class client_socket2 : public st_asio_wrapper::tcp::client_socket_base 38 | { 39 | private: 40 | typedef st_asio_wrapper::tcp::client_socket_base super; 41 | 42 | public: 43 | client_socket2(boost::asio::io_context& io_context_) : super(io_context_) {} 44 | client_socket2(Matrix& matrix_) : super(matrix_) {} 45 | }; 46 | typedef client_socket connector; 47 | typedef st_asio_wrapper::tcp::single_client_base single_client; 48 | typedef st_asio_wrapper::tcp::multi_client_base multi_client; 49 | template 50 | class multi_client2 : public st_asio_wrapper::tcp::multi_client_base, Matrix> 51 | { 52 | private: 53 | typedef st_asio_wrapper::tcp::multi_client_base, Matrix> super; 54 | 55 | public: 56 | multi_client2(service_pump& service_pump_) : super(service_pump_) {} 57 | }; 58 | typedef multi_client client; 59 | 60 | typedef st_asio_wrapper::tcp::server_socket_base server_socket; 61 | template 62 | class server_socket2 : public st_asio_wrapper::tcp::server_socket_base 63 | { 64 | private: 65 | typedef st_asio_wrapper::tcp::server_socket_base super; 66 | 67 | public: 68 | server_socket2(Server& server_) : super(server_) {} 69 | template server_socket2(Server& server_, Arg& arg) : super(server_, arg) {} 70 | }; 71 | typedef st_asio_wrapper::tcp::server_base server; 72 | template 73 | class server2 : public st_asio_wrapper::tcp::server_base, Server> 74 | { 75 | private: 76 | typedef st_asio_wrapper::tcp::server_base, Server> super; 77 | 78 | public: 79 | server2(service_pump& service_pump_) : super(service_pump_) {} 80 | }; 81 | 82 | #ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS 83 | typedef st_asio_wrapper::tcp::unix_client_socket_base unix_client_socket; 84 | template 85 | class unix_client_socket2 : public st_asio_wrapper::tcp::unix_client_socket_base 86 | { 87 | private: 88 | typedef st_asio_wrapper::tcp::unix_client_socket_base super; 89 | 90 | public: 91 | unix_client_socket2(boost::asio::io_context& io_context_) : super(io_context_) {} 92 | unix_client_socket2(Matrix& matrix_) : super(matrix_) {} 93 | }; 94 | typedef st_asio_wrapper::tcp::single_client_base unix_single_client; 95 | typedef st_asio_wrapper::tcp::multi_client_base unix_multi_client; 96 | //typedef multi_client2 unix_multi_client2; //multi_client2 can be used for unix socket too, but we cannot typedef it. 97 | 98 | typedef st_asio_wrapper::tcp::unix_server_socket_base unix_server_socket; 99 | template 100 | class unix_server_socket2 : public st_asio_wrapper::tcp::unix_server_socket_base 101 | { 102 | private: 103 | typedef st_asio_wrapper::tcp::unix_server_socket_base super; 104 | 105 | public: 106 | unix_server_socket2(Server& server_) : super(server_) {} 107 | template unix_server_socket2(Server& server_, Arg& arg) : super(server_, arg) {} 108 | }; 109 | typedef st_asio_wrapper::tcp::unix_server_base unix_server; 110 | template 111 | class unix_server2 : public st_asio_wrapper::tcp::unix_server_base, Server> 112 | { 113 | private: 114 | typedef st_asio_wrapper::tcp::unix_server_base, Server> super; 115 | 116 | public: 117 | unix_server2(service_pump& service_pump_) : super(service_pump_) {} 118 | }; 119 | #endif 120 | 121 | namespace proxy { 122 | 123 | namespace socks4 { 124 | typedef st_asio_wrapper::tcp::proxy::socks4::client_socket_base client_socket; 125 | template 126 | class client_socket2 : public st_asio_wrapper::tcp::proxy::socks4::client_socket_base 127 | { 128 | private: 129 | typedef st_asio_wrapper::tcp::proxy::socks4::client_socket_base super; 130 | 131 | public: 132 | client_socket2(boost::asio::io_context& io_context_) : super(io_context_) {} 133 | client_socket2(Matrix& matrix_) : super(matrix_) {} 134 | }; 135 | typedef client_socket connector; 136 | typedef st_asio_wrapper::tcp::single_client_base single_client; 137 | typedef st_asio_wrapper::tcp::multi_client_base multi_client; 138 | //typedef st_asio_wrapper::ext::tcp::multi_client2 multi_client2; //multi_client2 can be used for socks4 too, but we cannot typedef it. 139 | typedef multi_client client; 140 | } 141 | 142 | namespace socks5 { 143 | typedef st_asio_wrapper::tcp::proxy::socks5::client_socket_base client_socket; 144 | template 145 | class client_socket2 : public st_asio_wrapper::tcp::proxy::socks5::client_socket_base 146 | { 147 | private: 148 | typedef st_asio_wrapper::tcp::proxy::socks5::client_socket_base super; 149 | 150 | public: 151 | client_socket2(boost::asio::io_context& io_context_) : super(io_context_) {} 152 | client_socket2(Matrix& matrix_) : super(matrix_) {} 153 | }; 154 | typedef client_socket connector; 155 | typedef st_asio_wrapper::tcp::single_client_base single_client; 156 | typedef st_asio_wrapper::tcp::multi_client_base multi_client; 157 | //typedef st_asio_wrapper::ext::tcp::multi_client2 multi_client2; //multi_client2 can be used for socks5 too, but we cannot typedef it. 158 | typedef multi_client client; 159 | } 160 | 161 | } 162 | 163 | }}} //namespace 164 | 165 | #endif /* ST_ASIO_EXT_TCP_H_ */ 166 | -------------------------------------------------------------------------------- /include/ext/udp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * udp.h 3 | * 4 | * Created on: 2016-9-7 5 | * Author: youngwolf 6 | * email: mail2tao@163.com 7 | * QQ: 676218192 8 | * Community on QQ: 198941541 9 | * 10 | * udp related conveniences. 11 | */ 12 | 13 | #ifndef ST_ASIO_EXT_UDP_H_ 14 | #define ST_ASIO_EXT_UDP_H_ 15 | 16 | #include "packer.h" 17 | #include "unpacker.h" 18 | #include "../udp/socket.h" 19 | #include "../udp/socket_service.h" 20 | #include "../single_service_pump.h" 21 | 22 | #ifndef ST_ASIO_DEFAULT_PACKER 23 | #define ST_ASIO_DEFAULT_PACKER st_asio_wrapper::ext::packer<> 24 | #endif 25 | 26 | #ifndef ST_ASIO_DEFAULT_UDP_UNPACKER 27 | #define ST_ASIO_DEFAULT_UDP_UNPACKER st_asio_wrapper::ext::udp_unpacker 28 | #endif 29 | 30 | namespace st_asio_wrapper { namespace ext { namespace udp { 31 | 32 | typedef st_asio_wrapper::udp::socket_base socket; 33 | template 34 | class socket2 : public st_asio_wrapper::udp::socket_base 35 | { 36 | private: 37 | typedef st_asio_wrapper::udp::socket_base super; 38 | 39 | public: 40 | socket2(boost::asio::io_context& io_context_) : super(io_context_) {} 41 | socket2(Matrix& matrix_) : super(matrix_) {} 42 | }; 43 | typedef st_asio_wrapper::udp::single_socket_service_base single_socket_service; 44 | typedef st_asio_wrapper::udp::multi_socket_service_base multi_socket_service; 45 | template 46 | class multi_socket_service2 : public st_asio_wrapper::udp::multi_socket_service_base, Matrix> 47 | { 48 | private: 49 | typedef st_asio_wrapper::udp::multi_socket_service_base, Matrix> super; 50 | 51 | public: 52 | multi_socket_service2(service_pump& service_pump_) : super(service_pump_) {} 53 | }; 54 | typedef multi_socket_service socket_service; 55 | 56 | #ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS 57 | typedef st_asio_wrapper::udp::unix_socket_base unix_socket; 58 | template 59 | class unix_socket2 : public st_asio_wrapper::udp::unix_socket_base 60 | { 61 | private: 62 | typedef st_asio_wrapper::udp::unix_socket_base super; 63 | 64 | public: 65 | unix_socket2(boost::asio::io_context& io_context_) : super(io_context_) {} 66 | unix_socket2(Matrix& matrix_) : super(matrix_) {} 67 | }; 68 | typedef st_asio_wrapper::udp::single_socket_service_base unix_single_socket_service; 69 | typedef st_asio_wrapper::udp::multi_socket_service_base unix_multi_socket_service; 70 | //typedef multi_socket_service2 unix_multi_socket_service2; //multi_socket_service2 can be used for unix socket too, but we cannot typedef it. 71 | #endif 72 | 73 | }}} //namespace 74 | 75 | #endif /* ST_ASIO_EXT_UDP_H_ */ 76 | -------------------------------------------------------------------------------- /include/ext/websocket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * websocket.h 3 | * 4 | * Created on: 2022-5-27 5 | * Author: youngwolf 6 | * email: mail2tao@163.com 7 | * QQ: 676218192 8 | * Community on QQ: 198941541 9 | * 10 | * websocket related conveniences. 11 | */ 12 | 13 | #ifndef ST_ASIO_EXT_WEBSOCKET_H_ 14 | #define ST_ASIO_EXT_WEBSOCKET_H_ 15 | 16 | #include "packer.h" 17 | #include "../tcp/websocket/websocket.h" 18 | #include "../single_service_pump.h" 19 | 20 | #ifndef ST_ASIO_DEFAULT_PACKER 21 | #define ST_ASIO_DEFAULT_PACKER st_asio_wrapper::ext::packer<> 22 | #endif 23 | 24 | #ifndef ST_ASIO_DEFAULT_UNPACKER 25 | #define ST_ASIO_DEFAULT_UNPACKER st_asio_wrapper::dummy_unpacker 26 | #endif 27 | 28 | namespace st_asio_wrapper { namespace ext { namespace websocket { 29 | 30 | typedef st_asio_wrapper::websocket::client_socket_base client_socket; 31 | template using client_socket2 = st_asio_wrapper::websocket::client_socket_base; 32 | typedef client_socket connector; 33 | typedef st_asio_wrapper::tcp::single_client_base single_client; 34 | typedef st_asio_wrapper::tcp::multi_client_base multi_client; 35 | template using multi_client2 = st_asio_wrapper::tcp::multi_client_base, Matrix>; 36 | typedef multi_client client; 37 | 38 | typedef st_asio_wrapper::websocket::server_socket_base server_socket; 39 | template using server_socket2 = st_asio_wrapper::websocket::server_socket_base; 40 | typedef st_asio_wrapper::tcp::server_base server; 41 | template using server2 = st_asio_wrapper::tcp::server_base, Server>; 42 | 43 | }}} //namespace 44 | 45 | #endif /* ST_ASIO_EXT_WEBSOCKET_H_ */ 46 | -------------------------------------------------------------------------------- /include/old_class_names.h: -------------------------------------------------------------------------------- 1 | /* 2 | * old_class_names.h 3 | * 4 | * Created on: 2016-7-30 5 | * Author: youngwolf 6 | * email: mail2tao@163.com 7 | * QQ: 676218192 8 | * Community on QQ: 198941541 9 | * 10 | * be compatible with old editions. 11 | */ 12 | 13 | #ifndef ST_ASIO_OLD_CLASS_NAMES_H_ 14 | #define ST_ASIO_OLD_CLASS_NAMES_H_ 15 | 16 | //common 17 | #define st_object object 18 | #define st_timer timer 19 | #define st_object_pool object_pool 20 | #define st_service_pump service_pump 21 | 22 | #define st_socket socket 23 | #define st_tcp_socket_base socket_base //from st_asio_wrapper to st_asio_wrapper::tcp 24 | 25 | #define st_sclient single_socket_service 26 | #define st_client multi_socket_service 27 | //common 28 | 29 | //tcp client 30 | #define st_client_socket_base client_socket_base //from st_asio_wrapper to st_asio_wrapper::tcp 31 | #define st_client_socket client_socket //from st_asio_wrapper::ext to st_asio_wrapper::ext::tcp 32 | #define st_connector_base connector_base //from st_asio_wrapper to st_asio_wrapper::tcp 33 | #define st_connector connector //from st_asio_wrapper::ext to st_asio_wrapper::ext::tcp 34 | #define st_tcp_sclient_base single_client_base //from st_asio_wrapper to st_asio_wrapper::tcp 35 | #define st_tcp_sclient single_client //from st_asio_wrapper::ext to st_asio_wrapper::ext::tcp 36 | #define st_tcp_client_base client_base //from st_asio_wrapper to st_asio_wrapper::tcp 37 | #define st_tcp_client client //from st_asio_wrapper::ext to st_asio_wrapper::ext::tcp 38 | //tcp client 39 | 40 | //tcp server 41 | #define st_server_socket_base server_socket_base //from st_asio_wrapper to st_asio_wrapper::tcp 42 | #define st_server_socket server_socket //from st_asio_wrapper::ext to st_asio_wrapper::ext::tcp 43 | #define st_server_base server_base //from st_asio_wrapper to st_asio_wrapper::tcp 44 | #define st_server server //from st_asio_wrapper::ext to st_asio_wrapper::ext::tcp 45 | //tcp server 46 | 47 | //ssl 48 | #define st_ssl_client_socket_base client_socket_base //from st_asio_wrapper to st_asio_wrapper::ssl 49 | #define st_ssl_client_socket client_socket //from st_asio_wrapper::ext to st_asio_wrapper::ext::ssl 50 | #define st_ssl_connector_base connector_base //from st_asio_wrapper to st_asio_wrapper::ssl 51 | #define st_ssl_connector connector //from st_asio_wrapper::ext to st_asio_wrapper::ext::ssl 52 | #define st_ssl_tcp_sclient_base single_client_base //from st_asio_wrapper to st_asio_wrapper::ssl 53 | #define st_ssl_tcp_sclient single_client //from st_asio_wrapper::ext to st_asio_wrapper::ext::ssl 54 | #define st_ssl_tcp_client_base client_base //from st_asio_wrapper to st_asio_wrapper::ssl 55 | #define st_ssl_tcp_client client //from st_asio_wrapper::ext to st_asio_wrapper::ext::ssl 56 | 57 | #define st_ssl_server_socket_base server_socket_base //from st_asio_wrapper to st_asio_wrapper::ssl 58 | #define st_ssl_server_socket server_socket //from st_asio_wrapper::ext to st_asio_wrapper::ext::ssl 59 | #define st_ssl_server_base server_base //from st_asio_wrapper to st_asio_wrapper::ssl 60 | #define st_ssl_server server //from st_asio_wrapper::ext to st_asio_wrapper::ext::ssl 61 | //ssl 62 | 63 | //udp 64 | #define st_udp_socket_base socket_base //from st_asio_wrapper to st_asio_wrapper::udp 65 | #define st_udp_socket socket //from st_asio_wrapper::ext to st_asio_wrapper::ext::udp 66 | #define st_udp_sclient_base single_socket_service_base //from st_asio_wrapper to st_asio_wrapper::udp 67 | #define st_udp_sclient single_socket_service //from st_asio_wrapper::ext to st_asio_wrapper::ext::udp 68 | #define st_udp_client_base socket_service_base //from st_asio_wrapper to st_asio_wrapper::udp 69 | #define st_udp_client socket_service //from st_asio_wrapper::ext to st_asio_wrapper::ext::udp 70 | //udp 71 | 72 | #endif /* ST_ASIO_OLD_CLASS_NAMES_H_ */ 73 | -------------------------------------------------------------------------------- /include/single_service_pump.h: -------------------------------------------------------------------------------- 1 | /* 2 | * single_service_pump.h 3 | * 4 | * Created on: 2019-5-17 5 | * Author: youngwolf 6 | * email: mail2tao@163.com 7 | * QQ: 676218192 8 | * Community on QQ: 198941541 9 | * 10 | * one service_pump for one service. 11 | */ 12 | 13 | #ifndef _ST_ASIO_SINGLE_SERVICE_PUMP_H_ 14 | #define _ST_ASIO_SINGLE_SERVICE_PUMP_H_ 15 | 16 | #include "service_pump.h" 17 | 18 | namespace st_asio_wrapper 19 | { 20 | 21 | template class single_service_pump : public service_pump, public Service 22 | { 23 | 24 | public: 25 | using service_pump::start_service; 26 | using service_pump::stop_service; 27 | 28 | public: 29 | #if BOOST_ASIO_VERSION >= 101200 30 | #ifdef ST_ASIO_DECREASE_THREAD_AT_RUNTIME 31 | single_service_pump(int concurrency_hint = BOOST_ASIO_CONCURRENCY_HINT_SAFE) : service_pump(concurrency_hint), Service(boost::ref(*(service_pump*) this)) {} 32 | template single_service_pump(Arg& arg, int concurrency_hint = BOOST_ASIO_CONCURRENCY_HINT_SAFE) : 33 | service_pump(concurrency_hint), Service(boost::ref(*(service_pump*) this), arg) {} 34 | #else 35 | //single_service_pump always think it's using multiple io_context 36 | single_service_pump(int concurrency_hint = BOOST_ASIO_CONCURRENCY_HINT_SAFE) : service_pump(concurrency_hint, true), Service(boost::ref(*(service_pump*) this)) {} 37 | template single_service_pump(Arg& arg, int concurrency_hint = BOOST_ASIO_CONCURRENCY_HINT_SAFE) : 38 | service_pump(concurrency_hint, true), Service(boost::ref(*(service_pump*) this), arg) {} 39 | #endif 40 | #else 41 | #ifdef ST_ASIO_DECREASE_THREAD_AT_RUNTIME 42 | single_service_pump() : Service(boost::ref(*(service_pump*) this)) {} 43 | template single_service_pump(Arg& arg) : Service(boost::ref(*(service_pump*) this), arg) {} 44 | #else 45 | //single_service_pump always think it's using multiple io_context 46 | single_service_pump() : service_pump(true), Service(boost::ref(*(service_pump*) this)) {} 47 | template single_service_pump(Arg& arg) : service_pump(true), Service(boost::ref(*(service_pump*) this), arg) {} 48 | #endif 49 | #endif 50 | }; 51 | 52 | } //namespace 53 | 54 | #endif /* _ST_ASIO_SINGLE_SERVICE_PUMP_H_ */ 55 | -------------------------------------------------------------------------------- /include/socket_service.h: -------------------------------------------------------------------------------- 1 | /* 2 | * socket_service.h 3 | * 4 | * Created on: 2012-3-2 5 | * Author: youngwolf 6 | * email: mail2tao@163.com 7 | * QQ: 676218192 8 | * Community on QQ: 198941541 9 | * 10 | * this class only used at client endpoint 11 | */ 12 | 13 | #ifndef ST_ASIO_SOCKET_SERVICE_H_ 14 | #define ST_ASIO_SOCKET_SERVICE_H_ 15 | 16 | #include "object_pool.h" 17 | 18 | namespace st_asio_wrapper 19 | { 20 | 21 | //only support one socket 22 | template 23 | class single_socket_service : public service_pump::i_service, public Socket 24 | { 25 | public: 26 | single_socket_service(service_pump& service_pump_) : i_service(service_pump_), Socket(service_pump_) {} 27 | template single_socket_service(service_pump& service_pump_, Arg& arg) : i_service(service_pump_), Socket(service_pump_, arg) {} 28 | ~single_socket_service() {clear_io_context_refs();} 29 | 30 | using Socket::id; //release these functions 31 | 32 | protected: 33 | virtual bool init() {ST_THIS reset_io_context_refs(); ST_THIS start(); return Socket::started();} 34 | virtual void uninit() {ST_THIS graceful_shutdown();} //if you wanna force shutdown, call force_shutdown before service_pump::stop_service invocation. 35 | 36 | private: 37 | virtual void attach_io_context(boost::asio::io_context& io_context_, unsigned refs) {get_service_pump().assign_io_context(io_context_, refs);} 38 | virtual void detach_io_context(boost::asio::io_context& io_context_, unsigned refs) {get_service_pump().return_io_context(io_context_, refs);} 39 | 40 | private: 41 | //hide these functions 42 | using Socket::add_io_context_refs; 43 | using Socket::sub_io_context_refs; 44 | using Socket::clear_io_context_refs; 45 | using Socket::get_matrix; 46 | }; 47 | 48 | template 49 | class multi_socket_service : public Matrix, public Pool 50 | { 51 | protected: 52 | multi_socket_service(service_pump& service_pump_) : Pool(service_pump_) {} 53 | template multi_socket_service(service_pump& service_pump_, const Arg& arg) : Pool(service_pump_, arg) {} 54 | ~multi_socket_service() {ST_THIS clear_io_context_refs();} 55 | 56 | virtual bool init() 57 | { 58 | ST_THIS do_something_to_all(boost::lambda::bind(&Socket::start, *boost::lambda::_1)); 59 | ST_THIS start(); 60 | return true; 61 | } 62 | 63 | public: 64 | //implement i_matrix's pure virtual functions 65 | virtual bool started() const {return ST_THIS service_started();} 66 | virtual service_pump& get_service_pump() {return Pool::get_service_pump();} 67 | virtual const service_pump& get_service_pump() const {return Pool::get_service_pump();} 68 | 69 | virtual bool socket_exist(boost::uint_fast64_t id) {return ST_THIS exist(id);} 70 | virtual boost::shared_ptr find_socket(boost::uint_fast64_t id) {return ST_THIS find(id);} 71 | virtual bool del_socket(boost::uint_fast64_t id) {return ST_THIS del_object(id);} 72 | 73 | typename Pool::object_type create_object() {return Pool::create_object(boost::ref(*this));} 74 | template typename Pool::object_type create_object(Arg& arg) {return Pool::create_object(boost::ref(*this), arg);} 75 | 76 | //will call socket_ptr's start function if the service_pump already started. 77 | bool add_socket(typename Pool::object_ctype& socket_ptr, unsigned additional_io_context_refs = 0) 78 | { 79 | if (ST_THIS add_object(socket_ptr)) 80 | { 81 | socket_ptr->add_io_context_refs(additional_io_context_refs); 82 | if (get_service_pump().is_service_started()) //service already started 83 | socket_ptr->start(); 84 | 85 | return true; 86 | } 87 | 88 | return false; 89 | } 90 | 91 | private: 92 | virtual void attach_io_context(boost::asio::io_context& io_context_, unsigned refs) {get_service_pump().assign_io_context(io_context_, refs);} 93 | virtual void detach_io_context(boost::asio::io_context& io_context_, unsigned refs) {get_service_pump().return_io_context(io_context_, refs);} 94 | }; 95 | 96 | } //namespace 97 | 98 | #endif /* ST_ASIO_SOCKET_SERVICE_H_ */ 99 | -------------------------------------------------------------------------------- /include/tcp/alias.h: -------------------------------------------------------------------------------- 1 | /* 2 | * alias.h 3 | * 4 | * Created on: 2017-7-17 5 | * Author: youngwolf 6 | * email: mail2tao@163.com 7 | * QQ: 676218192 8 | * Community on QQ: 198941541 9 | * 10 | * some alias, they are deprecated. 11 | */ 12 | 13 | #ifndef ST_ASIO_TCP_ALIAS_H_ 14 | #define ST_ASIO_TCP_ALIAS_H_ 15 | 16 | #include "client_socket.h" 17 | #include "client.h" 18 | 19 | namespace st_asio_wrapper { namespace tcp { 20 | 21 | template class InQueue = ST_ASIO_INPUT_QUEUE, template class InContainer = ST_ASIO_INPUT_CONTAINER, 23 | template class OutQueue = ST_ASIO_OUTPUT_QUEUE, template class OutContainer = ST_ASIO_OUTPUT_CONTAINER, 24 | template class ReaderWriter = reader_writer> 25 | class connector_base : public client_socket_base 26 | { 27 | private: 28 | typedef client_socket_base super; 29 | 30 | public: 31 | connector_base(boost::asio::io_context& io_context_) : super(io_context_) {} 32 | template connector_base(boost::asio::io_context& io_context_, Arg& arg) : super(io_context_, arg) {} 33 | 34 | connector_base(Matrix& matrix_) : super(matrix_) {} 35 | template connector_base(Matrix& matrix_, Arg& arg) : super(matrix_, arg) {} 36 | }; 37 | 38 | template, typename Matrix = i_matrix> class client_base : public multi_client_base 39 | { 40 | public: 41 | client_base(service_pump& service_pump_) : multi_client_base(service_pump_) {} 42 | }; 43 | 44 | }} //namespace 45 | 46 | #endif /* ST_ASIO_TCP_ALIAS_H_ */ 47 | -------------------------------------------------------------------------------- /include/tcp/client.h: -------------------------------------------------------------------------------- 1 | /* 2 | * client.h 3 | * 4 | * Created on: 2012-3-2 5 | * Author: youngwolf 6 | * email: mail2tao@163.com 7 | * QQ: 676218192 8 | * Community on QQ: 198941541 9 | * 10 | * this class only used at client endpoint 11 | */ 12 | 13 | #ifndef ST_ASIO_TCP_CLIENT_H_ 14 | #define ST_ASIO_TCP_CLIENT_H_ 15 | 16 | #include "../socket_service.h" 17 | 18 | namespace st_asio_wrapper { namespace tcp { 19 | 20 | template class single_client_base : public single_socket_service 21 | { 22 | public: 23 | single_client_base(service_pump& service_pump_) : single_socket_service(service_pump_) {} 24 | template 25 | single_client_base(service_pump& service_pump_, Arg& arg) : single_socket_service(service_pump_, arg) {} 26 | }; 27 | 28 | template, typename Matrix = i_matrix> 29 | class multi_client_base : public multi_socket_service 30 | { 31 | private: 32 | typedef multi_socket_service super; 33 | 34 | public: 35 | multi_client_base(service_pump& service_pump_) : super(service_pump_) {} 36 | template multi_client_base(service_pump& service_pump_, const Arg& arg) : super(service_pump_, arg) {} 37 | 38 | //connected link size, may smaller than total object size (object_pool::size) 39 | size_t valid_size() 40 | { 41 | size_t size = 0; 42 | ST_THIS do_something_to_all(boost::lambda::if_then(boost::lambda::bind(&Socket::is_connected, *boost::lambda::_1), ++boost::lambda::var(size))); 43 | return size; 44 | } 45 | 46 | using super::add_socket; 47 | typename Pool::object_type add_socket() 48 | { 49 | BOOST_AUTO(socket_ptr, ST_THIS create_object()); 50 | return add_socket(socket_ptr) ? socket_ptr : typename Pool::object_type(); 51 | } 52 | typename Pool::object_type add_socket(unsigned short port, const std::string& ip = ST_ASIO_SERVER_IP, unsigned additional_io_context_refs = 0) 53 | { 54 | BOOST_AUTO(socket_ptr, ST_THIS create_object()); 55 | if (!socket_ptr) 56 | return socket_ptr; 57 | 58 | socket_ptr->set_server_addr(port, ip); 59 | return add_socket(socket_ptr, additional_io_context_refs) ? socket_ptr : typename Pool::object_type(); 60 | } 61 | typename Pool::object_type add_socket(unsigned short port, unsigned short local_port, const std::string& ip = ST_ASIO_SERVER_IP, const std::string& local_ip = std::string(), 62 | unsigned additional_io_context_refs = 0) 63 | { 64 | BOOST_AUTO(socket_ptr, ST_THIS create_object()); 65 | if (!socket_ptr) 66 | return socket_ptr; 67 | 68 | socket_ptr->set_server_addr(port, ip); 69 | socket_ptr->set_local_addr(local_port, local_ip); 70 | return add_socket(socket_ptr, additional_io_context_refs) ? socket_ptr : typename Pool::object_type(); 71 | } 72 | 73 | /////////////////////////////////////////////////// 74 | //msg sending interface 75 | TCP_BROADCAST_MSG(broadcast_msg, send_msg) 76 | TCP_BROADCAST_MSG(broadcast_native_msg, send_native_msg) 77 | //guarantee send msg successfully even if can_overflow equal to false 78 | //success at here just means put the msg into tcp::socket_base's send buffer 79 | TCP_BROADCAST_MSG(safe_broadcast_msg, safe_send_msg) 80 | TCP_BROADCAST_MSG(safe_broadcast_native_msg, safe_send_native_msg) 81 | //msg sending interface 82 | /////////////////////////////////////////////////// 83 | 84 | //functions with a socket_ptr parameter will remove the link from object pool first, then call corresponding function, if you want to reconnect to the server, 85 | //please call socket_ptr's 'disconnect' 'force_shutdown' or 'graceful_shutdown' with true 'reconnect' directly. 86 | void disconnect(typename Pool::object_ctype& socket_ptr) {ST_THIS del_object(socket_ptr); socket_ptr->disconnect(false);} 87 | void disconnect(bool reconnect = false) {ST_THIS do_something_to_all(boost::bind(&Socket::disconnect, boost::placeholders::_1, reconnect));} 88 | void force_shutdown(typename Pool::object_ctype& socket_ptr) {ST_THIS del_object(socket_ptr); socket_ptr->force_shutdown(false);} 89 | void force_shutdown(bool reconnect = false) {ST_THIS do_something_to_all(boost::bind(&Socket::force_shutdown, boost::placeholders::_1, reconnect));} 90 | void graceful_shutdown(typename Pool::object_ctype& socket_ptr) {ST_THIS del_object(socket_ptr); socket_ptr->graceful_shutdown(false);} 91 | void graceful_shutdown(bool reconnect = false) {ST_THIS do_something_to_all(boost::bind(&Socket::graceful_shutdown, boost::placeholders::_1, reconnect));} 92 | 93 | protected: 94 | virtual void uninit() {ST_THIS stop(); force_shutdown();} //if you wanna graceful shutdown, call graceful_shutdown before service_pump::stop_service invocation. 95 | }; 96 | 97 | }} //namespace 98 | 99 | #endif /* ST_ASIO_TCP_CLIENT_H_ */ 100 | -------------------------------------------------------------------------------- /include/tcp/server_socket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * server_socket.h 3 | * 4 | * Created on: 2013-4-11 5 | * Author: youngwolf 6 | * email: mail2tao@163.com 7 | * QQ: 676218192 8 | * Community on QQ: 198941541 9 | * 10 | * this class only used at server endpoint 11 | */ 12 | 13 | #ifndef ST_ASIO_SERVER_SOCKET_H_ 14 | #define ST_ASIO_SERVER_SOCKET_H_ 15 | 16 | #include "socket.h" 17 | 18 | namespace st_asio_wrapper { namespace tcp { 19 | 20 | template class generic_server_socket : public Socket, public boost::enable_shared_from_this > 21 | { 22 | public: 23 | typedef generic_server_socket type_of_object_restore; 24 | 25 | private: 26 | typedef Socket super; 27 | 28 | public: 29 | generic_server_socket(Server& server_) : super(server_.get_service_pump()), server(server_) {} 30 | template generic_server_socket(Server& server_, Arg& arg) : super(server_.get_service_pump(), arg), server(server_) {} 31 | ~generic_server_socket() {ST_THIS clear_io_context_refs();} 32 | 33 | virtual const char* type_name() const {return "TCP (server endpoint)";} 34 | virtual int type_id() const {return 2;} 35 | 36 | virtual void take_over(boost::shared_ptr socket_ptr) {} //restore this socket from socket_ptr 37 | 38 | void disconnect() {force_shutdown();} 39 | void force_shutdown() 40 | { 41 | if (super::FORCE_SHUTTING_DOWN != ST_THIS status) 42 | ST_THIS show_info("server link:", "been shut down."); 43 | 44 | super::force_shutdown(); 45 | } 46 | 47 | //this function is not thread safe, please note. 48 | void graceful_shutdown() 49 | { 50 | if (ST_THIS is_broken()) 51 | return force_shutdown(); 52 | else if (!ST_THIS is_shutting_down()) 53 | ST_THIS show_info("server link:", "being shut down gracefully."); 54 | 55 | super::graceful_shutdown(); 56 | } 57 | 58 | protected: 59 | Server& get_server() {return server;} 60 | const Server& get_server() const {return server;} 61 | 62 | virtual void on_unpack_error() {unified_out::error_out(ST_ASIO_LLF " can not unpack msg.", ST_THIS id()); ST_THIS unpacker()->dump_left_data(); force_shutdown();} 63 | virtual void on_recv_error(const boost::system::error_code& ec) {ST_THIS show_info(ec, "server link:", "broken/been shut down"); force_shutdown();} 64 | virtual void on_async_shutdown_error() {force_shutdown();} 65 | virtual bool on_heartbeat_error() {ST_THIS show_info("server link:", "broke unexpectedly."); force_shutdown(); return false;} 66 | 67 | virtual void on_close() 68 | { 69 | ST_THIS clear_io_context_refs(); 70 | #ifndef ST_ASIO_CLEAR_OBJECT_INTERVAL 71 | server.del_socket(ST_THIS shared_from_this(), false); 72 | #endif 73 | super::on_close(); 74 | } 75 | 76 | private: 77 | //call following two functions (via timer object's add_io_context_refs, sub_io_context_refs or clear_io_context_refs) in: 78 | // 1. on_xxxx callbacks on this object; 79 | // 2. use this->post or this->set_timer to emit an async event, then in the callback. 80 | //otherwise, you must protect them to not be called with reset and on_close simultaneously 81 | virtual void attach_io_context(boost::asio::io_context& io_context_, unsigned refs) {server.get_service_pump().assign_io_context(io_context_, refs);} 82 | virtual void detach_io_context(boost::asio::io_context& io_context_, unsigned refs) {server.get_service_pump().return_io_context(io_context_, refs);} 83 | 84 | private: 85 | Server& server; 86 | }; 87 | 88 | template class InQueue = ST_ASIO_INPUT_QUEUE, template class InContainer = ST_ASIO_INPUT_CONTAINER, 90 | template class OutQueue = ST_ASIO_OUTPUT_QUEUE, template class OutContainer = ST_ASIO_OUTPUT_CONTAINER, 91 | template class ReaderWriter = reader_writer> 92 | class server_socket_base : public generic_server_socket, Server> 93 | { 94 | private: 95 | typedef generic_server_socket, Server> super; 96 | 97 | public: 98 | server_socket_base(Server& server_) : super(server_) {} 99 | template server_socket_base(Server& server_, Arg& arg) : super(server_, arg) {} 100 | }; 101 | 102 | #ifdef BOOST_ASIO_HAS_LOCAL_SOCKETS 103 | template class InQueue = ST_ASIO_INPUT_QUEUE, template class InContainer = ST_ASIO_INPUT_CONTAINER, 105 | template class OutQueue = ST_ASIO_OUTPUT_QUEUE, template class OutContainer = ST_ASIO_OUTPUT_CONTAINER, 106 | template class ReaderWriter = reader_writer> 107 | class unix_server_socket_base : public generic_server_socket, Server> 108 | { 109 | private: 110 | typedef generic_server_socket, Server> super; 111 | 112 | public: 113 | unix_server_socket_base(Server& server_) : super(server_) {} 114 | }; 115 | #endif 116 | 117 | }} //namespace 118 | 119 | #endif /* ST_ASIO_SERVER_SOCKET_H_ */ 120 | -------------------------------------------------------------------------------- /include/tcp/ssl/alias.h: -------------------------------------------------------------------------------- 1 | /* 2 | * alias.h 3 | * 4 | * Created on: 2017-7-17 5 | * Author: youngwolf 6 | * email: mail2tao@163.com 7 | * QQ: 676218192 8 | * Community on QQ: 198941541 9 | * 10 | * some alias, they are deprecated. 11 | */ 12 | 13 | #ifndef ST_ASIO_SSL_ALIAS_H_ 14 | #define ST_ASIO_SSL_ALIAS_H_ 15 | 16 | #include "ssl.h" 17 | 18 | namespace st_asio_wrapper { namespace ssl { 19 | 20 | template class InQueue = ST_ASIO_INPUT_QUEUE, template class InContainer = ST_ASIO_INPUT_CONTAINER, 22 | template class OutQueue = ST_ASIO_OUTPUT_QUEUE, template class OutContainer = ST_ASIO_OUTPUT_CONTAINER> 23 | class connector_base : public client_socket_base 24 | { 25 | private: 26 | typedef client_socket_base super; 27 | 28 | public: 29 | connector_base(boost::asio::io_context& io_context_, boost::asio::ssl::context& ctx) : super(io_context_, ctx) {} 30 | connector_base(Matrix& matrix_, boost::asio::ssl::context& ctx) : super(matrix_, ctx) {} 31 | }; 32 | 33 | template > class client_base : public multi_client_base 34 | { 35 | public: 36 | client_base(service_pump& service_pump_, const boost::asio::ssl::context::method& m) : multi_client_base(service_pump_, m) {} 37 | }; 38 | 39 | }} //namespace 40 | 41 | #endif /* ST_ASIO_SSL_ALIAS_H_ */ 42 | -------------------------------------------------------------------------------- /include/tcp/ssl/ssl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ssl.h 3 | * 4 | * Created on: 2012-3-2 5 | * Author: youngwolf 6 | * email: mail2tao@163.com 7 | * QQ: 676218192 8 | * Community on QQ: 198941541 9 | * 10 | * make st_asio_wrapper support ssl (based on boost::asio::ssl) 11 | */ 12 | 13 | #ifndef ST_ASIO_SSL_H_ 14 | #define ST_ASIO_SSL_H_ 15 | 16 | #include 17 | 18 | #include "../client.h" 19 | #include "../server.h" 20 | #include "../client_socket.h" 21 | #include "../server_socket.h" 22 | #include "../../object_pool.h" 23 | 24 | namespace st_asio_wrapper { namespace ssl { 25 | 26 | template class socket : public Socket 27 | { 28 | public: 29 | template socket(Arg& arg, boost::asio::ssl::context& ctx_) : Socket(arg, ctx_), ctx(ctx_) {} 30 | 31 | public: 32 | virtual void reset() {ST_THIS reset_next_layer(ctx); Socket::reset();} 33 | 34 | boost::asio::ssl::context& get_context() {return ctx;} 35 | 36 | protected: 37 | virtual void on_handshake(const boost::system::error_code& ec) 38 | { 39 | if (!ec) 40 | ST_THIS show_info(NULL, "handshake success."); 41 | else 42 | ST_THIS show_info(ec, NULL, "handshake failed"); 43 | } 44 | virtual void on_recv_error(const boost::system::error_code& ec) {ST_THIS stop_graceful_shutdown_monitoring(); Socket::on_recv_error(ec);} 45 | 46 | void shutdown_ssl() {ST_THIS status = Socket::GRACEFUL_SHUTTING_DOWN; ST_THIS dispatch_in_io_strand(boost::bind(&socket::async_shutdown, this));} 47 | 48 | private: 49 | void async_shutdown() 50 | { 51 | ST_THIS show_info("ssl link:", "been shutting down."); 52 | ST_THIS start_graceful_shutdown_monitoring(); 53 | ST_THIS next_layer().async_shutdown(ST_THIS make_handler_error(boost::bind(&socket::shutdown_handler, this, boost::asio::placeholders::error))); 54 | } 55 | 56 | //do not stop the shutdown monitoring at here, sometimes, this async_shutdown cannot trigger on_recv_error, 57 | //very strange, maybe, there's a bug in Asio. so we stop it in on_recv_error. 58 | void shutdown_handler(const boost::system::error_code& ec) {if (ec) ST_THIS show_info(ec, "ssl link", "async shutdown failed");} 59 | 60 | private: 61 | boost::asio::ssl::context& ctx; 62 | }; 63 | 64 | template class InQueue = ST_ASIO_INPUT_QUEUE, template class InContainer = ST_ASIO_INPUT_CONTAINER, 66 | template class OutQueue = ST_ASIO_OUTPUT_QUEUE, template class OutContainer = ST_ASIO_OUTPUT_CONTAINER> 67 | class client_socket_base : public socket, InQueue, InContainer, OutQueue, OutContainer> > 68 | { 69 | private: 70 | typedef socket, InQueue, InContainer, OutQueue, OutContainer> > super; 71 | 72 | public: 73 | client_socket_base(boost::asio::io_context& io_context_, boost::asio::ssl::context& ctx_) : super(io_context_, ctx_) {} 74 | client_socket_base(Matrix& matrix_, boost::asio::ssl::context& ctx_) : super(matrix_, ctx_) {} 75 | 76 | virtual const char* type_name() const {return "SSL (client endpoint)";} 77 | virtual int type_id() const {return 3;} 78 | 79 | //these functions are not thread safe, please note. 80 | void disconnect(bool reconnect = false) {force_shutdown(reconnect);} 81 | void force_shutdown(bool reconnect = false) {graceful_shutdown(reconnect);} 82 | void graceful_shutdown(bool reconnect = false) 83 | { 84 | if (ST_THIS is_ready()) 85 | { 86 | ST_THIS set_reconnect(reconnect); 87 | shutdown_ssl(); 88 | } 89 | else 90 | super::force_shutdown(reconnect); 91 | } 92 | 93 | protected: 94 | virtual void on_unpack_error() {unified_out::info_out(ST_ASIO_LLF " can not unpack msg.", ST_THIS id()); ST_THIS unpacker()->dump_left_data(); force_shutdown(ST_THIS is_reconnect());} 95 | virtual void on_close() 96 | { 97 | ST_THIS reset_next_layer(ST_THIS get_context()); 98 | super::on_close(); 99 | } 100 | 101 | private: 102 | virtual void connect_handler(const boost::system::error_code& ec) //intercept tcp::client_socket_base::connect_handler 103 | { 104 | if (!ec) 105 | { 106 | ST_THIS status = super::HANDSHAKING; 107 | ST_THIS next_layer().async_handshake(boost::asio::ssl::stream_base::client, 108 | ST_THIS make_handler_error(boost::bind(&client_socket_base::handle_handshake, this, boost::asio::placeholders::error))); 109 | } 110 | else 111 | super::connect_handler(ec); 112 | } 113 | 114 | void handle_handshake(const boost::system::error_code& ec) 115 | { 116 | ST_THIS on_handshake(ec); 117 | ec ? ST_THIS force_shutdown() : super::connect_handler(ec); //return to tcp::client_socket_base::connect_handler 118 | } 119 | 120 | using super::shutdown_ssl; 121 | }; 122 | 123 | template 124 | class object_pool : public st_asio_wrapper::object_pool 125 | { 126 | private: 127 | typedef st_asio_wrapper::object_pool super; 128 | 129 | public: 130 | object_pool(service_pump& service_pump_, const boost::asio::ssl::context::method& m) : super(service_pump_), ctx(m) {} 131 | boost::asio::ssl::context& context() {return ctx;} 132 | 133 | protected: 134 | template typename super::object_type create_object(Arg& arg) {return super::create_object(arg, boost::ref(ctx));} 135 | 136 | private: 137 | boost::asio::ssl::context ctx; 138 | }; 139 | 140 | template class InQueue = ST_ASIO_INPUT_QUEUE, template class InContainer = ST_ASIO_INPUT_CONTAINER, 142 | template class OutQueue = ST_ASIO_OUTPUT_QUEUE, template class OutContainer = ST_ASIO_OUTPUT_CONTAINER> 143 | class server_socket_base : public socket, InQueue, InContainer, OutQueue, OutContainer> > 144 | { 145 | private: 146 | typedef socket, InQueue, InContainer, OutQueue, OutContainer> > super; 147 | 148 | public: 149 | server_socket_base(Server& server_, boost::asio::ssl::context& ctx_) : super(server_, ctx_) {} 150 | 151 | virtual const char* type_name() const {return "SSL (server endpoint)";} 152 | virtual int type_id() const {return 4;} 153 | 154 | //these functions are not thread safe, please note. 155 | void disconnect() {force_shutdown();} 156 | void force_shutdown() {graceful_shutdown();} 157 | void graceful_shutdown() {if (ST_THIS is_ready()) shutdown_ssl(); else super::force_shutdown();} 158 | 159 | protected: 160 | virtual bool do_start() //intercept tcp::server_socket_base::do_start (to add handshake) 161 | { 162 | ST_THIS status = super::HANDSHAKING; 163 | ST_THIS next_layer().async_handshake(boost::asio::ssl::stream_base::server, 164 | ST_THIS make_handler_error(boost::bind(&server_socket_base::handle_handshake, this, boost::asio::placeholders::error))); 165 | return true; 166 | } 167 | 168 | virtual void on_unpack_error() {unified_out::info_out(ST_ASIO_LLF " can not unpack msg.", ST_THIS id()); ST_THIS unpacker()->dump_left_data(); force_shutdown();} 169 | 170 | private: 171 | void handle_handshake(const boost::system::error_code& ec) 172 | { 173 | ST_THIS on_handshake(ec); 174 | ec ? ST_THIS get_server().del_socket(ST_THIS shared_from_this()) : super::do_start(); //return to tcp::server_socket_base::do_start 175 | } 176 | 177 | using super::shutdown_ssl; 178 | }; 179 | 180 | template, typename Server = tcp::i_server> class server_base : public tcp::server_base 181 | { 182 | public: 183 | server_base(service_pump& service_pump_, const boost::asio::ssl::context::method& m) : tcp::server_base(service_pump_, m) {} 184 | }; 185 | template class single_client_base : public tcp::single_client_base 186 | { 187 | private: 188 | typedef tcp::single_client_base super; 189 | 190 | public: 191 | single_client_base(service_pump& service_pump_, const boost::shared_ptr& ctx_) : super(service_pump_, *ctx_), ctx_holder(ctx_) {} 192 | 193 | protected: 194 | virtual bool init() {if (0 == ST_THIS get_io_context_refs()) ST_THIS reset_next_layer(ST_THIS get_context()); return super::init();} 195 | 196 | private: 197 | boost::shared_ptr ctx_holder; 198 | }; 199 | template, typename Matrix = i_matrix> class multi_client_base : public tcp::multi_client_base 200 | { 201 | public: 202 | multi_client_base(service_pump& service_pump_, const boost::asio::ssl::context::method& m) : tcp::multi_client_base(service_pump_, m) {} 203 | }; 204 | 205 | }} //namespace 206 | 207 | #endif /* ST_ASIO_SSL_H_ */ 208 | -------------------------------------------------------------------------------- /include/tcp/websocket/ssl/ssl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * websocket/ssh.h 3 | * 4 | * Created on: 2022-6-9 5 | * Author: youngwolf 6 | * email: mail2tao@163.com 7 | * QQ: 676218192 8 | * Community on QQ: 198941541 9 | * 10 | * make st_asio_wrapper support ssl websocket (based on boost::beast) 11 | */ 12 | 13 | #ifndef ST_ASIO_SSL_WEBSOCKET_H_ 14 | #define ST_ASIO_SSL_WEBSOCKET_H_ 15 | 16 | #include 17 | #if BOOST_VERSION >= 107000 18 | #include 19 | #else 20 | #include 21 | namespace boost {namespace beast {template using ssl_stream = boost::asio::ssl::stream;}} 22 | #endif 23 | #include 24 | #include 25 | 26 | #include "../websocket.h" 27 | 28 | namespace st_asio_wrapper { namespace websocket { namespace ssl { 29 | 30 | 31 | template class lowest_layer_getter : public Stream 32 | { 33 | public: 34 | #if BOOST_VERSION >= 107000 35 | typedef typename Stream::next_layer_type::next_layer_type::socket_type lowest_layer_type; 36 | lowest_layer_type& lowest_layer() {return this->next_layer().next_layer().socket();} 37 | const lowest_layer_type& lowest_layer() const {return this->next_layer().next_layer().socket();} 38 | #endif 39 | 40 | public: 41 | template explicit lowest_layer_getter(Args&&... args) : Stream(std::forward(args)...) {} 42 | }; 43 | 44 | template class socket : public Socket 45 | { 46 | public: 47 | template socket(Arg& arg, boost::asio::ssl::context& ctx_) : Socket(arg, ctx_), ctx(ctx_) {} 48 | 49 | public: 50 | virtual void reset() {this->reset_next_layer(ctx); Socket::reset();} 51 | boost::asio::ssl::context& get_context() {return ctx;} 52 | 53 | protected: 54 | virtual void on_handshake(const boost::system::error_code& ec) {show_handshake(ec, "websocket");} 55 | virtual void on_ssl_handshake(const boost::system::error_code& ec) {show_handshake(ec, "ssl");} 56 | 57 | void show_handshake(const boost::system::error_code& ec, const char* type) 58 | { 59 | assert(nullptr != type); 60 | 61 | if (!ec) 62 | this->show_info(type, "handshake success."); 63 | else 64 | this->show_info(ec, type, "handshake failed"); 65 | } 66 | 67 | private: 68 | boost::asio::ssl::context& ctx; 69 | }; 70 | 71 | template class InQueue = ST_ASIO_INPUT_QUEUE, template class InContainer = ST_ASIO_INPUT_CONTAINER, 73 | template class OutQueue = ST_ASIO_OUTPUT_QUEUE, template class OutContainer = ST_ASIO_OUTPUT_CONTAINER> 74 | class client_socket_base : public socket, lowest_layer_getter, InQueue, InContainer, OutQueue, OutContainer>> 75 | { 76 | private: 77 | typedef socket, lowest_layer_getter, InQueue, InContainer, OutQueue, OutContainer>> super; 78 | 79 | public: 80 | client_socket_base(boost::asio::io_context& io_context_, boost::asio::ssl::context& ctx_) : super(io_context_, ctx_) {} 81 | client_socket_base(Matrix& matrix_, boost::asio::ssl::context& ctx_) : super(matrix_, ctx_) {} 82 | 83 | virtual const char* type_name() const {return "ssl websocket (client endpoint)";} 84 | virtual int type_id() const {return 9;} 85 | 86 | protected: 87 | virtual void on_close() 88 | { 89 | this->reset_next_layer(this->get_context()); 90 | super::on_close(); 91 | } 92 | 93 | private: 94 | virtual void connect_handler(const boost::system::error_code& ec) //intercept websocket::client_socket_base::connect_handler 95 | { 96 | if (ec) 97 | return super::connect_handler(ec); 98 | 99 | this->status = super::HANDSHAKING; 100 | 101 | #if BOOST_VERSION >= 107000 102 | // Set a timeout on the operation 103 | //boost::beast::get_lowest_layer(this->next_layer()).expires_after(std::chrono::seconds(30)); 104 | #endif 105 | // Set SNI Hostname (many hosts need this to handshake successfully) 106 | if (!SSL_set_tlsext_host_name(this->next_layer().next_layer().native_handle(), this->get_server_addr().address().to_string().data())) 107 | return super::connect_handler(boost::beast::error_code(static_cast(::ERR_get_error()), boost::asio::error::get_ssl_category())); 108 | 109 | // Perform the SSL handshake 110 | this->next_layer().next_layer().async_handshake(boost::asio::ssl::stream_base::client, this->make_handler_error([this](const boost::system::error_code& ec) {handle_handshake(ec);})); 111 | } 112 | 113 | void handle_handshake(const boost::system::error_code& ec) 114 | { 115 | this->on_ssl_handshake(ec); 116 | ec ? this->force_shutdown() : super::connect_handler(ec); //return to websocket::client_socket_base::connect_handler 117 | } 118 | }; 119 | 120 | template class InQueue = ST_ASIO_INPUT_QUEUE, template class InContainer = ST_ASIO_INPUT_CONTAINER, 122 | template class OutQueue = ST_ASIO_OUTPUT_QUEUE, template class OutContainer = ST_ASIO_OUTPUT_CONTAINER> 123 | class server_socket_base : public socket, lowest_layer_getter, InQueue, InContainer, OutQueue, OutContainer>> 124 | { 125 | private: 126 | typedef socket, lowest_layer_getter, InQueue, InContainer, OutQueue, OutContainer>> super; 127 | 128 | public: 129 | server_socket_base(Server& server_, boost::asio::ssl::context& ctx_) : super(server_, ctx_) {} 130 | 131 | virtual const char* type_name() const {return "ssl websocket (server endpoint)";} 132 | virtual int type_id() const {return 10;} 133 | 134 | protected: 135 | virtual bool do_start() //intercept websocket::server_socket_base::do_start (to add handshake) 136 | { 137 | this->status = super::HANDSHAKING; 138 | 139 | #if BOOST_VERSION >= 107000 140 | // Set the timeout. 141 | //boost::beast::get_lowest_layer(this->next_layer()).expires_after(std::chrono::seconds(30)); 142 | #endif 143 | // Perform the SSL handshake 144 | this->next_layer().next_layer().async_handshake(boost::asio::ssl::stream_base::server, this->make_handler_error([this](const boost::system::error_code& ec) {handle_handshake(ec);})); 145 | return true; 146 | } 147 | 148 | private: 149 | void handle_handshake(const boost::system::error_code& ec) 150 | { 151 | this->on_ssl_handshake(ec); 152 | ec ? this->get_server().del_socket(this->shared_from_this()) : super::do_start(); //return to websocket::server_socket_base::do_start 153 | } 154 | }; 155 | 156 | }}} 157 | 158 | #endif /* ST_ASIO_SSL_WEBSOCKET_H_ */ 159 | -------------------------------------------------------------------------------- /include/tcp/websocket/websocket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * websocket.h 3 | * 4 | * Created on: 2022-5-27 5 | * Author: youngwolf 6 | * email: mail2tao@163.com 7 | * QQ: 676218192 8 | * Community on QQ: 198941541 9 | * 10 | * make st_asio_wrapper support websocket (based on boost::beast) 11 | */ 12 | 13 | #ifndef ST_ASIO_WEBSOCKET_H_ 14 | #define ST_ASIO_WEBSOCKET_H_ 15 | 16 | #include 17 | #include 18 | #if BOOST_VERSION < 107000 19 | namespace boost {namespace beast {using tcp_stream = boost::asio::ip::tcp::socket;}} 20 | #endif 21 | 22 | #include "../client.h" 23 | #include "../server.h" 24 | #include "../client_socket.h" 25 | #include "../server_socket.h" 26 | #include "../../object_pool.h" 27 | 28 | namespace st_asio_wrapper { namespace websocket { 29 | 30 | template class lowest_layer_getter : public Stream 31 | { 32 | public: 33 | #if BOOST_VERSION >= 107000 34 | typedef typename Stream::next_layer_type::socket_type lowest_layer_type; 35 | lowest_layer_type& lowest_layer() {return this->next_layer().socket();} 36 | const lowest_layer_type& lowest_layer() const {return this->next_layer().socket();} 37 | #endif 38 | 39 | public: 40 | template explicit lowest_layer_getter(Args&&... args) : Stream(std::forward(args)...) {} 41 | }; 42 | 43 | template class LowestLayerGetter = lowest_layer_getter> 44 | class stream : public LowestLayerGetter> 45 | { 46 | private: 47 | typedef LowestLayerGetter> super; 48 | 49 | public: 50 | typedef boost::function ReadWriteCallBack; 51 | 52 | public: 53 | template explicit stream(Args&&... args) : super(std::forward(args)...) {first_init();} 54 | 55 | void async_read(const ReadWriteCallBack& call_back) {super::async_read(recv_buff, call_back);} 56 | template bool parse_msg(list& msg_can) 57 | { 58 | #if BOOST_VERSION < 107000 59 | bool re = this->is_message_done() ? (msg_can.emplace_back((const char*) recv_buff.data().data(), recv_buff.size()), true) : false; 60 | recv_buff.consume(-1); 61 | #else 62 | bool re = this->is_message_done() ? (msg_can.emplace_back((const char*) recv_buff.cdata().data(), recv_buff.size()), true) : false; 63 | recv_buff.clear(); 64 | #endif 65 | 66 | return re; 67 | } 68 | template void async_write(const Buffer& buff, const ReadWriteCallBack& call_back) {super::async_write(buff, call_back);} 69 | 70 | protected: 71 | //helper function, just call it in constructor 72 | void first_init() {this->binary(0 != ST_ASIO_WEBSOCKET_BINARY);} 73 | 74 | private: 75 | boost::beast::flat_buffer recv_buff; 76 | }; 77 | 78 | template class reader_writer : public Socket 79 | { 80 | public: 81 | reader_writer(boost::asio::io_context& io_context_) : Socket(io_context_) {} 82 | template reader_writer(boost::asio::io_context& io_context_, Arg& arg) : Socket(io_context_, arg) {} 83 | 84 | protected: 85 | template bool async_read(const CallBack& call_back) {this->next_layer().async_read(call_back); return true;} 86 | bool parse_msg(size_t bytes_transferred, list& msg_can) {return this->next_layer().parse_msg(msg_can);} 87 | 88 | size_t batch_msg_send_size() const {return 0;} 89 | template void async_write(const Buffer& msg_can, const CallBack& call_back) {this->next_layer().async_write(msg_can, call_back);} 90 | }; 91 | 92 | template class socket : public Socket 93 | { 94 | public: 95 | template socket(Arg& arg) : Socket(arg) {} 96 | template socket(Arg1& arg1, Arg2& arg2) : Socket(arg1, arg2) {} 97 | 98 | protected: 99 | virtual void on_handshake(const boost::system::error_code& ec) 100 | { 101 | if (!ec) 102 | this->show_info(nullptr, "handshake success."); 103 | else 104 | this->show_info(ec, nullptr, "handshake failed"); 105 | } 106 | 107 | void shutdown_websocket() 108 | { 109 | this->status = Socket::GRACEFUL_SHUTTING_DOWN; 110 | this->dispatch_in_io_strand([this]() { 111 | this->show_info("websocket link:", "been shutting down."); 112 | this->start_graceful_shutdown_monitoring(); 113 | this->next_layer().async_close(boost::beast::websocket::close_code::normal, this->make_handler_error([this](const boost::system::error_code& ec) { 114 | this->stop_graceful_shutdown_monitoring(); 115 | if (ec) 116 | this->show_info(ec, "websocket link", "async shutdown failed"); 117 | })); 118 | }); 119 | } 120 | }; 121 | 122 | template class LowestLayerGetter = lowest_layer_getter, 123 | template class InQueue = ST_ASIO_INPUT_QUEUE, template class InContainer = ST_ASIO_INPUT_CONTAINER, 124 | template class OutQueue = ST_ASIO_OUTPUT_QUEUE, template class OutContainer = ST_ASIO_OUTPUT_CONTAINER, 125 | template class ReaderWriter = reader_writer> 126 | class client_socket_base : public socket, InQueue, InContainer, OutQueue, OutContainer, ReaderWriter>> 127 | { 128 | private: 129 | typedef socket, InQueue, InContainer, OutQueue, OutContainer, ReaderWriter>> super; 130 | 131 | public: 132 | client_socket_base(boost::asio::io_context& io_context_) : super(io_context_) {} 133 | template client_socket_base(boost::asio::io_context& io_context_, Arg& arg) : super(io_context_, arg) {} 134 | 135 | client_socket_base(Matrix& matrix_) : super(matrix_) {} 136 | template client_socket_base(Matrix& matrix_, Arg& arg) : super(matrix_, arg) {} 137 | 138 | virtual const char* type_name() const {return "websocket (client endpoint)";} 139 | virtual int type_id() const {return 7;} 140 | 141 | //these functions are not thread safe, please note. 142 | void disconnect(bool reconnect = false) {force_shutdown(reconnect);} 143 | void force_shutdown(bool reconnect = false) {graceful_shutdown(reconnect);} 144 | void graceful_shutdown(bool reconnect = false) 145 | { 146 | if (this->is_ready()) 147 | { 148 | this->set_reconnect(reconnect); 149 | shutdown_websocket(); 150 | } 151 | else 152 | super::force_shutdown(reconnect); 153 | } 154 | 155 | protected: 156 | virtual void on_unpack_error() {unified_out::info_out(ST_ASIO_LLF " can not unpack msg.", this->id()); this->unpacker()->dump_left_data(); force_shutdown(this->is_reconnect());} 157 | 158 | virtual void connect_handler(const boost::system::error_code& ec) //intercept tcp::client_socket_base::connect_handler 159 | { 160 | if (ec) 161 | return super::connect_handler(ec); 162 | 163 | this->status = super::HANDSHAKING; 164 | 165 | #if BOOST_VERSION >= 107000 166 | // Turn off the timeout on the tcp_stream, because 167 | // the websocket stream has its own timeout system. 168 | boost::beast::get_lowest_layer(this->next_layer()).expires_never(); 169 | 170 | // Set suggested timeout settings for the websocket 171 | this->next_layer().set_option(boost::beast::websocket::stream_base::timeout::suggested(boost::beast::role_type::client)); 172 | 173 | // Set a decorator to change the User-Agent of the handshake 174 | this->next_layer().set_option(boost::beast::websocket::stream_base::decorator([](boost::beast::websocket::request_type& req) { 175 | req.set(boost::beast::http::field::user_agent, "st_asio_wrapper websocket client based on " BOOST_BEAST_VERSION_STRING); 176 | })); 177 | #endif 178 | // Provide the value of the Host HTTP header during the WebSocket handshake. 179 | // See https://tools.ietf.org/html/rfc7230#section-5.4 180 | // Perform the websocket handshake 181 | this->next_layer().async_handshake(this->endpoint_to_string(this->get_server_addr()), "/", this->make_handler_error([this](const boost::system::error_code& ec) {handle_handshake(ec);})); 182 | } 183 | 184 | private: 185 | void handle_handshake(const boost::system::error_code& ec) 186 | { 187 | this->on_handshake(ec); 188 | ec ? this->force_shutdown() : super::connect_handler(ec); //return to tcp::client_socket_base::connect_handler 189 | } 190 | 191 | using super::shutdown_websocket; 192 | }; 193 | 194 | template class LowestLayerGetter = lowest_layer_getter, 195 | template class InQueue = ST_ASIO_INPUT_QUEUE, template class InContainer = ST_ASIO_INPUT_CONTAINER, 196 | template class OutQueue = ST_ASIO_OUTPUT_QUEUE, template class OutContainer = ST_ASIO_OUTPUT_CONTAINER, 197 | template class ReaderWriter = reader_writer> 198 | class server_socket_base : public socket, InQueue, InContainer, OutQueue, OutContainer, ReaderWriter>> 199 | { 200 | private: 201 | typedef socket, InQueue, InContainer, OutQueue, OutContainer, ReaderWriter>> super; 202 | 203 | public: 204 | server_socket_base(Server& server_) : super(server_) {} 205 | template server_socket_base(Server& server_, Arg& arg) : super(server_, arg) {} 206 | 207 | virtual const char* type_name() const {return "websocket (server endpoint)";} 208 | virtual int type_id() const {return 8;} 209 | 210 | //these functions are not thread safe, please note. 211 | void disconnect() {force_shutdown();} 212 | void force_shutdown() {graceful_shutdown();} 213 | void graceful_shutdown() {if (this->is_ready()) shutdown_websocket(); else super::force_shutdown();} 214 | 215 | protected: 216 | virtual bool do_start() //intercept tcp::server_socket_base::do_start (to add handshake) 217 | { 218 | this->status = super::HANDSHAKING; 219 | 220 | #if BOOST_VERSION >= 107000 221 | // Set suggested timeout settings for the websocket 222 | this->next_layer().set_option(boost::beast::websocket::stream_base::timeout::suggested(boost::beast::role_type::server)); 223 | 224 | // Set a decorator to change the Server of the handshake 225 | this->next_layer().set_option(boost::beast::websocket::stream_base::decorator([](boost::beast::websocket::response_type& res) { 226 | res.set(boost::beast::http::field::server, "st_asio_wrapper websocket server based on " BOOST_BEAST_VERSION_STRING); 227 | })); 228 | #endif 229 | // Accept the websocket handshake 230 | this->next_layer().async_accept(this->make_handler_error([this](const boost::system::error_code& ec) {handle_handshake(ec);})); 231 | return true; 232 | } 233 | 234 | virtual void on_unpack_error() {unified_out::info_out(ST_ASIO_LLF " can not unpack msg.", this->id()); this->unpacker()->dump_left_data(); this->force_shutdown();} 235 | 236 | private: 237 | void handle_handshake(const boost::system::error_code& ec) 238 | { 239 | this->on_handshake(ec); 240 | ec ? this->get_server().del_socket(this->shared_from_this()) : super::do_start(); //return to tcp::server_socket_base::do_start 241 | } 242 | 243 | using super::shutdown_websocket; 244 | }; 245 | 246 | }} //namespace 247 | 248 | #endif /* ST_ASIO_WEBSOCKET_H_ */ 249 | -------------------------------------------------------------------------------- /include/timer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * timer.h 3 | * 4 | * Created on: 2012-3-2 5 | * Author: youngwolf 6 | * email: mail2tao@163.com 7 | * QQ: 676218192 8 | * Community on QQ: 198941541 9 | * 10 | * timer base class 11 | */ 12 | 13 | #ifndef ST_ASIO_TIMER_H_ 14 | #define ST_ASIO_TIMER_H_ 15 | 16 | #ifdef ST_ASIO_USE_STEADY_TIMER 17 | #include 18 | #elif defined(ST_ASIO_USE_SYSTEM_TIMER) 19 | #include 20 | #endif 21 | 22 | #include "base.h" 23 | 24 | //If you inherit a class from class X, your own timer ids must begin from X::TIMER_END 25 | namespace st_asio_wrapper 26 | { 27 | 28 | //timers are identified by id. 29 | //for the same timer in the same timer object, any manipulations are not thread safe, please pay special attention. 30 | //to resolve this defect, we must add a mutex member variable to timer_info, it's not worth. otherwise, they are thread safe. 31 | // 32 | //suppose you have more than one service thread(see service_pump for service thread number controlling), then: 33 | //for same timer object: same timer, on_timer is called in sequence 34 | //for same timer object: distinct timer, on_timer is called concurrently 35 | //for distinct timer object: on_timer is always called concurrently 36 | template 37 | class timer : public Executor 38 | { 39 | public: 40 | #ifdef BOOST_ASIO_HAS_STD_CHRONO 41 | typedef std::chrono::milliseconds milliseconds; 42 | #else 43 | typedef boost::chrono::milliseconds milliseconds; 44 | #endif 45 | 46 | #ifdef ST_ASIO_USE_STEADY_TIMER 47 | typedef boost::asio::steady_timer timer_type; 48 | #else 49 | typedef boost::asio::system_timer timer_type; 50 | #endif 51 | 52 | typedef unsigned short tid; 53 | static const tid TIMER_END = 0; //subclass' id must begin from parent class' TIMER_END 54 | 55 | struct timer_info 56 | { 57 | enum timer_status {TIMER_CREATED, TIMER_STARTED, TIMER_CANCELED}; 58 | 59 | tid id; 60 | unsigned char seq; 61 | timer_status status; 62 | unsigned interval_ms; 63 | timer_type timer; 64 | boost::function call_back; //return true from call_back to continue the timer, or the timer will stop 65 | 66 | timer_info(tid id_, boost::asio::io_context& io_context_) : id(id_), seq(-1), status(TIMER_CREATED), interval_ms(0), timer(io_context_) {} 67 | bool operator ==(const timer_info& other) {return id == other.id;} 68 | bool operator ==(tid id_) {return id == id_;} 69 | }; 70 | typedef const timer_info timer_cinfo; 71 | 72 | timer(boost::asio::io_context& io_context_) : Executor(io_context_), io_context_refs(1) {} 73 | ~timer() {stop_all_timer();} 74 | 75 | unsigned get_io_context_refs() const {return io_context_refs;} 76 | void add_io_context_refs(unsigned count) 77 | { 78 | if (count > 0) 79 | { 80 | io_context_refs += count; 81 | attach_io_context(io_context_, count); 82 | } 83 | } 84 | void sub_io_context_refs(unsigned count) 85 | { 86 | if (count > 0 && io_context_refs >= count) 87 | { 88 | io_context_refs -= count; 89 | detach_io_context(io_context_, count); 90 | } 91 | } 92 | void clear_io_context_refs() {sub_io_context_refs(io_context_refs);} 93 | 94 | //after this call, call_back cannot be used again, please note. 95 | bool create_or_update_timer(tid id, unsigned interval, boost::function& call_back, bool start = false) 96 | { 97 | timer_info* ti = NULL; 98 | { 99 | boost::lock_guard lock(timer_can_mutex); 100 | BOOST_AUTO(iter, std::find(timer_can.begin(), timer_can.end(), id)); 101 | if (iter == timer_can.end()) 102 | { 103 | try {timer_can.emplace_back(id, boost::ref(io_context_)); ti = &timer_can.back();} 104 | catch (const std::exception& e) {unified_out::error_out("cannot create timer %d (%s)", id, e.what()); return false;} 105 | } 106 | else 107 | ti = &*iter; 108 | } 109 | assert(NULL != ti); 110 | 111 | ti->interval_ms = interval; 112 | ti->call_back.swap(call_back); 113 | 114 | if (start) 115 | start_timer(*ti); 116 | 117 | return true; 118 | } 119 | bool create_or_update_timer(tid id, unsigned interval, const boost::function& call_back, bool start = false) 120 | {BOOST_AUTO(unused, call_back); return create_or_update_timer(id, interval, unused, start);} 121 | 122 | bool change_timer_status(tid id, typename timer_info::timer_status status) {BOOST_AUTO(ti, find_timer(id)); return NULL != ti ? ti->status = status, true : false;} 123 | bool change_timer_interval(tid id, unsigned interval) {BOOST_AUTO(ti, find_timer(id)); return NULL != ti ? ti->interval_ms = interval, true : false;} 124 | 125 | //after this call, call_back cannot be used again, please note. 126 | bool change_timer_call_back(tid id, boost::function& call_back) {BOOST_AUTO(ti, find_timer(id)); return NULL != ti ? ti->call_back.swap(call_back), true : false;} 127 | bool change_timer_call_back(tid id, const boost::function& call_back) {BOOST_AUTO(unused, call_back); return change_timer_call_back(id, unused);} 128 | 129 | //after this call, call_back cannot be used again, please note. 130 | bool set_timer(tid id, unsigned interval, boost::function& call_back) {return create_or_update_timer(id, interval, call_back, true);} 131 | bool set_timer(tid id, unsigned interval, const boost::function& call_back) {return create_or_update_timer(id, interval, call_back, true);} 132 | 133 | timer_info* find_timer(tid id) 134 | { 135 | boost::lock_guard lock(timer_can_mutex); 136 | BOOST_AUTO(iter, std::find(timer_can.begin(), timer_can.end(), id)); 137 | if (iter != timer_can.end()) 138 | return &*iter; 139 | 140 | return NULL; 141 | } 142 | 143 | bool is_timer(tid id) {BOOST_AUTO(ti, find_timer(id)); return NULL != ti ? timer_info::TIMER_STARTED == ti->status : false;} 144 | bool start_timer(tid id) {BOOST_AUTO(ti, find_timer(id)); return NULL != ti ? start_timer(*ti) : false;} 145 | void stop_timer(tid id) {BOOST_AUTO(ti, find_timer(id)); if (NULL != ti) stop_timer(*ti);} 146 | void stop_all_timer() {do_something_to_all(boost::bind((void (timer::*) (timer_info&)) &timer::stop_timer, this, boost::placeholders::_1));} 147 | void stop_all_timer(tid excepted_id) 148 | { 149 | do_something_to_all(boost::lambda::if_then(excepted_id != boost::lambda::bind(&timer_info::id, boost::lambda::_1), 150 | boost::lambda::bind((void (timer::*) (timer_info&)) &timer::stop_timer, this, boost::lambda::_1))); 151 | } 152 | 153 | DO_SOMETHING_TO_ALL_MUTEX(timer_can, timer_can_mutex, boost::lock_guard) 154 | DO_SOMETHING_TO_ONE_MUTEX(timer_can, timer_can_mutex, boost::lock_guard) 155 | 156 | protected: 157 | bool start_timer(timer_info& ti, unsigned interval_ms) 158 | { 159 | if (!ti.call_back) 160 | return false; 161 | 162 | ti.status = timer_info::TIMER_STARTED; 163 | #if BOOST_ASIO_VERSION >= 101100 164 | ti.timer.expires_after(milliseconds(interval_ms)); 165 | #else 166 | ti.timer.expires_from_now(milliseconds(interval_ms)); 167 | #endif 168 | 169 | //if timer already started, this will cancel it first 170 | ti.timer.async_wait(ST_THIS make_handler_error(boost::bind(&timer::timer_handler, this, boost::asio::placeholders::error, boost::ref(ti), ++ti.seq))); 171 | return true; 172 | } 173 | bool start_timer(timer_info& ti) {return start_timer(ti, ti.interval_ms);} 174 | 175 | void timer_handler(const boost::system::error_code& ec, timer_info& ti, unsigned char prev_seq) 176 | { 177 | //the first 'timer_info::TIMER_STARTED == ti.status' judgement means stop_timer can also invalidate cumulative timer callbacks 178 | //the second 'timer_info::TIMER_STARTED == ti.status' judgement is used to exclude a particular situation--stop the same timer in call_back and return true 179 | #ifdef ST_ASIO_ALIGNED_TIMER 180 | BOOST_AUTO(begin_time, boost::chrono::system_clock::now()); 181 | if (timer_info::TIMER_STARTED == ti.status && !ec && ti.call_back(ti.id) && timer_info::TIMER_STARTED == ti.status) 182 | { 183 | unsigned elapsed_ms = (unsigned) boost::chrono::duration_cast(boost::chrono::system_clock::now() - begin_time).count(); 184 | if (elapsed_ms > ti.interval_ms) 185 | elapsed_ms %= ti.interval_ms; 186 | 187 | start_timer(ti, ti.interval_ms - elapsed_ms); 188 | } 189 | #else 190 | if (timer_info::TIMER_STARTED == ti.status && !ec && ti.call_back(ti.id) && timer_info::TIMER_STARTED == ti.status) 191 | start_timer(ti); 192 | #endif 193 | else if (prev_seq == ti.seq) //exclude a particular situation--start the same timer in call_back and return false 194 | ti.status = timer_info::TIMER_CANCELED; 195 | } 196 | 197 | void stop_timer(timer_info& ti) 198 | { 199 | if (timer_info::TIMER_STARTED == ti.status) //enable stopping timers that has been stopped 200 | { 201 | ti.status = timer_info::TIMER_CANCELED; //invalidate cumulative timer callbacks first 202 | try {ti.timer.cancel();} 203 | catch (const boost::system::system_error& e) {unified_out::error_out("cannot stop timer %d (%d %s)", ti.id, e.code().value(), e.what());} 204 | } 205 | } 206 | 207 | void reset_io_context_refs() {if (0 == io_context_refs) add_io_context_refs(1);} 208 | virtual void attach_io_context(boost::asio::io_context& io_context_, unsigned refs) {} 209 | virtual void detach_io_context(boost::asio::io_context& io_context_, unsigned refs) {} 210 | 211 | private: 212 | typedef boost::container::list container_type; 213 | container_type timer_can; 214 | boost::mutex timer_can_mutex; 215 | 216 | using Executor::io_context_; 217 | unsigned io_context_refs; 218 | }; 219 | 220 | } //namespace 221 | 222 | #endif /* ST_ASIO_TIMER_H_ */ 223 | -------------------------------------------------------------------------------- /include/tracked_executor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * stracked_executor.h 3 | * 4 | * Created on: 2018-4-19 5 | * Author: youngwolf 6 | * email: mail2tao@163.com 7 | * QQ: 676218192 8 | * Community on QQ: 198941541 9 | * 10 | * the top class 11 | */ 12 | 13 | #ifndef _ST_ASIO_TRACKED_EXECUTOR_H_ 14 | #define _ST_ASIO_TRACKED_EXECUTOR_H_ 15 | 16 | #include "executor.h" 17 | 18 | namespace st_asio_wrapper 19 | { 20 | 21 | #if 0 == ST_ASIO_DELAY_CLOSE 22 | class tracked_executor 23 | { 24 | protected: 25 | tracked_executor(boost::asio::io_context& _io_context_) : io_context_(_io_context_), aci(boost::make_shared((char) ST_ASIO_MIN_ACI_REF)) {} 26 | virtual ~tracked_executor() {} 27 | 28 | public: 29 | typedef boost::function handler_with_error; 30 | typedef boost::function handler_with_error_size; 31 | 32 | bool stopped() const {return io_context_.stopped();} 33 | 34 | #if BOOST_ASIO_VERSION >= 101100 35 | void post(const boost::function& handler) {boost::asio::post(io_context_, (aci, boost::lambda::bind(boost::lambda::unlambda(handler))));} 36 | void defer(const boost::function& handler) {boost::asio::defer(io_context_, (aci, boost::lambda::bind(boost::lambda::unlambda(handler))));} 37 | void dispatch(const boost::function& handler) {boost::asio::dispatch(io_context_, (aci, boost::lambda::bind(boost::lambda::unlambda(handler))));} 38 | void post_strand(boost::asio::io_context::strand& strand, const boost::function& handler) 39 | {boost::asio::post(strand, (aci, boost::lambda::bind(boost::lambda::unlambda(handler))));} 40 | void defer_strand(boost::asio::io_context::strand& strand, const boost::function& handler) 41 | {boost::asio::defer(strand, (aci, boost::lambda::bind(boost::lambda::unlambda(handler))));} 42 | void dispatch_strand(boost::asio::io_context::strand& strand, const boost::function& handler) 43 | {boost::asio::dispatch(strand, (aci, boost::lambda::bind(boost::lambda::unlambda(handler))));} 44 | #else 45 | void post(const boost::function& handler) {io_context_.post((aci, boost::lambda::bind(boost::lambda::unlambda(handler))));} 46 | void dispatch(const boost::function& handler) {io_context_.dispatch((aci, boost::lambda::bind(boost::lambda::unlambda(handler))));} 47 | void post_strand(boost::asio::io_context::strand& strand, const boost::function& handler) 48 | {strand.post((aci, boost::lambda::bind(boost::lambda::unlambda(handler))));} 49 | void dispatch_strand(boost::asio::io_context::strand& strand, const boost::function& handler) 50 | {strand.dispatch((aci, boost::lambda::bind(boost::lambda::unlambda(handler))));} 51 | #endif 52 | 53 | handler_with_error make_handler_error(const handler_with_error& handler) const {return (aci, boost::lambda::bind(boost::lambda::unlambda(handler), boost::lambda::_1));} 54 | handler_with_error_size make_handler_error_size(const handler_with_error_size& handler) const 55 | {return (aci, boost::lambda::bind(boost::lambda::unlambda(handler), boost::lambda::_1, boost::lambda::_2));} 56 | 57 | long get_aci_ref() const {return aci.use_count();} 58 | bool is_async_calling() const {return !aci.unique();} 59 | int is_last_async_call() const //can only be called in callbacks, 0-not, -1-fault error, 1-yes 60 | { 61 | long cur_ref = aci.use_count(); 62 | if (cur_ref > *aci) 63 | return 0; 64 | 65 | return cur_ref < *aci ? -1 : 1; 66 | } 67 | inline void set_async_calling(bool) {} 68 | 69 | protected: 70 | boost::asio::io_context& io_context_; 71 | 72 | private: 73 | boost::shared_ptr aci; //asynchronous calling indicator 74 | }; 75 | #else 76 | class tracked_executor : public executor 77 | { 78 | protected: 79 | tracked_executor(boost::asio::io_context& io_context_) : executor(io_context_), aci(false) {} 80 | 81 | public: 82 | inline long get_aci_ref() const {return -1;} //na 83 | inline bool is_async_calling() const {return aci;} 84 | inline int is_last_async_call() const {return 1;} //1-yes 85 | inline void set_async_calling(bool value) {aci = value;} 86 | 87 | private: 88 | bool aci; //asynchronous calling indicator 89 | }; 90 | #endif 91 | 92 | } //namespace 93 | 94 | #endif /* _ST_ASIO_TRACKED_EXECUTOR_H_ */ 95 | -------------------------------------------------------------------------------- /include/udp/alias.h: -------------------------------------------------------------------------------- 1 | /* 2 | * alias.h 3 | * 4 | * Created on: 2017-7-17 5 | * Author: youngwolf 6 | * email: mail2tao@163.com 7 | * QQ: 676218192 8 | * Community on QQ: 198941541 9 | * 10 | * some alias, they are deprecated. 11 | */ 12 | 13 | #ifndef ST_ASIO_UDP_ALIAS_H_ 14 | #define ST_ASIO_UDP_ALIAS_H_ 15 | 16 | #include "socket_service.h" 17 | 18 | namespace st_asio_wrapper { namespace udp { 19 | 20 | template, typename Matrix = i_matrix> class service_base : public multi_socket_service_base 21 | { 22 | public: 23 | service_base(service_pump& service_pump_) : multi_socket_service_base(service_pump_) {} 24 | }; 25 | 26 | }} //namespace 27 | 28 | #endif /* ST_ASIO_UDP_ALIAS_H_ */ 29 | -------------------------------------------------------------------------------- /include/udp/reliable_socket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * reliable_socket.h 3 | * 4 | * Created on: 2021-9-3 5 | * Author: youngwolf 6 | * email: mail2tao@163.com 7 | * QQ: 676218192 8 | * Community on QQ: 198941541 9 | * 10 | * reliable UDP socket 11 | */ 12 | 13 | #ifndef ST_ASIO_RELIABLE_UDP_SOCKET_H_ 14 | #define ST_ASIO_RELIABLE_UDP_SOCKET_H_ 15 | 16 | #include 17 | 18 | #include "socket.h" 19 | 20 | namespace st_asio_wrapper { namespace udp { 21 | 22 | template class InQueue = ST_ASIO_INPUT_QUEUE, template class InContainer = ST_ASIO_INPUT_CONTAINER, 24 | template class OutQueue = ST_ASIO_OUTPUT_QUEUE, template class OutContainer = ST_ASIO_OUTPUT_CONTAINER> 25 | class reliable_socket_base : public socket_base 26 | { 27 | private: 28 | typedef socket_base super; 29 | 30 | public: 31 | static const typename super::tid TIMER_BEGIN = super::TIMER_END; 32 | static const typename super::tid TIMER_CC = TIMER_BEGIN; 33 | static const typename super::tid TIMER_KCP_UPDATE = TIMER_BEGIN + 1; 34 | static const typename super::tid TIMER_END = TIMER_BEGIN + 5; 35 | 36 | public: 37 | reliable_socket_base(boost::asio::io_context& io_context_) : super(io_context_), kcp(NULL), max_nsnd_que(ST_ASIO_RELIABLE_UDP_NSND_QUE) {} 38 | reliable_socket_base(Matrix& matrix_) : super(matrix_), kcp(NULL), max_nsnd_que(ST_ASIO_RELIABLE_UDP_NSND_QUE) {} 39 | ~reliable_socket_base() {release_kcp();} 40 | 41 | ikcpcb* get_kcpcb() {return kcp;} 42 | ikcpcb* create_kcpcb(IUINT32 conv, void* user) {if (ST_THIS started()) return NULL; release_kcp(); return (kcp = ikcp_create(conv, user));} 43 | 44 | IUINT32 get_max_nsnd_que() const {return max_nsnd_que;} 45 | void set_max_nsnd_que(IUINT32 max_nsnd_que_) {max_nsnd_que = max_nsnd_que_;} 46 | 47 | int output(const char* buf, int len) 48 | { 49 | boost::system::error_code ec; 50 | ST_THIS next_layer().send(boost::asio::buffer(buf, (size_t) len), 0, ec); 51 | return ec ? (unified_out::error_out(ST_ASIO_LLF " send msg error (%d)", ST_THIS id(), ec.value()), 0) : len; 52 | } 53 | 54 | //from kpc's test.h 55 | /* get system time */ 56 | static inline void itimeofday(long *sec, long *usec) 57 | { 58 | #if defined(__unix) 59 | struct timeval time; 60 | gettimeofday(&time, NULL); 61 | if (sec) *sec = time.tv_sec; 62 | if (usec) *usec = time.tv_usec; 63 | #else 64 | static long mode = 0, addsec = 0; 65 | BOOL retval; 66 | static IINT64 freq = 1; 67 | IINT64 qpc; 68 | if (mode == 0) { 69 | retval = QueryPerformanceFrequency((LARGE_INTEGER*)&freq); 70 | freq = (freq == 0)? 1 : freq; 71 | retval = QueryPerformanceCounter((LARGE_INTEGER*)&qpc); 72 | addsec = (long)time(NULL); 73 | addsec = addsec - (long)((qpc / freq) & 0x7fffffff); 74 | mode = 1; 75 | } 76 | retval = QueryPerformanceCounter((LARGE_INTEGER*)&qpc); 77 | retval = retval * 2; 78 | if (sec) *sec = (long)(qpc / freq) + addsec; 79 | if (usec) *usec = (long)((qpc % freq) * 1000000 / freq); 80 | #endif 81 | } 82 | 83 | /* get clock in millisecond 64 */ 84 | static inline IINT64 iclock64(void) 85 | { 86 | long s, u; 87 | IINT64 value; 88 | itimeofday(&s, &u); 89 | value = ((IINT64)s) * 1000 + (u / 1000); 90 | return value; 91 | } 92 | 93 | static inline IUINT32 iclock() 94 | { 95 | return (IUINT32)(iclock64() & 0xfffffffful); 96 | } 97 | //from kpc's test.h 98 | 99 | protected: 100 | virtual bool do_start() 101 | { 102 | if (NULL != kcp) 103 | { 104 | IUINT32 now = iclock(); 105 | ST_THIS set_timer(TIMER_KCP_UPDATE, ikcp_check(kcp, now) - now, boost::bind(&reliable_socket_base::timer_handler, this, boost::placeholders::_1)); 106 | } 107 | 108 | return super::do_start(); 109 | } 110 | 111 | virtual void on_close() {release_kcp(); super::on_close();} 112 | 113 | virtual bool check_send_cc() //congestion control, return true means can continue to send messages 114 | { 115 | boost::lock_guard lock(mutex); 116 | if (NULL == kcp || kcp->nsnd_que <= max_nsnd_que) 117 | return true; 118 | 119 | ST_THIS set_timer(TIMER_CC, 10, boost::bind(&reliable_socket_base::timer_handler, this, boost::placeholders::_1)); 120 | return false; 121 | } 122 | 123 | virtual bool do_send_msg(const typename super::in_msg& msg) 124 | { 125 | boost::lock_guard lock(mutex); 126 | if (NULL == kcp) 127 | return false; 128 | 129 | int re = ikcp_send(kcp, msg.data(), (long) msg.size()); 130 | if (re < 0) 131 | unified_out::error_out("ikcp_send return error: %d", re); 132 | else 133 | ikcp_update(kcp, iclock()); 134 | 135 | return true; 136 | } 137 | 138 | virtual void pre_handle_msg(typename Unpacker::container_type& msg_can) 139 | { 140 | boost::lock_guard lock(mutex); 141 | if (NULL == kcp) 142 | return; 143 | 144 | for (BOOST_AUTO(iter, msg_can.begin()); iter != msg_can.end(); ++iter) 145 | { 146 | int re = ikcp_input(kcp, iter->data(), (long) iter->size()); 147 | if (re < 0) 148 | unified_out::error_out("ikcp_input return error: %d", re); 149 | else 150 | ikcp_update(kcp, iclock()); 151 | } 152 | 153 | msg_can.clear(); 154 | char buff[ST_ASIO_MSG_BUFFER_SIZE]; 155 | while (true) 156 | { 157 | int re = ikcp_recv(kcp, buff, sizeof(buff)); 158 | if (re < 0) 159 | break; 160 | 161 | ST_THIS unpacker()->compose_msg(buff, (size_t) re, msg_can); 162 | } 163 | } 164 | 165 | private: 166 | bool timer_handler(typename super::tid id) 167 | { 168 | switch (id) 169 | { 170 | case TIMER_CC: 171 | if (NULL != kcp) 172 | { 173 | boost::unique_lock lock(mutex); 174 | if (kcp->nsnd_que > max_nsnd_que) 175 | return true; //continue CC 176 | lock.unlock(); 177 | 178 | super::resume_sending(); 179 | } 180 | break; 181 | case TIMER_KCP_UPDATE: 182 | if (NULL != kcp) 183 | { 184 | boost::lock_guard lock(mutex); 185 | IUINT32 now = iclock(); 186 | ikcp_update(kcp, now); 187 | 188 | ST_THIS change_timer_interval(id, ikcp_check(kcp, now) - now); 189 | return true; 190 | } 191 | break; 192 | default: 193 | assert(false); 194 | break; 195 | } 196 | 197 | return false; 198 | } 199 | 200 | void release_kcp() {if (NULL != kcp) ikcp_release(kcp); kcp = NULL;} 201 | 202 | private: 203 | ikcpcb* kcp; 204 | boost::mutex mutex; 205 | 206 | IUINT32 max_nsnd_que; 207 | }; 208 | 209 | }} //namespace 210 | 211 | #endif /* ST_ASIO_RELIABLE_UDP_SOCKET_H_ */ 212 | -------------------------------------------------------------------------------- /include/udp/socket_service.h: -------------------------------------------------------------------------------- 1 | /* 2 | * socket_service.h 3 | * 4 | * Created on: 2012-3-2 5 | * Author: youngwolf 6 | * email: mail2tao@163.com 7 | * QQ: 676218192 8 | * Community on QQ: 198941541 9 | * 10 | * UDP socket service 11 | */ 12 | 13 | #ifndef ST_ASIO_UDP_SOCKET_SERVICE_H_ 14 | #define ST_ASIO_UDP_SOCKET_SERVICE_H_ 15 | 16 | #include "../socket_service.h" 17 | 18 | namespace st_asio_wrapper { namespace udp { 19 | 20 | template class single_socket_service_base : public single_socket_service 21 | { 22 | public: 23 | single_socket_service_base(service_pump& service_pump_) : single_socket_service(service_pump_) {} 24 | }; 25 | 26 | template, typename Matrix = i_matrix> 27 | class multi_socket_service_base : public multi_socket_service 28 | { 29 | private: 30 | typedef multi_socket_service super; 31 | 32 | public: 33 | multi_socket_service_base(service_pump& service_pump_) : super(service_pump_) {} 34 | 35 | using super::add_socket; 36 | typename Pool::object_type add_socket(unsigned short port, const std::string& ip = std::string(), unsigned additional_io_context_refs = 0) 37 | { 38 | BOOST_AUTO(socket_ptr, ST_THIS create_object()); 39 | if (!socket_ptr) 40 | return socket_ptr; 41 | 42 | socket_ptr->set_local_addr(port, ip); 43 | return add_socket(socket_ptr, additional_io_context_refs) ? socket_ptr : typename Pool::object_type(); 44 | } 45 | typename Pool::object_type add_socket(unsigned short port, unsigned short peer_port, const std::string& ip = std::string(), const std::string& peer_ip = std::string(), 46 | unsigned additional_io_context_refs = 0) 47 | { 48 | BOOST_AUTO(socket_ptr, ST_THIS create_object()); 49 | if (!socket_ptr) 50 | return socket_ptr; 51 | 52 | socket_ptr->set_local_addr(port, ip); 53 | socket_ptr->set_peer_addr(peer_port, peer_ip); 54 | return add_socket(socket_ptr, additional_io_context_refs) ? socket_ptr : typename Pool::object_type(); 55 | } 56 | 57 | //functions with a socket_ptr parameter will remove the link from object pool first, then call corresponding function 58 | void disconnect(typename Pool::object_ctype& socket_ptr) {ST_THIS del_object(socket_ptr); socket_ptr->disconnect();} 59 | void disconnect() {ST_THIS do_something_to_all(boost::mem_fn(&Socket::disconnect));} 60 | void force_shutdown(typename Pool::object_ctype& socket_ptr) {ST_THIS del_object(socket_ptr); socket_ptr->force_shutdown();} 61 | void force_shutdown() {ST_THIS do_something_to_all(boost::mem_fn(&Socket::force_shutdown));} 62 | void graceful_shutdown(typename Pool::object_ctype& socket_ptr) {ST_THIS del_object(socket_ptr); socket_ptr->graceful_shutdown();} 63 | void graceful_shutdown() {ST_THIS do_something_to_all(boost::mem_fn(&Socket::graceful_shutdown));} 64 | 65 | protected: 66 | virtual void uninit() {ST_THIS stop(); force_shutdown();} 67 | }; 68 | 69 | }} //namespace 70 | 71 | #endif /* ST_ASIO_UDP_SOCKET_SERVICE_H_ */ 72 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | 2 | ST_MAKE = ${MAKE_COMMAND} 3 | ifeq (${MAKECMDGOALS}, debug) 4 | ST_MAKE += debug 5 | else 6 | ifeq (${MAKECMDGOALS}, clean) 7 | ST_MAKE += clean 8 | endif 9 | endif 10 | 11 | target_machine = ${shell ${CXX} -dumpmachine} 12 | 13 | release debug clean : 14 | cd echo_server && ${ST_MAKE} 15 | cd echo_client && ${ST_MAKE} 16 | cd client && ${ST_MAKE} 17 | cd file_server && ${ST_MAKE} 18 | cd file_client && ${ST_MAKE} 19 | cd pingpong_server && ${ST_MAKE} 20 | cd pingpong_client && ${ST_MAKE} 21 | cd concurrent_server && ${ST_MAKE} 22 | cd concurrent_client && ${ST_MAKE} 23 | cd socket_management && ${ST_MAKE} 24 | cd udp_test && ${ST_MAKE} 25 | cd ssl_test && ${ST_MAKE} 26 | cd websocket_test && ${ST_MAKE} 27 | cd ssl_websocket_test && ${ST_MAKE} 28 | ifeq (, ${findstring cygwin, ${target_machine}}) 29 | ifeq (, ${findstring mingw, ${target_machine}}) 30 | cd unix_socket && ${ST_MAKE} 31 | cd unix_udp_test && ${ST_MAKE} 32 | endif 33 | endif 34 | 35 | -------------------------------------------------------------------------------- /pingpong_client/makefile: -------------------------------------------------------------------------------- 1 | 2 | module = pingpong_client 3 | ext_libs = -lboost_timer 4 | 5 | include ../config.mk 6 | 7 | -------------------------------------------------------------------------------- /pingpong_client/pingpong_client.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | //configuration 7 | #define ST_ASIO_SERVER_PORT 9527 8 | #define ST_ASIO_REUSE_OBJECT //use objects pool 9 | #define ST_ASIO_DELAY_CLOSE 5 //define this to avoid hooks for async call (and slightly improve performance) 10 | #define ST_ASIO_SYNC_DISPATCH 11 | //#define ST_ASIO_WANT_MSG_SEND_NOTIFY 12 | #define ST_ASIO_MSG_BUFFER_SIZE 65536 13 | #define ST_ASIO_DEFAULT_UNPACKER stream_unpacker //non-protocol 14 | #define ST_ASIO_DECREASE_THREAD_AT_RUNTIME 15 | //configuration 16 | 17 | #include "../include/ext/tcp.h" 18 | using namespace st_asio_wrapper; 19 | //using namespace st_asio_wrapper::tcp; 20 | using namespace st_asio_wrapper::ext; 21 | using namespace st_asio_wrapper::ext::tcp; 22 | 23 | #define QUIT_COMMAND "quit" 24 | #define STATUS "status" 25 | #define STATISTIC "statistic" 26 | #define LIST_ALL_CLIENT "list all client" 27 | #define INCREASE_THREAD "increase thread" 28 | #define DECREASE_THREAD "decrease thread" 29 | 30 | boost::timer::cpu_timer begin_time; 31 | #if BOOST_VERSION >= 105300 32 | boost::atomic_ushort completed_session_num; 33 | #else 34 | atomic completed_session_num; 35 | #endif 36 | 37 | class echo_socket : public client_socket 38 | { 39 | public: 40 | echo_socket(i_matrix& matrix_) : client_socket(matrix_) {} 41 | 42 | void begin(size_t msg_num, const char* msg, size_t msg_len) 43 | { 44 | total_bytes = msg_len; 45 | total_bytes *= msg_num; 46 | send_bytes = recv_bytes = 0; 47 | 48 | send_native_msg(msg, msg_len, false); 49 | } 50 | 51 | protected: 52 | virtual void on_connect() {boost::asio::ip::tcp::no_delay option(true); lowest_layer().set_option(option); client_socket::on_connect();} 53 | 54 | //msg handling, must define macro ST_ASIO_SYNC_DISPATCH 55 | //do not hold msg_can for further usage, access msg_can and return from on_msg as quickly as possible 56 | //access msg_can freely within this callback, it's always thread safe. 57 | virtual size_t on_msg(list& msg_can) 58 | { 59 | st_asio_wrapper::do_something_to_all(msg_can, boost::bind(&echo_socket::handle_msg, this, boost::placeholders::_1)); 60 | BOOST_AUTO(re, msg_can.size()); 61 | msg_can.clear(); //if we left behind some messages in msg_can, they will be dispatched via on_msg_handle asynchronously, which means it's 62 | //possible that on_msg_handle be invoked concurrently with the next on_msg (new messages arrived) and then disorder messages. 63 | //here we always consumed all messages, so we can use sync message dispatching, otherwise, we should not use sync message dispatching 64 | //except we can bear message disordering. 65 | 66 | return re; 67 | } 68 | //msg handling end 69 | 70 | #ifdef ST_ASIO_WANT_MSG_SEND_NOTIFY 71 | virtual void on_msg_send(in_msg_type& msg) 72 | { 73 | send_bytes += msg.size(); 74 | if (send_bytes < total_bytes) 75 | direct_send_msg(msg, true); 76 | } 77 | 78 | private: 79 | void handle_msg(out_msg_ctype& msg) 80 | { 81 | recv_bytes += msg.size(); 82 | if (recv_bytes >= total_bytes && 0 == --completed_session_num) 83 | begin_time.stop(); 84 | } 85 | #else 86 | private: 87 | void handle_msg(out_msg_type& msg) 88 | { 89 | if (0 == total_bytes) 90 | return; 91 | 92 | recv_bytes += msg.size(); 93 | if (recv_bytes >= total_bytes) 94 | { 95 | total_bytes = 0; 96 | if (0 == --completed_session_num) 97 | begin_time.stop(); 98 | } 99 | else 100 | direct_send_msg(msg, true); 101 | //if the type of out_msg_type and in_msg_type are not identical, the compilation will fail, then you should use send_native_msg instead. 102 | } 103 | #endif 104 | 105 | private: 106 | boost::uint64_t total_bytes, send_bytes, recv_bytes; 107 | }; 108 | 109 | class echo_client : public st_asio_wrapper::tcp::multi_client_base 110 | { 111 | public: 112 | echo_client(service_pump& service_pump_) : multi_client_base(service_pump_) {} 113 | 114 | void begin(size_t msg_num, const char* msg, size_t msg_len) {do_something_to_all(boost::bind(&echo_socket::begin, boost::placeholders::_1, msg_num, msg, msg_len));} 115 | }; 116 | 117 | int main(int argc, const char* argv[]) 118 | { 119 | printf("usage: %s [ [ [ [link num=16]]]]\n", argv[0], ST_ASIO_SERVER_PORT, ST_ASIO_SERVER_IP); 120 | if (argc >= 2 && (0 == strcmp(argv[1], "--help") || 0 == strcmp(argv[1], "-h"))) 121 | return 0; 122 | else 123 | puts("type " QUIT_COMMAND " to end."); 124 | 125 | /////////////////////////////////////////////////////////// 126 | size_t link_num = 16; 127 | if (argc > 4) 128 | link_num = std::min(ST_ASIO_MAX_OBJECT_NUM, std::max(atoi(argv[4]), 1)); 129 | 130 | printf("exec: pingpong_client with " ST_ASIO_SF " links\n", link_num); 131 | /////////////////////////////////////////////////////////// 132 | 133 | service_pump sp; 134 | echo_client client(sp); 135 | 136 | // argv[3] = "::1" //ipv6 137 | // argv[3] = "127.0.0.1" //ipv4 138 | std::string ip = argc > 3 ? argv[3] : ST_ASIO_SERVER_IP; 139 | unsigned short port = argc > 2 ? atoi(argv[2]) : ST_ASIO_SERVER_PORT; 140 | 141 | int thread_num = 1; 142 | if (argc > 1) 143 | thread_num = std::min(16, std::max(thread_num, atoi(argv[1]))); 144 | //add one thread will seriously impact IO throughput when doing performance benchmark, this is because the business logic is very simple (send original messages back, 145 | //or just add up total message size), under this scenario, just one service thread without receiving buffer will obtain the best IO throughput. 146 | //the server has such behavior too. 147 | 148 | for (size_t i = 0; i < link_num; ++i) 149 | client.add_socket(port, ip); 150 | 151 | sp.start_service(thread_num); 152 | while(sp.is_running()) 153 | { 154 | std::string str; 155 | std::getline(std::cin, str); 156 | if (str.empty()) 157 | ; 158 | else if (QUIT_COMMAND == str) 159 | sp.stop_service(); 160 | else if (STATISTIC == str) 161 | { 162 | printf("link #: " ST_ASIO_SF ", valid links: " ST_ASIO_SF ", invalid links: " ST_ASIO_SF "\n\n", client.size(), client.valid_size(), client.invalid_object_size()); 163 | puts(client.get_statistic().to_string().data()); 164 | } 165 | else if (STATUS == str) 166 | client.list_all_status(); 167 | else if (LIST_ALL_CLIENT == str) 168 | client.list_all_object(); 169 | else if (INCREASE_THREAD == str) 170 | sp.add_service_thread(1); 171 | else if (DECREASE_THREAD == str) 172 | sp.del_service_thread(1); 173 | else 174 | { 175 | size_t msg_num = 1024; 176 | size_t msg_len = 1024; //must greater than or equal to sizeof(size_t) 177 | char msg_fill = '0'; 178 | 179 | boost::char_separator sep(" \t"); 180 | boost::tokenizer > tok(str, sep); 181 | BOOST_AUTO(iter, tok.begin()); 182 | if (iter != tok.end()) msg_num = std::max((size_t) atoi(iter++->data()), (size_t) 1); 183 | if (iter != tok.end()) msg_len = std::min((size_t) ST_ASIO_MSG_BUFFER_SIZE, std::max((size_t) atoi(iter++->data()), (size_t) 1)); 184 | if (iter != tok.end()) msg_fill = *iter++->data(); 185 | 186 | printf("test parameters after adjustment: " ST_ASIO_SF " " ST_ASIO_SF " %c\n", msg_num, msg_len, msg_fill); 187 | puts("performance test begin, this application will have no response during the test!"); 188 | 189 | completed_session_num = (unsigned short) link_num; 190 | char* init_msg = new char[msg_len]; 191 | memset(init_msg, msg_fill, msg_len); 192 | client.begin(msg_num, init_msg, msg_len); 193 | begin_time.start(); 194 | 195 | while (0 != completed_session_num) 196 | boost::this_thread::sleep_for(boost::chrono::milliseconds(50)); 197 | 198 | boost::uint64_t total_msg_bytes = link_num; total_msg_bytes *= msg_len; total_msg_bytes *= msg_num; 199 | double used_time = (double) begin_time.elapsed().wall / 1000000000; 200 | printf("finished in %f seconds, TPS: %f(*2), speed: %f(*2) MBps.\n", used_time, link_num * msg_num / used_time, total_msg_bytes / used_time / 1024 / 1024); 201 | 202 | delete[] init_msg; 203 | } 204 | } 205 | 206 | return 0; 207 | } 208 | -------------------------------------------------------------------------------- /pingpong_client/pingpong_client.vcproj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngwolf-project/st_asio_wrapper/3e060755ca6a8fc2ebfed8ccc41c561ad783a211/pingpong_client/pingpong_client.vcproj -------------------------------------------------------------------------------- /pingpong_server/makefile: -------------------------------------------------------------------------------- 1 | 2 | module = pingpong_server 3 | 4 | include ../config.mk 5 | 6 | -------------------------------------------------------------------------------- /pingpong_server/pingpong_server.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | //configuration 5 | #define ST_ASIO_SERVER_PORT 9527 6 | #define ST_ASIO_REUSE_OBJECT //use objects pool 7 | #define ST_ASIO_DELAY_CLOSE 5 //define this to avoid hooks for async call (and slightly improve performance) 8 | #define ST_ASIO_SYNC_DISPATCH 9 | #define ST_ASIO_MSG_BUFFER_SIZE 65536 10 | #define ST_ASIO_DEFAULT_UNPACKER stream_unpacker //non-protocol 11 | #define ST_ASIO_DECREASE_THREAD_AT_RUNTIME 12 | //configuration 13 | 14 | #include "../include/ext/tcp.h" 15 | using namespace st_asio_wrapper; 16 | //using namespace st_asio_wrapper::tcp; 17 | using namespace st_asio_wrapper::ext::tcp; 18 | 19 | #define QUIT_COMMAND "quit" 20 | #define STATUS "status" 21 | #define STATISTIC "statistic" 22 | #define LIST_ALL_CLIENT "list all client" 23 | #define INCREASE_THREAD "increase thread" 24 | #define DECREASE_THREAD "decrease thread" 25 | 26 | class echo_socket : public server_socket 27 | { 28 | public: 29 | echo_socket(tcp::i_server& server_) : server_socket(server_) {} 30 | 31 | protected: 32 | //msg handling: send the original msg back(echo server), must define macro ST_ASIO_SYNC_DISPATCH 33 | //do not hold msg_can for further usage, access msg_can and return from on_msg as quickly as possible 34 | //access msg_can freely within this callback, it's always thread safe. 35 | virtual size_t on_msg(list& msg_can) 36 | { 37 | //if the type of out_msg_type and in_msg_type are not identical, the compilation will fail, then you should use send_native_msg instead. 38 | for (BOOST_AUTO(iter, msg_can.begin()); iter != msg_can.end(); ++iter) direct_send_msg(*iter); 39 | BOOST_AUTO(re, msg_can.size()); 40 | msg_can.clear(); //if we left behind some messages in msg_can, they will be dispatched via on_msg_handle asynchronously, which means it's 41 | //possible that on_msg_handle be invoked concurrently with the next on_msg (new messages arrived) and then disorder messages. 42 | //here we always consumed all messages, so we can use sync message dispatching, otherwise, we should not use sync message dispatching 43 | //except we can bear message disordering. 44 | 45 | return re; 46 | } 47 | //msg handling end 48 | }; 49 | 50 | class echo_server : public tcp::server_base 51 | { 52 | public: 53 | echo_server(service_pump& service_pump_) : server_base(service_pump_) {} 54 | 55 | protected: 56 | virtual bool on_accept(object_ctype& socket_ptr) {boost::asio::ip::tcp::no_delay option(true); socket_ptr->lowest_layer().set_option(option); return true;} 57 | }; 58 | 59 | int main(int argc, const char* argv[]) 60 | { 61 | printf("usage: %s [ [ [ip=0.0.0.0]]]\n", argv[0], ST_ASIO_SERVER_PORT); 62 | if (argc >= 2 && (0 == strcmp(argv[1], "--help") || 0 == strcmp(argv[1], "-h"))) 63 | return 0; 64 | else 65 | puts("type " QUIT_COMMAND " to end."); 66 | 67 | service_pump sp; 68 | echo_server echo_server_(sp); 69 | 70 | if (argc > 3) 71 | echo_server_.set_server_addr(atoi(argv[2]), argv[3]); 72 | else if (argc > 2) 73 | echo_server_.set_server_addr(atoi(argv[2])); 74 | 75 | int thread_num = 1; 76 | if (argc > 1) 77 | thread_num = std::min(16, std::max(thread_num, atoi(argv[1]))); 78 | 79 | sp.start_service(thread_num); 80 | while(sp.is_running()) 81 | { 82 | std::string str; 83 | std::getline(std::cin, str); 84 | if (str.empty()) 85 | ; 86 | else if (QUIT_COMMAND == str) 87 | sp.stop_service(); 88 | else if (STATISTIC == str) 89 | { 90 | printf("link #: " ST_ASIO_SF ", invalid links: " ST_ASIO_SF "\n\n", echo_server_.size(), echo_server_.invalid_object_size()); 91 | puts(echo_server_.get_statistic().to_string().data()); 92 | } 93 | else if (STATUS == str) 94 | echo_server_.list_all_status(); 95 | else if (LIST_ALL_CLIENT == str) 96 | echo_server_.list_all_object(); 97 | else if (INCREASE_THREAD == str) 98 | sp.add_service_thread(1); 99 | else if (DECREASE_THREAD == str) 100 | sp.del_service_thread(1); 101 | } 102 | 103 | return 0; 104 | } 105 | -------------------------------------------------------------------------------- /pingpong_server/pingpong_server.vcproj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngwolf-project/st_asio_wrapper/3e060755ca6a8fc2ebfed8ccc41c561ad783a211/pingpong_server/pingpong_server.vcproj -------------------------------------------------------------------------------- /socket_management/client.h: -------------------------------------------------------------------------------- 1 | #ifndef _CLIENT_H_ 2 | #define _CLIENT_H_ 3 | 4 | //demonstrates how to call multi_client_base in client_socket_base (just like server_socket_base call server_base) 5 | class my_matrix : public i_matrix 6 | { 7 | public: 8 | virtual bool del_link(const std::string& name) = 0; 9 | }; 10 | 11 | typedef client_socket_base my_client_socket_base; 12 | class my_client_socket : public my_client_socket_base 13 | { 14 | public: 15 | my_client_socket(my_matrix& matrix_) : my_client_socket_base(matrix_) 16 | { 17 | #if 3 == PACKER_UNPACKER_TYPE 18 | boost::dynamic_pointer_cast(packer())->prefix_suffix("", "\n"); 19 | boost::dynamic_pointer_cast(unpacker())->prefix_suffix("", "\n"); 20 | #endif 21 | } 22 | 23 | void name(const std::string& name_) {_name = name_;} 24 | const std::string& name() const {return _name;} 25 | 26 | protected: 27 | //msg handling 28 | #if 2 == PACKER_UNPACKER_TYPE 29 | //fixed_length_unpacker uses basic_buffer as its message type, it doesn't append additional \0 to the end of the message as std::string does, 30 | //so it cannot be printed by printf. 31 | virtual bool on_msg_handle(out_msg_type& msg) {printf("received: " ST_ASIO_SF ", I'm %s\n", msg.size(), _name.data()); return true;} 32 | #else 33 | virtual bool on_msg_handle(out_msg_type& msg) {printf("received: %s, I'm %s\n", msg.data(), _name.data()); return true;} 34 | #endif 35 | //msg handling end 36 | 37 | virtual void on_recv_error(const boost::system::error_code& ec) {get_matrix()->del_link(_name); my_client_socket_base::on_recv_error(ec);} 38 | 39 | private: 40 | std::string _name; 41 | }; 42 | 43 | typedef multi_client_base, my_matrix> my_client_base; 44 | class my_client : public my_client_base 45 | { 46 | public: 47 | my_client(service_pump& service_pump_) : my_client_base(service_pump_) {} 48 | 49 | bool add_link(const std::string& name) 50 | { 51 | boost::lock_guard lock(link_map_mutex); 52 | if (link_map.count(name) > 0) 53 | printf("%s already exists.\n", name.data()); 54 | else 55 | { 56 | BOOST_AUTO(socket_ptr, create_object()); 57 | assert(socket_ptr); 58 | 59 | socket_ptr->name(name); 60 | //socket_ptr->set_server_addr(9527, "127.0.0.1"); //if you want to set server ip, do it at here like this 61 | 62 | if (add_socket(socket_ptr)) //exceed ST_ASIO_MAX_OBJECT_NUM 63 | { 64 | printf("add socket %s.\n", name.data()); 65 | link_map[name] = socket_ptr; 66 | 67 | return true; 68 | } 69 | } 70 | 71 | return false; 72 | } 73 | 74 | object_type find_link(const std::string& name) 75 | { 76 | boost::lock_guard lock(link_map_mutex); 77 | BOOST_AUTO(iter, link_map.find(name)); 78 | return iter != link_map.end() ? iter->second : object_type(); 79 | } 80 | 81 | object_type find_and_remove_link(const std::string& name) 82 | { 83 | object_type socket_ptr; 84 | 85 | boost::lock_guard lock(link_map_mutex); 86 | BOOST_AUTO(iter, link_map.find(name)); 87 | if (iter != link_map.end()) 88 | { 89 | socket_ptr = iter->second; 90 | link_map.erase(iter); 91 | } 92 | 93 | return socket_ptr; 94 | } 95 | 96 | bool shutdown_link(const std::string& name) 97 | { 98 | BOOST_AUTO(socket_ptr, find_and_remove_link(name)); 99 | return socket_ptr ? (socket_ptr->force_shutdown(), true) : false; 100 | } 101 | 102 | bool send_msg(const std::string& name, const std::string& msg) {std::string unused(msg); return send_msg(name, unused);} 103 | bool send_msg(const std::string& name, std::string& msg) 104 | { 105 | BOOST_AUTO(socket_ptr, find_link(name)); 106 | return socket_ptr ? socket_ptr->send_msg(msg) : false; 107 | } 108 | 109 | protected: 110 | //from my_matrix, pure virtual function, we must implement it. 111 | virtual bool del_link(const std::string& name) 112 | { 113 | boost::lock_guard lock(link_map_mutex); 114 | return link_map.erase(name) > 0; 115 | } 116 | 117 | private: 118 | std::map link_map; 119 | boost::mutex link_map_mutex; 120 | }; 121 | 122 | #endif //#define _CLIENT_H_ 123 | -------------------------------------------------------------------------------- /socket_management/makefile: -------------------------------------------------------------------------------- 1 | 2 | module = socket_management 3 | 4 | include ../config.mk 5 | 6 | -------------------------------------------------------------------------------- /socket_management/server.h: -------------------------------------------------------------------------------- 1 | #ifndef _SERVER_H_ 2 | #define _SERVER_H_ 3 | 4 | class my_server_socket : public ext::tcp::server_socket 5 | { 6 | public: 7 | my_server_socket(i_server& server_) : ext::tcp::server_socket(server_) 8 | { 9 | #if 3 == PACKER_UNPACKER_TYPE 10 | boost::dynamic_pointer_cast(packer())->prefix_suffix("", "\n"); 11 | boost::dynamic_pointer_cast(unpacker())->prefix_suffix("", "\n"); 12 | #endif 13 | } 14 | 15 | protected: 16 | //msg handling 17 | #if 1 == PACKER_UNPACKER_TYPE 18 | //unpacker2 uses unique_buffer or shared_buffer as its message type 19 | virtual bool on_msg_handle(out_msg_type& msg) 20 | { 21 | BOOST_AUTO(raw_msg, new string_buffer()); 22 | raw_msg->assign(" (from the server)"); 23 | 24 | ST_ASIO_DEFAULT_PACKER::msg_type msg2(raw_msg); 25 | return send_msg(msg, msg2); //new feature introduced in 2.2.0 26 | } 27 | #elif 2 == PACKER_UNPACKER_TYPE 28 | virtual bool on_msg_handle(out_msg_type& msg) {return send_msg(msg);} 29 | #else 30 | virtual bool on_msg_handle(out_msg_type& msg) {std::string msg2(" (from the server)"); return send_msg(msg, msg2);} //new feature introduced in 2.2.0 31 | #endif 32 | //msg handling end 33 | }; 34 | typedef server_base my_server; 35 | 36 | #endif //#define _SERVER_H_ 37 | -------------------------------------------------------------------------------- /socket_management/socket_management.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | //configuration 6 | #define ST_ASIO_REUSE_OBJECT //use objects pool 7 | #define ST_ASIO_HEARTBEAT_INTERVAL 5 8 | #define ST_ASIO_AVOID_AUTO_STOP_SERVICE 9 | #define ST_ASIO_RECONNECT false 10 | #define ST_ASIO_SHARED_MUTEX_TYPE boost::shared_mutex //we search objects frequently, defining this can promote performance, otherwise, 11 | #define ST_ASIO_SHARED_LOCK_TYPE boost::shared_lock //you should not define these two macro and st_asio_wrapper will use boost::mutex instead. 12 | 13 | //use the following macro to control the type of packer and unpacker 14 | #define PACKER_UNPACKER_TYPE 0 15 | //0-default packer and unpacker, head(length) + body 16 | //1-packer2 and unpacker2, head(length) + body 17 | //2-fixed length packer and unpacker 18 | //3-prefix and/or suffix packer and unpacker 19 | 20 | #if 1 == PACKER_UNPACKER_TYPE 21 | #define ST_ASIO_DEFAULT_PACKER packer2, std::string> 22 | #define ST_ASIO_DEFAULT_UNPACKER unpacker2 > 23 | #elif 2 == PACKER_UNPACKER_TYPE 24 | #undef ST_ASIO_HEARTBEAT_INTERVAL 25 | #define ST_ASIO_HEARTBEAT_INTERVAL 0 //not support heartbeat 26 | #define ST_ASIO_DEFAULT_PACKER fixed_length_packer 27 | #define ST_ASIO_DEFAULT_UNPACKER fixed_length_unpacker 28 | #elif 3 == PACKER_UNPACKER_TYPE 29 | #define ST_ASIO_DEFAULT_PACKER prefix_suffix_packer 30 | #define ST_ASIO_DEFAULT_UNPACKER prefix_suffix_unpacker 31 | #endif 32 | //configuration 33 | 34 | #include "../include/ext/tcp.h" 35 | using namespace st_asio_wrapper; 36 | using namespace st_asio_wrapper::tcp; 37 | using namespace st_asio_wrapper::ext; 38 | //using namespace st_asio_wrapper::ext::tcp; 39 | 40 | #include "server.h" 41 | #include "client.h" 42 | 43 | int main(int argc, const char* argv[]) 44 | { 45 | service_pump sp; 46 | my_server server(sp); 47 | my_client client(sp); 48 | 49 | sp.start_service(); 50 | while(sp.is_running()) 51 | { 52 | std::string str; 53 | std::getline(std::cin, str); 54 | if (str.empty()) 55 | ; 56 | else if ("quit" == str) 57 | sp.stop_service(); 58 | else 59 | { 60 | boost::char_separator sep(" \t"); 61 | boost::tokenizer > tok(str, sep); 62 | BOOST_AUTO(iter, tok.begin()); 63 | if (iter == tok.end()) 64 | continue; 65 | 66 | if ("add" == *iter) 67 | for (++iter; iter != tok.end(); ++iter) 68 | client.add_link(*iter); 69 | else if ("del" == *iter) 70 | for (++iter; iter != tok.end(); ++iter) 71 | client.shutdown_link(*iter); 72 | else 73 | { 74 | std::string name = *iter++; 75 | for (; iter != tok.end(); ++iter) 76 | #if 2 == PACKER_UNPACKER_TYPE 77 | { 78 | std::string msg(1024, '$'); //the default fixed length is 1024 79 | client.send_msg(name, msg); 80 | } 81 | #else 82 | client.send_msg(name, *iter); 83 | #endif 84 | } 85 | } 86 | } 87 | 88 | return 0; 89 | } 90 | -------------------------------------------------------------------------------- /socket_management/socket_management.vcproj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngwolf-project/st_asio_wrapper/3e060755ca6a8fc2ebfed8ccc41c561ad783a211/socket_management/socket_management.vcproj -------------------------------------------------------------------------------- /ssl_test/certs/dh2048.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN DH PARAMETERS----- 2 | MIIBCAKCAQEA1Qny9h8N5IJrbjUFfCpyWgoICvKf6vRfhN/ujvfi82APMksbieuM 3 | JYjfxNgoUQ3DsqutvjLtHOkGlLcKKjLUT/5ZCuQo6w1kvO0NTiLoTyNTrhBUC20R 4 | 5ej7URUJoXpLc7mMpOKHBBztmxUZZrgWfappFsOHsVgN9Dnv9yjaEXALFgyJm1Bq 5 | DX8jvYu24lpUlGkRqh+rb7qzZrS1Lh7gp6D313iu/BDndOYJ4LhP2jYUHlFAPn+U 6 | JL9SvVdIe/4hgPNWv/mJOeOhQgeTu6KAFMkmJ7SzbeXUySM/VMZ/SFI8z7yzdh1T 7 | m4O/jyyRbZeBEifS86e1cLLYaFpTb6ogOwIBAg== 8 | -----END DH PARAMETERS----- 9 | -------------------------------------------------------------------------------- /ssl_test/certs/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDhTCCAm0CFDynRVPoIvuaGTtgg30CvYBDO3dHMA0GCSqGSIb3DQEBCwUAMH8x 3 | CzAJBgNVBAYTAkNOMRAwDgYDVQQIDAdTaUNodWFuMRAwDgYDVQQHDAdDaGVuZ0R1 4 | MQ0wCwYDVQQKDARhc2NzMQ0wCwYDVQQLDARhc2NzMQ0wCwYDVQQDDAR3b2xmMR8w 5 | HQYJKoZIhvcNAQkBFhBtYWlsMnRhb0AxNjMuY29tMB4XDTIxMDIwMjEyMjkwM1oX 6 | DTMxMDEzMTEyMjkwM1owfzELMAkGA1UEBhMCQ04xEDAOBgNVBAgMB1NpQ2h1YW4x 7 | EDAOBgNVBAcMB0NoZW5nRHUxDTALBgNVBAoMBGFzY3MxDTALBgNVBAsMBGFzY3Mx 8 | DTALBgNVBAMMBHdvbGYxHzAdBgkqhkiG9w0BCQEWEG1haWwydGFvQDE2My5jb20w 9 | ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDK0Ib/08IF9eeRRgTzBnWk 10 | sFn8GcYKsBCxNNL4UBg6oAIpcdPF7F8Iq1yoV1dSy7zX1BX/qj2+lcu8gHajXjI0 11 | lwgDS24t88MJJ74Dkb3I7sjnz43/Y3Y4CaS9byuAWEKL+VPakTA9F/+R7e33VYg0 12 | /TncFMD7zC/UU1isnPoJu0lV9+yeDuheGFYulk1/H69Gv5YE9IgElP1GULGvVdvV 13 | qmgXVaiMSXohk5sgcw6/9HwqJIjdzBWDDKT1vCcDfiuNWZ3HsOZsCNW/VE+oai4c 14 | gXkoagKyDJSvsYN67CQEa4mSbno7Fru/BdVHnNnT6zfWizG90mIukkUqXHW0rNe5 15 | AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAMeLgs6570ApV5lEL85rQIxpNGr43gZ8 16 | QWeIsgKRH+uinnxG/sRTIjOIBc3bwq3sdZYX+IxJYKd1wd29xD2fOHabTwdX2vuD 17 | ZBHUQhpVLxmLTT5EQN8gzobm51pC97C+Ph5RcaUoHkJ5zlHEpwTEchrnfuuRMq7l 18 | Noz9UCPr9XwAm70JHZtipqinx38oNsJ0rukzF85loQ/FVZNuWf+ndL1kspMwdzbb 19 | TOoC7SFigiNFZWV1V+0Y47eo0la63zfVrOeHelVkMrWbnDGR78igEpAu2LDOm+YG 20 | 7fY4jhjmym/7yFRG5u7jVeQwCRTCjJAgUv9QlBo6ABSpz9VlVsIbJG0= 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /ssl_test/certs/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpgIBAAKCAQEAytCG/9PCBfXnkUYE8wZ1pLBZ/BnGCrAQsTTS+FAYOqACKXHT 3 | xexfCKtcqFdXUsu819QV/6o9vpXLvIB2o14yNJcIA0tuLfPDCSe+A5G9yO7I58+N 4 | /2N2OAmkvW8rgFhCi/lT2pEwPRf/ke3t91WINP053BTA+8wv1FNYrJz6CbtJVffs 5 | ng7oXhhWLpZNfx+vRr+WBPSIBJT9RlCxr1Xb1apoF1WojEl6IZObIHMOv/R8KiSI 6 | 3cwVgwyk9bwnA34rjVmdx7DmbAjVv1RPqGouHIF5KGoCsgyUr7GDeuwkBGuJkm56 7 | Oxa7vwXVR5zZ0+s31osxvdJiLpJFKlx1tKzXuQIDAQABAoIBAQDEonCA0JoolUWy 8 | f6SEyxp8Vc6osYRlEFbeuExjG6SiEkiGTin4lzd8fEgVnri3OXkZ+DJr8m5yvWEO 9 | na5orgcXHedS6mskelX6JmH/q+nJSlnXBlCx74jKw+7JC2Otx+SdOVqnamTOltne 10 | bkRtrKumVG0oh6ajelBVF4m9sWRq0UOFbkRwNH4URMz3WNXtOr1d+ei3AozXZdBi 11 | wXkSb3GUorH0/LrJMM0Vx8f7xQPT9Xew2ja0J+YCjqNzwjlCo65T4r51jVBqxA9n 12 | Z3HlpgP93QWeRzxuFi0Gtx/LhGnA9+k/7Q3YG90V4ROWpty2DjVJMgWa6P2Qo4hY 13 | 9hjqzqFBAoGBAPLtyXwCZ5c6GGzTkLXUZBBE7YpEozz4GSwz3nZXupYu8S9sjusj 14 | uqnUHMFDcnIGfgvNe7fMyQK+secQ5jwzIYmW1W0d17YG9+y7CAjpqIVcKH+7+1SN 15 | 7K0JBPq3eqWuGhxnQ3xpdfqh8z9HdvF99OXX1ef0P8BjQ6arvEbwWcK1AoGBANW6 16 | MAs+3vjKYk9R4H0ZhsyQTbEcskuCHliB2PRu085tD1mb8F40WB+dRDEdwHTqGFLo 17 | ssctiuvJ/g0ws8OBAPIf9kO+UQCYS96LLQ4DVGdB0W0W93XkOyDLUh1CnM7IJ1Ks 18 | wx4onUS9nBzPhEjRTQ7wewzqBQUwp7g2qJ6r7U91AoGBAJL1InQwiDZF4MzE18AH 19 | sljdOc3xY8bYV3IUFroErE16LFGCHJtGy/884ABSKwOrxciiD/vKmLdeYQTlhkJY 20 | tCsl4grWiM4HPSgqpNuvblDuxVkwgQRPryOmVyrMoBdmUUlpdrvmmIZ8PkjDlMLW 21 | bbY1caOWcJKT+jLzpTxM3iAZAoGBAJupg5xtKhChtoB27b2vfdI3t54rfGAqYNet 22 | mspMfc929xsYzDSQgy5jaGstdCKy7QxVlwAiV2/sKjCJLCRULNAsHzyvvGdmhLuN 23 | Oj9ehXa/JT0C4TDoDXiRHTlabsLcXGeGlIW+puyN/MmvCnXOmwUqeTSqrQVeroko 24 | ph8KsUiRAoGBAJ+d72YSfYFrPUpzMT7BzpeBMO8w+rZePsHO4rv8qX6tDjiJVvNu 25 | vFMkvd1JShSHHsUeS1JWJ/ThKO0DUiJyzB1qblvn741W+lXIuUr4mcwbzJpPWP76 26 | hWFV4fE15+MXZc2+yqk0RDoc1zxg+lRc9eLab6llQy77wtSRiAx46C17 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /ssl_test/client_certs/dh2048.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN DH PARAMETERS----- 2 | MIIBCAKCAQEA1Qny9h8N5IJrbjUFfCpyWgoICvKf6vRfhN/ujvfi82APMksbieuM 3 | JYjfxNgoUQ3DsqutvjLtHOkGlLcKKjLUT/5ZCuQo6w1kvO0NTiLoTyNTrhBUC20R 4 | 5ej7URUJoXpLc7mMpOKHBBztmxUZZrgWfappFsOHsVgN9Dnv9yjaEXALFgyJm1Bq 5 | DX8jvYu24lpUlGkRqh+rb7qzZrS1Lh7gp6D313iu/BDndOYJ4LhP2jYUHlFAPn+U 6 | JL9SvVdIe/4hgPNWv/mJOeOhQgeTu6KAFMkmJ7SzbeXUySM/VMZ/SFI8z7yzdh1T 7 | m4O/jyyRbZeBEifS86e1cLLYaFpTb6ogOwIBAg== 8 | -----END DH PARAMETERS----- 9 | -------------------------------------------------------------------------------- /ssl_test/client_certs/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDhTCCAm0CFDynRVPoIvuaGTtgg30CvYBDO3dHMA0GCSqGSIb3DQEBCwUAMH8x 3 | CzAJBgNVBAYTAkNOMRAwDgYDVQQIDAdTaUNodWFuMRAwDgYDVQQHDAdDaGVuZ0R1 4 | MQ0wCwYDVQQKDARhc2NzMQ0wCwYDVQQLDARhc2NzMQ0wCwYDVQQDDAR3b2xmMR8w 5 | HQYJKoZIhvcNAQkBFhBtYWlsMnRhb0AxNjMuY29tMB4XDTIxMDIwMjEyMjkwM1oX 6 | DTMxMDEzMTEyMjkwM1owfzELMAkGA1UEBhMCQ04xEDAOBgNVBAgMB1NpQ2h1YW4x 7 | EDAOBgNVBAcMB0NoZW5nRHUxDTALBgNVBAoMBGFzY3MxDTALBgNVBAsMBGFzY3Mx 8 | DTALBgNVBAMMBHdvbGYxHzAdBgkqhkiG9w0BCQEWEG1haWwydGFvQDE2My5jb20w 9 | ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDK0Ib/08IF9eeRRgTzBnWk 10 | sFn8GcYKsBCxNNL4UBg6oAIpcdPF7F8Iq1yoV1dSy7zX1BX/qj2+lcu8gHajXjI0 11 | lwgDS24t88MJJ74Dkb3I7sjnz43/Y3Y4CaS9byuAWEKL+VPakTA9F/+R7e33VYg0 12 | /TncFMD7zC/UU1isnPoJu0lV9+yeDuheGFYulk1/H69Gv5YE9IgElP1GULGvVdvV 13 | qmgXVaiMSXohk5sgcw6/9HwqJIjdzBWDDKT1vCcDfiuNWZ3HsOZsCNW/VE+oai4c 14 | gXkoagKyDJSvsYN67CQEa4mSbno7Fru/BdVHnNnT6zfWizG90mIukkUqXHW0rNe5 15 | AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAMeLgs6570ApV5lEL85rQIxpNGr43gZ8 16 | QWeIsgKRH+uinnxG/sRTIjOIBc3bwq3sdZYX+IxJYKd1wd29xD2fOHabTwdX2vuD 17 | ZBHUQhpVLxmLTT5EQN8gzobm51pC97C+Ph5RcaUoHkJ5zlHEpwTEchrnfuuRMq7l 18 | Noz9UCPr9XwAm70JHZtipqinx38oNsJ0rukzF85loQ/FVZNuWf+ndL1kspMwdzbb 19 | TOoC7SFigiNFZWV1V+0Y47eo0la63zfVrOeHelVkMrWbnDGR78igEpAu2LDOm+YG 20 | 7fY4jhjmym/7yFRG5u7jVeQwCRTCjJAgUv9QlBo6ABSpz9VlVsIbJG0= 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /ssl_test/client_certs/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpgIBAAKCAQEAytCG/9PCBfXnkUYE8wZ1pLBZ/BnGCrAQsTTS+FAYOqACKXHT 3 | xexfCKtcqFdXUsu819QV/6o9vpXLvIB2o14yNJcIA0tuLfPDCSe+A5G9yO7I58+N 4 | /2N2OAmkvW8rgFhCi/lT2pEwPRf/ke3t91WINP053BTA+8wv1FNYrJz6CbtJVffs 5 | ng7oXhhWLpZNfx+vRr+WBPSIBJT9RlCxr1Xb1apoF1WojEl6IZObIHMOv/R8KiSI 6 | 3cwVgwyk9bwnA34rjVmdx7DmbAjVv1RPqGouHIF5KGoCsgyUr7GDeuwkBGuJkm56 7 | Oxa7vwXVR5zZ0+s31osxvdJiLpJFKlx1tKzXuQIDAQABAoIBAQDEonCA0JoolUWy 8 | f6SEyxp8Vc6osYRlEFbeuExjG6SiEkiGTin4lzd8fEgVnri3OXkZ+DJr8m5yvWEO 9 | na5orgcXHedS6mskelX6JmH/q+nJSlnXBlCx74jKw+7JC2Otx+SdOVqnamTOltne 10 | bkRtrKumVG0oh6ajelBVF4m9sWRq0UOFbkRwNH4URMz3WNXtOr1d+ei3AozXZdBi 11 | wXkSb3GUorH0/LrJMM0Vx8f7xQPT9Xew2ja0J+YCjqNzwjlCo65T4r51jVBqxA9n 12 | Z3HlpgP93QWeRzxuFi0Gtx/LhGnA9+k/7Q3YG90V4ROWpty2DjVJMgWa6P2Qo4hY 13 | 9hjqzqFBAoGBAPLtyXwCZ5c6GGzTkLXUZBBE7YpEozz4GSwz3nZXupYu8S9sjusj 14 | uqnUHMFDcnIGfgvNe7fMyQK+secQ5jwzIYmW1W0d17YG9+y7CAjpqIVcKH+7+1SN 15 | 7K0JBPq3eqWuGhxnQ3xpdfqh8z9HdvF99OXX1ef0P8BjQ6arvEbwWcK1AoGBANW6 16 | MAs+3vjKYk9R4H0ZhsyQTbEcskuCHliB2PRu085tD1mb8F40WB+dRDEdwHTqGFLo 17 | ssctiuvJ/g0ws8OBAPIf9kO+UQCYS96LLQ4DVGdB0W0W93XkOyDLUh1CnM7IJ1Ks 18 | wx4onUS9nBzPhEjRTQ7wewzqBQUwp7g2qJ6r7U91AoGBAJL1InQwiDZF4MzE18AH 19 | sljdOc3xY8bYV3IUFroErE16LFGCHJtGy/884ABSKwOrxciiD/vKmLdeYQTlhkJY 20 | tCsl4grWiM4HPSgqpNuvblDuxVkwgQRPryOmVyrMoBdmUUlpdrvmmIZ8PkjDlMLW 21 | bbY1caOWcJKT+jLzpTxM3iAZAoGBAJupg5xtKhChtoB27b2vfdI3t54rfGAqYNet 22 | mspMfc929xsYzDSQgy5jaGstdCKy7QxVlwAiV2/sKjCJLCRULNAsHzyvvGdmhLuN 23 | Oj9ehXa/JT0C4TDoDXiRHTlabsLcXGeGlIW+puyN/MmvCnXOmwUqeTSqrQVeroko 24 | ph8KsUiRAoGBAJ+d72YSfYFrPUpzMT7BzpeBMO8w+rZePsHO4rv8qX6tDjiJVvNu 25 | vFMkvd1JShSHHsUeS1JWJ/ThKO0DUiJyzB1qblvn741W+lXIuUr4mcwbzJpPWP76 26 | hWFV4fE15+MXZc2+yqk0RDoc1zxg+lRc9eLab6llQy77wtSRiAx46C17 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /ssl_test/makefile: -------------------------------------------------------------------------------- 1 | 2 | module = ssl_test 3 | ext_libs = -lcrypto -lssl 4 | 5 | include ../config.mk 6 | 7 | -------------------------------------------------------------------------------- /ssl_test/ssl_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | //configuration 5 | #define ST_ASIO_SERVER_PORT 9527 6 | #define ST_ASIO_REUSE_OBJECT //use objects pool 7 | //#define ST_ASIO_DEFAULT_PACKER packer2, std::string> 8 | //#define ST_ASIO_DEFAULT_UNPACKER unpacker2<> 9 | #define ST_ASIO_HEARTBEAT_INTERVAL 5 //SSL has supported heartbeat because we used user data instead of OOB to implement 10 | //heartbeat since 1.4.0 11 | //configuration 12 | 13 | #include "../include/ext/ssl.h" 14 | using namespace st_asio_wrapper; 15 | using namespace st_asio_wrapper::ext::ssl; 16 | 17 | #define QUIT_COMMAND "quit" 18 | #define RESTART_COMMAND "restart" 19 | #define RECONNECT "reconnect" 20 | #define SHOW_ALL_LINKS "show_all_links" 21 | #define SHUTDOWN_LINK "shutdown" 22 | 23 | int main(int argc, const char* argv[]) 24 | { 25 | puts("Directories 'certs' and 'client_certs' must available in current directory."); 26 | if (argc >= 2 && (0 == strcmp(argv[1], "--help") || 0 == strcmp(argv[1], "-h"))) 27 | return 0; 28 | else 29 | puts("type " QUIT_COMMAND " to end."); 30 | 31 | service_pump sp; 32 | 33 | server server_(sp, boost::asio::ssl::context::sslv23_server); 34 | server_.set_start_object_id(1000); 35 | 36 | server_.context().set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use); 37 | server_.context().set_verify_mode(boost::asio::ssl::context::verify_peer | boost::asio::ssl::context::verify_fail_if_no_peer_cert); 38 | server_.context().load_verify_file("client_certs/server.crt"); 39 | server_.context().use_certificate_chain_file("certs/server.crt"); 40 | server_.context().use_private_key_file("certs/server.key", boost::asio::ssl::context::pem); 41 | server_.context().use_tmp_dh_file("certs/dh2048.pem"); 42 | 43 | ///* 44 | //method #1 45 | multi_client client_(sp, boost::asio::ssl::context::sslv23_client); 46 | client_.context().set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use); 47 | client_.context().set_verify_mode(boost::asio::ssl::context::verify_peer | boost::asio::ssl::context::verify_fail_if_no_peer_cert); 48 | client_.context().load_verify_file("certs/server.crt"); 49 | client_.context().use_certificate_chain_file("client_certs/server.crt"); 50 | client_.context().use_private_key_file("client_certs/server.key", boost::asio::ssl::context::pem); 51 | client_.context().use_tmp_dh_file("client_certs/dh2048.pem"); 52 | 53 | //please config the ssl context before creating any clients. 54 | client_.add_socket(); 55 | client_.add_socket(); 56 | //*/ 57 | /* 58 | //method #2 59 | //to use single_client, we must construct ssl context first. 60 | boost::shared_ptr ctx = boost::make_shared(boost::asio::ssl::context::sslv23_client); 61 | ctx->set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use); 62 | ctx->set_verify_mode(boost::asio::ssl::context::verify_peer | boost::asio::ssl::context::verify_fail_if_no_peer_cert); 63 | ctx->load_verify_file("certs/server.crt"); 64 | ctx->use_certificate_chain_file("client_certs/server.crt"); 65 | ctx->use_private_key_file("client_certs/server.key", boost::asio::ssl::context::pem); 66 | ctx->use_tmp_dh_file("client_certs/dh2048.pem"); 67 | 68 | single_client client_(sp, ctx); 69 | */ 70 | sp.start_service(); 71 | while(sp.is_running()) 72 | { 73 | std::string str; 74 | std::cin >> str; 75 | if (str.empty()) 76 | ; 77 | else if (QUIT_COMMAND == str) 78 | { 79 | sp.stop_service(&client_); 80 | sp.stop_service(); 81 | } 82 | else if (SHOW_ALL_LINKS == str) 83 | { 84 | puts("server:"); 85 | printf("link #: " ST_ASIO_SF ", invalid links: " ST_ASIO_SF "\n", server_.size(), server_.invalid_object_size()); 86 | server_.list_all_object(); 87 | 88 | //if you used single_client, comment out following codes. 89 | puts("\nclient:"); 90 | printf("link #: " ST_ASIO_SF ", valid links: " ST_ASIO_SF ", invalid links: " ST_ASIO_SF "\n", client_.size(), client_.valid_size(), client_.invalid_object_size()); 91 | client_.list_all_object(); 92 | } 93 | else if (RESTART_COMMAND == str) 94 | { 95 | sp.stop_service(&client_); 96 | sp.stop_service(); 97 | 98 | //add all clients back 99 | client_.add_socket(); 100 | client_.add_socket(); 101 | sp.start_service(); 102 | } 103 | else if (RECONNECT == str) 104 | // server_.graceful_shutdown(); 105 | client_.graceful_shutdown(true); 106 | else if (SHUTDOWN_LINK == str) 107 | //async shutdown, client will reconnect to the server 108 | // server_.at(0)->graceful_shutdown(); 109 | // server_.at(0)->force_shutdown(); 110 | 111 | //sync shutdown, client will reconnect to the server 112 | // server_.at(0)->graceful_shutdown(true); 113 | 114 | //sync shutdown and reconnect to the server 115 | client_.at(0)->graceful_shutdown(true); 116 | // client_.at(0)->force_shutdown(true); 117 | // client_.graceful_shutdown(true); //if you used single_client 118 | // client_.force_shutdown(true); //if you used single_client 119 | 120 | //async shutdown and reconnect to the server 121 | // client_.at(0)->graceful_shutdown(true, false); 122 | // client_.graceful_shutdown(true, false); //if you used single_client 123 | 124 | //sync shutdown and not reconnect to the server 125 | // client_.at(0)->graceful_shutdown(); 126 | // client_.at(0)->force_shutdown(); 127 | // client_.graceful_shutdown(client_.at(0)); 128 | // client_.force_shutdown(client_.at(0)); 129 | // client_.graceful_shutdown(); //if you used single_client 130 | // client_.force_shutdown(); //if you used single_client 131 | 132 | //async shutdown and not reconnect to the server 133 | // client_.at(0)->graceful_shutdown(false, false); 134 | // client_.graceful_shutdown(client_.at(0), false); 135 | // client_.graceful_shutdown(false, false); //if you used single_client 136 | else 137 | server_.broadcast_msg(str); 138 | } 139 | 140 | return 0; 141 | } 142 | -------------------------------------------------------------------------------- /ssl_test/ssl_test.vcproj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngwolf-project/st_asio_wrapper/3e060755ca6a8fc2ebfed8ccc41c561ad783a211/ssl_test/ssl_test.vcproj -------------------------------------------------------------------------------- /ssl_websocket_test/certs/dh2048.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN DH PARAMETERS----- 2 | MIIBCAKCAQEA1Qny9h8N5IJrbjUFfCpyWgoICvKf6vRfhN/ujvfi82APMksbieuM 3 | JYjfxNgoUQ3DsqutvjLtHOkGlLcKKjLUT/5ZCuQo6w1kvO0NTiLoTyNTrhBUC20R 4 | 5ej7URUJoXpLc7mMpOKHBBztmxUZZrgWfappFsOHsVgN9Dnv9yjaEXALFgyJm1Bq 5 | DX8jvYu24lpUlGkRqh+rb7qzZrS1Lh7gp6D313iu/BDndOYJ4LhP2jYUHlFAPn+U 6 | JL9SvVdIe/4hgPNWv/mJOeOhQgeTu6KAFMkmJ7SzbeXUySM/VMZ/SFI8z7yzdh1T 7 | m4O/jyyRbZeBEifS86e1cLLYaFpTb6ogOwIBAg== 8 | -----END DH PARAMETERS----- 9 | -------------------------------------------------------------------------------- /ssl_websocket_test/certs/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDhTCCAm0CFDynRVPoIvuaGTtgg30CvYBDO3dHMA0GCSqGSIb3DQEBCwUAMH8x 3 | CzAJBgNVBAYTAkNOMRAwDgYDVQQIDAdTaUNodWFuMRAwDgYDVQQHDAdDaGVuZ0R1 4 | MQ0wCwYDVQQKDARhc2NzMQ0wCwYDVQQLDARhc2NzMQ0wCwYDVQQDDAR3b2xmMR8w 5 | HQYJKoZIhvcNAQkBFhBtYWlsMnRhb0AxNjMuY29tMB4XDTIxMDIwMjEyMjkwM1oX 6 | DTMxMDEzMTEyMjkwM1owfzELMAkGA1UEBhMCQ04xEDAOBgNVBAgMB1NpQ2h1YW4x 7 | EDAOBgNVBAcMB0NoZW5nRHUxDTALBgNVBAoMBGFzY3MxDTALBgNVBAsMBGFzY3Mx 8 | DTALBgNVBAMMBHdvbGYxHzAdBgkqhkiG9w0BCQEWEG1haWwydGFvQDE2My5jb20w 9 | ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDK0Ib/08IF9eeRRgTzBnWk 10 | sFn8GcYKsBCxNNL4UBg6oAIpcdPF7F8Iq1yoV1dSy7zX1BX/qj2+lcu8gHajXjI0 11 | lwgDS24t88MJJ74Dkb3I7sjnz43/Y3Y4CaS9byuAWEKL+VPakTA9F/+R7e33VYg0 12 | /TncFMD7zC/UU1isnPoJu0lV9+yeDuheGFYulk1/H69Gv5YE9IgElP1GULGvVdvV 13 | qmgXVaiMSXohk5sgcw6/9HwqJIjdzBWDDKT1vCcDfiuNWZ3HsOZsCNW/VE+oai4c 14 | gXkoagKyDJSvsYN67CQEa4mSbno7Fru/BdVHnNnT6zfWizG90mIukkUqXHW0rNe5 15 | AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAMeLgs6570ApV5lEL85rQIxpNGr43gZ8 16 | QWeIsgKRH+uinnxG/sRTIjOIBc3bwq3sdZYX+IxJYKd1wd29xD2fOHabTwdX2vuD 17 | ZBHUQhpVLxmLTT5EQN8gzobm51pC97C+Ph5RcaUoHkJ5zlHEpwTEchrnfuuRMq7l 18 | Noz9UCPr9XwAm70JHZtipqinx38oNsJ0rukzF85loQ/FVZNuWf+ndL1kspMwdzbb 19 | TOoC7SFigiNFZWV1V+0Y47eo0la63zfVrOeHelVkMrWbnDGR78igEpAu2LDOm+YG 20 | 7fY4jhjmym/7yFRG5u7jVeQwCRTCjJAgUv9QlBo6ABSpz9VlVsIbJG0= 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /ssl_websocket_test/certs/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpgIBAAKCAQEAytCG/9PCBfXnkUYE8wZ1pLBZ/BnGCrAQsTTS+FAYOqACKXHT 3 | xexfCKtcqFdXUsu819QV/6o9vpXLvIB2o14yNJcIA0tuLfPDCSe+A5G9yO7I58+N 4 | /2N2OAmkvW8rgFhCi/lT2pEwPRf/ke3t91WINP053BTA+8wv1FNYrJz6CbtJVffs 5 | ng7oXhhWLpZNfx+vRr+WBPSIBJT9RlCxr1Xb1apoF1WojEl6IZObIHMOv/R8KiSI 6 | 3cwVgwyk9bwnA34rjVmdx7DmbAjVv1RPqGouHIF5KGoCsgyUr7GDeuwkBGuJkm56 7 | Oxa7vwXVR5zZ0+s31osxvdJiLpJFKlx1tKzXuQIDAQABAoIBAQDEonCA0JoolUWy 8 | f6SEyxp8Vc6osYRlEFbeuExjG6SiEkiGTin4lzd8fEgVnri3OXkZ+DJr8m5yvWEO 9 | na5orgcXHedS6mskelX6JmH/q+nJSlnXBlCx74jKw+7JC2Otx+SdOVqnamTOltne 10 | bkRtrKumVG0oh6ajelBVF4m9sWRq0UOFbkRwNH4URMz3WNXtOr1d+ei3AozXZdBi 11 | wXkSb3GUorH0/LrJMM0Vx8f7xQPT9Xew2ja0J+YCjqNzwjlCo65T4r51jVBqxA9n 12 | Z3HlpgP93QWeRzxuFi0Gtx/LhGnA9+k/7Q3YG90V4ROWpty2DjVJMgWa6P2Qo4hY 13 | 9hjqzqFBAoGBAPLtyXwCZ5c6GGzTkLXUZBBE7YpEozz4GSwz3nZXupYu8S9sjusj 14 | uqnUHMFDcnIGfgvNe7fMyQK+secQ5jwzIYmW1W0d17YG9+y7CAjpqIVcKH+7+1SN 15 | 7K0JBPq3eqWuGhxnQ3xpdfqh8z9HdvF99OXX1ef0P8BjQ6arvEbwWcK1AoGBANW6 16 | MAs+3vjKYk9R4H0ZhsyQTbEcskuCHliB2PRu085tD1mb8F40WB+dRDEdwHTqGFLo 17 | ssctiuvJ/g0ws8OBAPIf9kO+UQCYS96LLQ4DVGdB0W0W93XkOyDLUh1CnM7IJ1Ks 18 | wx4onUS9nBzPhEjRTQ7wewzqBQUwp7g2qJ6r7U91AoGBAJL1InQwiDZF4MzE18AH 19 | sljdOc3xY8bYV3IUFroErE16LFGCHJtGy/884ABSKwOrxciiD/vKmLdeYQTlhkJY 20 | tCsl4grWiM4HPSgqpNuvblDuxVkwgQRPryOmVyrMoBdmUUlpdrvmmIZ8PkjDlMLW 21 | bbY1caOWcJKT+jLzpTxM3iAZAoGBAJupg5xtKhChtoB27b2vfdI3t54rfGAqYNet 22 | mspMfc929xsYzDSQgy5jaGstdCKy7QxVlwAiV2/sKjCJLCRULNAsHzyvvGdmhLuN 23 | Oj9ehXa/JT0C4TDoDXiRHTlabsLcXGeGlIW+puyN/MmvCnXOmwUqeTSqrQVeroko 24 | ph8KsUiRAoGBAJ+d72YSfYFrPUpzMT7BzpeBMO8w+rZePsHO4rv8qX6tDjiJVvNu 25 | vFMkvd1JShSHHsUeS1JWJ/ThKO0DUiJyzB1qblvn741W+lXIuUr4mcwbzJpPWP76 26 | hWFV4fE15+MXZc2+yqk0RDoc1zxg+lRc9eLab6llQy77wtSRiAx46C17 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /ssl_websocket_test/client_certs/dh2048.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN DH PARAMETERS----- 2 | MIIBCAKCAQEA1Qny9h8N5IJrbjUFfCpyWgoICvKf6vRfhN/ujvfi82APMksbieuM 3 | JYjfxNgoUQ3DsqutvjLtHOkGlLcKKjLUT/5ZCuQo6w1kvO0NTiLoTyNTrhBUC20R 4 | 5ej7URUJoXpLc7mMpOKHBBztmxUZZrgWfappFsOHsVgN9Dnv9yjaEXALFgyJm1Bq 5 | DX8jvYu24lpUlGkRqh+rb7qzZrS1Lh7gp6D313iu/BDndOYJ4LhP2jYUHlFAPn+U 6 | JL9SvVdIe/4hgPNWv/mJOeOhQgeTu6KAFMkmJ7SzbeXUySM/VMZ/SFI8z7yzdh1T 7 | m4O/jyyRbZeBEifS86e1cLLYaFpTb6ogOwIBAg== 8 | -----END DH PARAMETERS----- 9 | -------------------------------------------------------------------------------- /ssl_websocket_test/client_certs/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDhTCCAm0CFDynRVPoIvuaGTtgg30CvYBDO3dHMA0GCSqGSIb3DQEBCwUAMH8x 3 | CzAJBgNVBAYTAkNOMRAwDgYDVQQIDAdTaUNodWFuMRAwDgYDVQQHDAdDaGVuZ0R1 4 | MQ0wCwYDVQQKDARhc2NzMQ0wCwYDVQQLDARhc2NzMQ0wCwYDVQQDDAR3b2xmMR8w 5 | HQYJKoZIhvcNAQkBFhBtYWlsMnRhb0AxNjMuY29tMB4XDTIxMDIwMjEyMjkwM1oX 6 | DTMxMDEzMTEyMjkwM1owfzELMAkGA1UEBhMCQ04xEDAOBgNVBAgMB1NpQ2h1YW4x 7 | EDAOBgNVBAcMB0NoZW5nRHUxDTALBgNVBAoMBGFzY3MxDTALBgNVBAsMBGFzY3Mx 8 | DTALBgNVBAMMBHdvbGYxHzAdBgkqhkiG9w0BCQEWEG1haWwydGFvQDE2My5jb20w 9 | ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDK0Ib/08IF9eeRRgTzBnWk 10 | sFn8GcYKsBCxNNL4UBg6oAIpcdPF7F8Iq1yoV1dSy7zX1BX/qj2+lcu8gHajXjI0 11 | lwgDS24t88MJJ74Dkb3I7sjnz43/Y3Y4CaS9byuAWEKL+VPakTA9F/+R7e33VYg0 12 | /TncFMD7zC/UU1isnPoJu0lV9+yeDuheGFYulk1/H69Gv5YE9IgElP1GULGvVdvV 13 | qmgXVaiMSXohk5sgcw6/9HwqJIjdzBWDDKT1vCcDfiuNWZ3HsOZsCNW/VE+oai4c 14 | gXkoagKyDJSvsYN67CQEa4mSbno7Fru/BdVHnNnT6zfWizG90mIukkUqXHW0rNe5 15 | AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAMeLgs6570ApV5lEL85rQIxpNGr43gZ8 16 | QWeIsgKRH+uinnxG/sRTIjOIBc3bwq3sdZYX+IxJYKd1wd29xD2fOHabTwdX2vuD 17 | ZBHUQhpVLxmLTT5EQN8gzobm51pC97C+Ph5RcaUoHkJ5zlHEpwTEchrnfuuRMq7l 18 | Noz9UCPr9XwAm70JHZtipqinx38oNsJ0rukzF85loQ/FVZNuWf+ndL1kspMwdzbb 19 | TOoC7SFigiNFZWV1V+0Y47eo0la63zfVrOeHelVkMrWbnDGR78igEpAu2LDOm+YG 20 | 7fY4jhjmym/7yFRG5u7jVeQwCRTCjJAgUv9QlBo6ABSpz9VlVsIbJG0= 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /ssl_websocket_test/client_certs/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpgIBAAKCAQEAytCG/9PCBfXnkUYE8wZ1pLBZ/BnGCrAQsTTS+FAYOqACKXHT 3 | xexfCKtcqFdXUsu819QV/6o9vpXLvIB2o14yNJcIA0tuLfPDCSe+A5G9yO7I58+N 4 | /2N2OAmkvW8rgFhCi/lT2pEwPRf/ke3t91WINP053BTA+8wv1FNYrJz6CbtJVffs 5 | ng7oXhhWLpZNfx+vRr+WBPSIBJT9RlCxr1Xb1apoF1WojEl6IZObIHMOv/R8KiSI 6 | 3cwVgwyk9bwnA34rjVmdx7DmbAjVv1RPqGouHIF5KGoCsgyUr7GDeuwkBGuJkm56 7 | Oxa7vwXVR5zZ0+s31osxvdJiLpJFKlx1tKzXuQIDAQABAoIBAQDEonCA0JoolUWy 8 | f6SEyxp8Vc6osYRlEFbeuExjG6SiEkiGTin4lzd8fEgVnri3OXkZ+DJr8m5yvWEO 9 | na5orgcXHedS6mskelX6JmH/q+nJSlnXBlCx74jKw+7JC2Otx+SdOVqnamTOltne 10 | bkRtrKumVG0oh6ajelBVF4m9sWRq0UOFbkRwNH4URMz3WNXtOr1d+ei3AozXZdBi 11 | wXkSb3GUorH0/LrJMM0Vx8f7xQPT9Xew2ja0J+YCjqNzwjlCo65T4r51jVBqxA9n 12 | Z3HlpgP93QWeRzxuFi0Gtx/LhGnA9+k/7Q3YG90V4ROWpty2DjVJMgWa6P2Qo4hY 13 | 9hjqzqFBAoGBAPLtyXwCZ5c6GGzTkLXUZBBE7YpEozz4GSwz3nZXupYu8S9sjusj 14 | uqnUHMFDcnIGfgvNe7fMyQK+secQ5jwzIYmW1W0d17YG9+y7CAjpqIVcKH+7+1SN 15 | 7K0JBPq3eqWuGhxnQ3xpdfqh8z9HdvF99OXX1ef0P8BjQ6arvEbwWcK1AoGBANW6 16 | MAs+3vjKYk9R4H0ZhsyQTbEcskuCHliB2PRu085tD1mb8F40WB+dRDEdwHTqGFLo 17 | ssctiuvJ/g0ws8OBAPIf9kO+UQCYS96LLQ4DVGdB0W0W93XkOyDLUh1CnM7IJ1Ks 18 | wx4onUS9nBzPhEjRTQ7wewzqBQUwp7g2qJ6r7U91AoGBAJL1InQwiDZF4MzE18AH 19 | sljdOc3xY8bYV3IUFroErE16LFGCHJtGy/884ABSKwOrxciiD/vKmLdeYQTlhkJY 20 | tCsl4grWiM4HPSgqpNuvblDuxVkwgQRPryOmVyrMoBdmUUlpdrvmmIZ8PkjDlMLW 21 | bbY1caOWcJKT+jLzpTxM3iAZAoGBAJupg5xtKhChtoB27b2vfdI3t54rfGAqYNet 22 | mspMfc929xsYzDSQgy5jaGstdCKy7QxVlwAiV2/sKjCJLCRULNAsHzyvvGdmhLuN 23 | Oj9ehXa/JT0C4TDoDXiRHTlabsLcXGeGlIW+puyN/MmvCnXOmwUqeTSqrQVeroko 24 | ph8KsUiRAoGBAJ+d72YSfYFrPUpzMT7BzpeBMO8w+rZePsHO4rv8qX6tDjiJVvNu 25 | vFMkvd1JShSHHsUeS1JWJ/ThKO0DUiJyzB1qblvn741W+lXIuUr4mcwbzJpPWP76 26 | hWFV4fE15+MXZc2+yqk0RDoc1zxg+lRc9eLab6llQy77wtSRiAx46C17 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /ssl_websocket_test/makefile: -------------------------------------------------------------------------------- 1 | 2 | module = ssl_websocket_test 3 | STD = c++11 4 | ext_libs = -lcrypto -lssl 5 | 6 | include ../config.mk 7 | 8 | -------------------------------------------------------------------------------- /ssl_websocket_test/ssl_websocket_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | //configuration 5 | //#define ST_ASIO_SYNC_RECV 6 | //#define ST_ASIO_SYNC_SEND 7 | //configuration 8 | 9 | #include "../include/ext/ssl_websocket.h" 10 | using namespace st_asio_wrapper; 11 | using namespace st_asio_wrapper::ext::websocket::ssl; 12 | 13 | #define QUIT_COMMAND "quit" 14 | #define RESTART_COMMAND "restart" 15 | #define RECONNECT "reconnect" 16 | 17 | int main(int argc, const char* argv[]) 18 | { 19 | puts("Demonstrate how to use ssl websocket with st_asio_wrapper."); 20 | if (argc >= 2 && (0 == strcmp(argv[1], "--help") || 0 == strcmp(argv[1], "-h"))) 21 | return 0; 22 | else 23 | puts("type " QUIT_COMMAND " to end."); 24 | 25 | service_pump sp; 26 | 27 | server server_(sp, boost::asio::ssl::context::sslv23_server); 28 | server_.set_start_object_id(1000); 29 | 30 | server_.context().set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use); 31 | server_.context().set_verify_mode(boost::asio::ssl::context::verify_peer | boost::asio::ssl::context::verify_fail_if_no_peer_cert); 32 | server_.context().load_verify_file("client_certs/server.crt"); 33 | server_.context().use_certificate_chain_file("certs/server.crt"); 34 | server_.context().use_private_key_file("certs/server.key", boost::asio::ssl::context::pem); 35 | server_.context().use_tmp_dh_file("certs/dh2048.pem"); 36 | 37 | multi_client client_(sp, boost::asio::ssl::context::sslv23_client); 38 | client_.context().set_options(boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use); 39 | client_.context().set_verify_mode(boost::asio::ssl::context::verify_peer | boost::asio::ssl::context::verify_fail_if_no_peer_cert); 40 | client_.context().load_verify_file("certs/server.crt"); 41 | client_.context().use_certificate_chain_file("client_certs/server.crt"); 42 | client_.context().use_private_key_file("client_certs/server.key", boost::asio::ssl::context::pem); 43 | client_.context().use_tmp_dh_file("client_certs/dh2048.pem"); 44 | 45 | //please config the ssl context before creating any clients. 46 | client_.add_socket(); 47 | client_.add_socket(); 48 | 49 | sp.start_service(2); 50 | while(sp.is_running()) 51 | { 52 | std::string str; 53 | std::cin >> str; 54 | if (QUIT_COMMAND == str) 55 | sp.stop_service(); 56 | else if (RESTART_COMMAND == str) 57 | { 58 | sp.stop_service(); 59 | 60 | //add all clients back 61 | client_.add_socket(); 62 | client_.add_socket(); 63 | sp.start_service(); 64 | } 65 | else if (RECONNECT == str) 66 | //client_.force_shutdown(true); 67 | client_.graceful_shutdown(true); 68 | else 69 | //client_.broadcast_native_msg(str); 70 | server_.broadcast_native_msg(str); 71 | } 72 | 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /ssl_websocket_test/ssl_websocket_test.vcproj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngwolf-project/st_asio_wrapper/3e060755ca6a8fc2ebfed8ccc41c561ad783a211/ssl_websocket_test/ssl_websocket_test.vcproj -------------------------------------------------------------------------------- /udp_test/makefile: -------------------------------------------------------------------------------- 1 | 2 | module = udp_test 3 | ext_cflag = -I../../kcp/ 4 | ext_libs = -L../../kcp/ -lkcp 5 | 6 | include ../config.mk 7 | 8 | -------------------------------------------------------------------------------- /udp_test/udp_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | //configuration 5 | #define ST_ASIO_NOT_REUSE_ADDRESS 6 | #define ST_ASIO_SYNC_RECV 7 | #define ST_ASIO_SYNC_SEND 8 | #define ST_ASIO_PASSIVE_RECV //if you annotate this definition, this demo will use mix model to receive messages, which means 9 | //some messages will be dispatched via on_msg_handle(), some messages will be returned via sync_recv_msg(), 10 | //type more than one messages (separate them by space) in one line with ENTER key to send them, 11 | //you will see them cross together on the receiver's screen. 12 | //with this macro, if heartbeat not applied, macro ST_ASIO_AVOID_AUTO_STOP_SERVICE must be defined to avoid the service_pump run out. 13 | #define ST_ASIO_AVOID_AUTO_STOP_SERVICE 14 | //#define ST_ASIO_UDP_CONNECT_MODE true 15 | //#define ST_ASIO_HEARTBEAT_INTERVAL 5 //neither udp_unpacker nor udp_unpacker2 support heartbeat message, so heartbeat will be treated as normal message. 16 | //#define ST_ASIO_DEFAULT_UDP_UNPACKER udp_unpacker2<> 17 | //configuration 18 | 19 | #include "../include/ext/reliable_udp.h" 20 | using namespace st_asio_wrapper; 21 | 22 | #define QUIT_COMMAND "quit" 23 | #define RESTART_COMMAND "restart" 24 | 25 | void sync_recv_thread(ext::udp::reliable_socket& socket) 26 | { 27 | list msg_can; 28 | sync_call_result re = SUCCESS; 29 | do 30 | { 31 | re = socket.sync_recv_msg(msg_can, 50); //st_asio_wrapper will not maintain messages in msg_can anymore after sync_recv_msg return, please note. 32 | if (SUCCESS == re) 33 | { 34 | for (BOOST_AUTO(iter, msg_can.begin()); iter != msg_can.end(); ++iter) 35 | printf("sync recv(" ST_ASIO_SF ") : %s\n", iter->size(), iter->data()); 36 | msg_can.clear(); //sync_recv_msg just append new message(s) to msg_can, please note. 37 | } 38 | } while (SUCCESS == re || TIMEOUT == re); 39 | puts("sync recv end."); 40 | } 41 | 42 | //because st_asio_wrapper is header only, it cannot provide the implementation of below global function, but kcp needs it, 43 | //you're supposed to provide it and call reliable_socket_base::output directly in it, like: 44 | int output(const char* buf, int len, ikcpcb* kcp, void* user) {return ((ext::udp::single_reliable_socket_service*) user)->output(buf, len);} 45 | 46 | int main(int argc, const char* argv[]) 47 | { 48 | printf("usage: %s [-n normal UDP, otherwise reliable UDP] [peer ip=127.0.0.1]\n", argv[0]); 49 | if (argc >= 2 && (0 == strcmp(argv[1], "--help") || 0 == strcmp(argv[1], "-h"))) 50 | return 0; 51 | 52 | int index = 0; 53 | if (argc >= 2 && 0 == strcmp(argv[1], "-n")) 54 | index = 1; 55 | 56 | if (argc < index + 3) 57 | return 1; 58 | else 59 | puts("type " QUIT_COMMAND " to end."); 60 | 61 | service_pump sp; 62 | ext::udp::single_reliable_socket_service service(sp); 63 | service.set_local_addr((unsigned short) atoi(argv[index + 1])); //for multicast, do not bind to a specific IP, just port is enough 64 | service.set_peer_addr((unsigned short) atoi(argv[index + 2]), argc >= index + 4 ? argv[index + 3] : "127.0.0.1"); 65 | 66 | if (0 == index) 67 | { 68 | service.set_connect_mode(); 69 | 70 | //reliable_socket cannot become reliable without below statement, instead, it downgrade to normal UDP socket 71 | service.create_kcpcb(0, (void*) &service); 72 | //without below statement, your application will core dump 73 | ikcp_setoutput(service.get_kcpcb(), &output); 74 | } 75 | 76 | sp.start_service(); 77 | //for broadcast 78 | // service.lowest_layer().set_option(boost::asio::socket_base::broadcast(true)); //usage: ./udp_test 5000 5000 "255.255.255.255" 79 | //for multicast, join it after start_service(): 80 | // service.lowest_layer().set_option(boost::asio::ip::multicast::join_group(boost::asio::ip::make_address("x.x.x.x"))); // >= asio 1.11 81 | 82 | //if you must join it before start_service(): 83 | // service.lowest_layer().open(ST_ASIO_UDP_DEFAULT_IP_VERSION); 84 | // service.lowest_layer().set_option(boost::asio::ip::multicast::join_group(boost::asio::ip::address::from_string("x.x.x.x"))); // < asio 1.11 85 | // sp.start_service(); 86 | 87 | //demonstrate how to change local address if the binding was failed. 88 | if (!service.service_started()) 89 | { 90 | service.set_local_addr(6666); 91 | sp.start_service(&service); 92 | } 93 | 94 | boost::thread t = boost::thread(boost::bind(&sync_recv_thread, boost::ref(service))); 95 | while(sp.is_running()) 96 | { 97 | std::string str; 98 | std::cin >> str; 99 | if (QUIT_COMMAND == str) 100 | { 101 | sp.stop_service(); 102 | t.join(); 103 | } 104 | else if (RESTART_COMMAND == str) 105 | { 106 | sp.stop_service(); 107 | t.join(); 108 | 109 | sp.start_service(); 110 | t = boost::thread(boost::bind(&sync_recv_thread, boost::ref(service))); 111 | } 112 | else 113 | service.sync_safe_send_native_msg(str); //to send to different endpoints, use overloads that take a const boost::asio::ip::udp::endpoint& parameter 114 | } 115 | 116 | return 0; 117 | } 118 | -------------------------------------------------------------------------------- /udp_test/udp_test.vcproj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngwolf-project/st_asio_wrapper/3e060755ca6a8fc2ebfed8ccc41c561ad783a211/udp_test/udp_test.vcproj -------------------------------------------------------------------------------- /unix_socket/makefile: -------------------------------------------------------------------------------- 1 | 2 | module = unix_socket 3 | 4 | include ../config.mk 5 | 6 | -------------------------------------------------------------------------------- /unix_socket/unix_socket.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | //configuration 5 | #define ST_ASIO_REUSE_OBJECT //use objects pool 6 | //configuration 7 | 8 | #include "../include/ext/tcp.h" 9 | using namespace st_asio_wrapper; 10 | using namespace st_asio_wrapper::tcp; 11 | using namespace st_asio_wrapper::ext; 12 | using namespace st_asio_wrapper::ext::tcp; 13 | 14 | #define QUIT "quit" 15 | #define UNIX_SOCKET_NAME "unix-socket" 16 | 17 | int main(int argc, const char* argv[]) 18 | { 19 | service_pump sp; 20 | 21 | unix_server server(sp); 22 | unix_single_client client(sp); 23 | //unix_multi_client client(sp); 24 | 25 | unlink(UNIX_SOCKET_NAME); 26 | server.set_server_addr(UNIX_SOCKET_NAME); 27 | client.set_server_addr(UNIX_SOCKET_NAME); 28 | //BOOST_AUTO(socket_ptr, client.create_object()); 29 | //socket_ptr->set_server_addr(UNIX_SOCKET_NAME); 30 | //client.add_socket(socket_ptr); 31 | 32 | //demonstrate how to set/get single client's id, and how to set/get i_service's id. 33 | //we need specific conversion for i_service because it has the same function name as single client does. 34 | client.id(10000); 35 | std::cout << client.id() << " : " << ((service_pump::i_service&) client).id() << std::endl; 36 | 37 | sp.start_service(); 38 | while(sp.is_running()) 39 | { 40 | std::string str; 41 | std::getline(std::cin, str); 42 | if (str.empty()) 43 | ; 44 | else if (QUIT == str) 45 | sp.stop_service(); 46 | else 47 | { 48 | client.send_msg("client says: " + str); 49 | //client.broadcast_msg("client says: " + str); 50 | server.broadcast_msg("server says: " + str); 51 | } 52 | } 53 | unlink(UNIX_SOCKET_NAME); 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /unix_udp_test/makefile: -------------------------------------------------------------------------------- 1 | 2 | module = unix_udp_test 3 | 4 | include ../config.mk 5 | 6 | -------------------------------------------------------------------------------- /unix_udp_test/unix_udp_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | //configuration 5 | //configuration 6 | 7 | #include "../include/ext/udp.h" 8 | using namespace st_asio_wrapper; 9 | using namespace st_asio_wrapper::ext::udp; 10 | 11 | #define QUIT_COMMAND "quit" 12 | #define RESTART_COMMAND "restart" 13 | #define UNIX_SOCKET_NAME_1 "unix-socket-1" 14 | #define UNIX_SOCKET_NAME_2 "unix-socket-2" 15 | 16 | int main(int argc, const char* argv[]) 17 | { 18 | puts("type " QUIT_COMMAND " to end."); 19 | 20 | service_pump sp; 21 | 22 | unix_single_socket_service uu1(sp); 23 | unix_single_socket_service uu2(sp); 24 | //unix_multi_socket_service uu2(sp); 25 | 26 | unlink(UNIX_SOCKET_NAME_1); 27 | unlink(UNIX_SOCKET_NAME_2); 28 | uu1.set_local_addr(UNIX_SOCKET_NAME_1); 29 | uu1.set_peer_addr(UNIX_SOCKET_NAME_2); 30 | uu2.set_local_addr(UNIX_SOCKET_NAME_2); 31 | uu2.set_peer_addr(UNIX_SOCKET_NAME_1); 32 | //BOOST_AUTO(socket_ptr, uu2.create_object()); 33 | //socket_ptr->set_local_addr(UNIX_SOCKET_NAME_2); 34 | //socket_ptr->set_peer_addr(UNIX_SOCKET_NAME_1); 35 | //uu2.add_socket(socket_ptr); 36 | 37 | sp.start_service(); 38 | while(sp.is_running()) 39 | { 40 | std::string str; 41 | std::cin >> str; 42 | if (QUIT_COMMAND == str) 43 | sp.stop_service(); 44 | else if (RESTART_COMMAND == str) 45 | { 46 | sp.stop_service(); 47 | 48 | //add all clients back 49 | //auto socket_ptr = uu2.create_object(); 50 | //socket_ptr->set_local_addr(UNIX_SOCKET_NAME_2); 51 | //socket_ptr->set_peer_addr(UNIX_SOCKET_NAME_1); 52 | //uu2.add_socket(socket_ptr); 53 | sp.start_service(); 54 | } 55 | else 56 | { 57 | uu1.send_native_msg("uu1 -> uu2: " + str); 58 | uu2.send_native_msg("uu2 -> uu1: " + str); 59 | //uu2.at(0)->send_native_msg("uu2 -> uu1: " + str); 60 | } 61 | } 62 | unlink(UNIX_SOCKET_NAME_1); 63 | unlink(UNIX_SOCKET_NAME_2); 64 | 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /websocket_test/makefile: -------------------------------------------------------------------------------- 1 | 2 | module = websocket_test 3 | STD = c++11 4 | 5 | include ../config.mk 6 | 7 | -------------------------------------------------------------------------------- /websocket_test/websocket_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | //configuration 5 | //#define ST_ASIO_SYNC_RECV 6 | //#define ST_ASIO_SYNC_SEND 7 | //configuration 8 | 9 | #include "../include/ext/websocket.h" 10 | using namespace st_asio_wrapper; 11 | using namespace st_asio_wrapper::ext::websocket; 12 | 13 | #define QUIT_COMMAND "quit" 14 | #define RESTART_COMMAND "restart" 15 | #define RECONNECT "reconnect" 16 | 17 | int main(int argc, const char* argv[]) 18 | { 19 | puts("Demonstrate how to use websocket with st_asio_wrapper."); 20 | if (argc >= 2 && (0 == strcmp(argv[1], "--help") || 0 == strcmp(argv[1], "-h"))) 21 | return 0; 22 | else 23 | puts("type " QUIT_COMMAND " to end."); 24 | 25 | service_pump sp; 26 | 27 | server server_(sp); 28 | server_.set_start_object_id(1000); 29 | 30 | multi_client client_(sp); 31 | client_.add_socket(); 32 | client_.add_socket(); 33 | 34 | sp.start_service(2); 35 | while(sp.is_running()) 36 | { 37 | std::string str; 38 | std::cin >> str; 39 | if (QUIT_COMMAND == str) 40 | sp.stop_service(); 41 | else if (RESTART_COMMAND == str) 42 | { 43 | sp.stop_service(); 44 | 45 | //add all clients back 46 | client_.add_socket(); 47 | client_.add_socket(); 48 | sp.start_service(); 49 | } 50 | else if (RECONNECT == str) 51 | //client_.force_shutdown(true); 52 | client_.graceful_shutdown(true); 53 | else 54 | //client_.broadcast_native_msg(str); 55 | server_.broadcast_native_msg(str); 56 | } 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /websocket_test/websocket_test.vcproj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/youngwolf-project/st_asio_wrapper/3e060755ca6a8fc2ebfed8ccc41c561ad783a211/websocket_test/websocket_test.vcproj --------------------------------------------------------------------------------