├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── client.cpp ├── config └── server.ini ├── kill.sh ├── rpc ├── Client.cpp ├── Client.h ├── FunctionHandler.h ├── Server.cpp └── Server.h ├── serialize ├── DataStream.cpp ├── DataStream.h └── Serializable.h ├── server.cpp ├── socket ├── ClientSocket.cpp ├── ClientSocket.h ├── EventPoller.cpp ├── EventPoller.h ├── ServerSocket.cpp ├── ServerSocket.h ├── Socket.cpp ├── Socket.h ├── SocketHandler.cpp └── SocketHandler.h ├── task ├── TaskFactory.h ├── WorkTask.cpp └── WorkTask.h ├── thread ├── AutoLock.cpp ├── AutoLock.h ├── Condition.cpp ├── Condition.h ├── Mutex.cpp ├── Mutex.h ├── Task.cpp ├── Task.h ├── TaskDispatcher.cpp ├── TaskDispatcher.h ├── Thread.cpp ├── Thread.h ├── ThreadPool.cpp ├── ThreadPool.h ├── WorkerThread.cpp └── WorkerThread.h └── utility ├── IniFile.cpp ├── IniFile.h ├── Logger.cpp ├── Logger.h ├── ObjectPool.h ├── Singleton.h ├── System.cpp └── System.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Log 5 | *.log 6 | 7 | # pyenv 8 | .idea/ 9 | 10 | # vscode 11 | .vscode 12 | 13 | # Compiled Object files 14 | *.slo 15 | *.lo 16 | *.o 17 | *.obj 18 | 19 | # Precompiled Headers 20 | *.gch 21 | *.pch 22 | 23 | # Compiled Dynamic libraries 24 | *.so 25 | *.dylib 26 | *.dll 27 | 28 | # Fortran module files 29 | *.mod 30 | *.smod 31 | 32 | # Compiled Static libraries 33 | *.lai 34 | *.la 35 | *.a 36 | *.lib 37 | 38 | # Executables 39 | *.exe 40 | *.out 41 | *.app 42 | main 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 oldjun 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #指定编译器 2 | CC = g++ 3 | 4 | #找出当前目录下,所有的源文件(以.cpp结尾) 5 | SRCS := $(shell find ./* -type f | grep '\.cpp' | grep -v 'server\.cpp' | grep -v 'client\.cpp') 6 | $(warning SRCS is ${SRCS}) 7 | 8 | #确定cpp源文件对应的目标文件 9 | OBJS := $(patsubst %.cpp, %.o, $(filter %.cpp, $(SRCS))) 10 | $(warning OBJS is ${OBJS}) 11 | 12 | #编译选项 13 | CFLAGS = -g -O2 -Wall -Werror -Wno-unused -ldl -lpthread -fPIC -std=c++14 14 | $(warning CFLAGS is ${CFLAGS}) 15 | 16 | #找出当前目录下所有的头文件 17 | INCLUDE_TEMP = $(shell find ./* -type d) 18 | INCLUDE = $(patsubst %,-I %, $(INCLUDE_TEMP)) 19 | $(warning INCLUDE is ${INCLUDE}) 20 | 21 | SRC_SERVER = server.cpp 22 | OBJ_SERVER = ${SRC_SERVER:%.cpp=%.o} 23 | EXE_SERVER = server 24 | 25 | SRC_CLIENT = client.cpp 26 | OBJ_CLIENT = ${SRC_CLIENT:%.cpp=%.o} 27 | EXE_CLIENT = client 28 | 29 | target: ${EXE_SERVER} ${EXE_CLIENT} 30 | 31 | server: ${EXE_SERVER} 32 | 33 | client: ${EXE_CLIENT} 34 | 35 | $(EXE_SERVER): $(OBJ_SERVER) $(OBJS) 36 | $(CC) -o $@ $^ $(CFLAGS) $(INCLUDE) 37 | 38 | $(EXE_CLIENT): $(OBJ_CLIENT) $(OBJS) 39 | $(CC) -o $@ $^ $(CFLAGS) $(INCLUDE) 40 | 41 | clean: 42 | rm -f ${OBJS} ${OBJ_SERVER} ${OBJ_CLIENT} ${EXE_SERVER} ${EXE_CLIENT} 43 | 44 | %.o: %.cpp 45 | ${CC} ${CFLAGS} ${INCLUDE} -c $< -o $@ 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # yazi-rpc 2 | c++ rpc framework 3 | -------------------------------------------------------------------------------- /client.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #include "Client.h" 5 | using namespace yazi::rpc; 6 | 7 | class Request : public Serializable 8 | { 9 | public: 10 | Request() {} 11 | Request(const string & name) : m_name(name) {} 12 | ~Request() {} 13 | 14 | const string & name() const 15 | { 16 | return m_name; 17 | } 18 | 19 | SERIALIZE(m_name) 20 | 21 | private: 22 | string m_name; 23 | }; 24 | 25 | class Response : public Serializable 26 | { 27 | public: 28 | Response() {} 29 | Response(const string & name) : m_name(name) {} 30 | ~Response() {} 31 | 32 | const string & name() const 33 | { 34 | return m_name; 35 | } 36 | 37 | SERIALIZE(m_name) 38 | 39 | private: 40 | string m_name; 41 | }; 42 | 43 | int main() 44 | { 45 | Client client; 46 | client.connect("127.0.0.1", 8080); 47 | 48 | auto reply = client.call("hello", "kitty"); 49 | std::cout << reply << std::endl; 50 | 51 | auto total = client.call("sum", 1, 2); 52 | std::cout << total << std::endl; 53 | 54 | Request req("kitty"); 55 | auto resp = client.call("upper", req); 56 | std::cout << resp.name() << std::endl; 57 | 58 | return 0; 59 | } -------------------------------------------------------------------------------- /config/server.ini: -------------------------------------------------------------------------------- 1 | [server] 2 | ip = 127.0.0.1 3 | port = 8080 4 | threads = 8 5 | max_conn = 32 6 | wait_time = 10 7 | -------------------------------------------------------------------------------- /kill.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ps -ef|grep server|grep -v grep|grep -v vscode|awk -F ' ' '{print $2}'|xargs kill -9 4 | 5 | rm -rf log/*.log 6 | 7 | -------------------------------------------------------------------------------- /rpc/Client.cpp: -------------------------------------------------------------------------------- 1 | #include "Client.h" 2 | using namespace yazi::rpc; 3 | 4 | #include "System.h" 5 | #include "Logger.h" 6 | #include "Singleton.h" 7 | using namespace yazi::utility; 8 | 9 | 10 | Client::Client() 11 | { 12 | System * sys = Singleton::instance(); 13 | sys->init(); 14 | 15 | // init logger 16 | Logger::instance()->open(sys->get_root_path() + "/log/client.log"); 17 | } 18 | 19 | Client::~Client() 20 | { 21 | m_socket.close(); 22 | } 23 | 24 | bool Client::connect(const string & ip, int port) 25 | { 26 | m_ip = ip; 27 | m_port = port; 28 | return m_socket.connect(ip, port); 29 | } -------------------------------------------------------------------------------- /rpc/Client.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | #include "ClientSocket.h" 9 | using namespace yazi::socket; 10 | 11 | #include "DataStream.h" 12 | using namespace yazi::serialize; 13 | 14 | namespace yazi { 15 | namespace rpc { 16 | 17 | struct MsgHead { 18 | char flag[8]; 19 | uint32_t cmd; 20 | uint32_t len; 21 | }; 22 | 23 | const uint32_t send_buff_size = 1024; 24 | const uint32_t recv_buff_size = 1024; 25 | 26 | class Client 27 | { 28 | public: 29 | Client(); 30 | ~Client(); 31 | 32 | bool connect(const string & ip, int port); 33 | 34 | template 35 | R call(const string & name, const Args&... args); 36 | 37 | private: 38 | string m_ip; 39 | int m_port; 40 | ClientSocket m_socket; 41 | }; 42 | 43 | template 44 | R Client::call(const string & name, const Args&... args) 45 | { 46 | DataStream in; 47 | in << name; 48 | in.write_args(args...); 49 | 50 | MsgHead head; 51 | strcpy(head.flag, "work"); 52 | head.cmd = 0; 53 | head.len = in.size(); 54 | 55 | char send_buff[send_buff_size]; 56 | std::memcpy(send_buff, (char *)&head, sizeof(MsgHead)); 57 | std::memcpy(send_buff + sizeof(MsgHead), in.data(), in.size()); 58 | 59 | int len = sizeof(MsgHead) + in.size(); 60 | m_socket.send(send_buff, len); 61 | 62 | char recv_buff[recv_buff_size]; 63 | int recv_size = m_socket.recv(recv_buff, recv_buff_size); 64 | 65 | DataStream out; 66 | out.write(recv_buff, recv_size); 67 | 68 | R v; 69 | out >> v; 70 | return v; 71 | } 72 | 73 | } 74 | } -------------------------------------------------------------------------------- /rpc/FunctionHandler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | #include "DataStream.h" 9 | using namespace yazi::serialize; 10 | 11 | namespace yazi { 12 | namespace rpc { 13 | 14 | class FunctionHandler 15 | { 16 | public: 17 | FunctionHandler() {} 18 | ~FunctionHandler() {} 19 | 20 | template 21 | void bind(const string & name, F func); 22 | 23 | void call(const string & name, DataStream & in, DataStream & out); 24 | 25 | private: 26 | template 27 | void wrap(F func, DataStream & in, DataStream & out); 28 | 29 | template 30 | void wrap_impl(R(*func)(Args...), DataStream & in, DataStream & out); 31 | 32 | template 33 | void wrap_impl(std::function func, DataStream & in, DataStream & out); 34 | 35 | template 36 | typename std::enable_if::value, int32_t>::type 37 | call_impl(F func, Tuple args); 38 | 39 | template 40 | typename std::enable_if::value, R>::type 41 | call_impl(F func, Tuple args); 42 | 43 | template 44 | auto invoke(F && func, Tuple && t); 45 | 46 | template 47 | auto invoke_impl(F && func, Tuple && t, std::index_sequence); 48 | 49 | template 50 | Tuple get_args(DataStream & ds, std::index_sequence); 51 | 52 | template 53 | void get_arg(DataStream & ds, Tuple & t); 54 | 55 | private: 56 | std::map> m_handlers; 57 | }; 58 | 59 | inline void FunctionHandler::call(const string & name, DataStream & in, DataStream & out) 60 | { 61 | auto func = m_handlers[name]; 62 | func(in, out); 63 | } 64 | 65 | template 66 | void FunctionHandler::bind(const string & name, F func) 67 | { 68 | m_handlers[name] = std::bind(&FunctionHandler::wrap, this, func, std::placeholders::_1, std::placeholders::_2); 69 | } 70 | 71 | template 72 | void FunctionHandler::wrap(F func, DataStream & in, DataStream & out) 73 | { 74 | wrap_impl(func, in, out); 75 | } 76 | 77 | template 78 | void FunctionHandler::wrap_impl(R(*func)(Args...), DataStream & in, DataStream & out) 79 | { 80 | wrap_impl(std::function(func), in, out); 81 | } 82 | 83 | template 84 | void FunctionHandler::wrap_impl(std::function func, DataStream & in, DataStream & out) 85 | { 86 | using args_type = std::tuple::type...>; 87 | constexpr auto size = std::tuple_size::type>::value; 88 | args_type args = get_args(in, std::make_index_sequence{}); 89 | auto ret = call_impl(func, args); 90 | out << ret; 91 | } 92 | 93 | template 94 | typename std::enable_if::value, int32_t>::type 95 | FunctionHandler::call_impl(F func, Tuple args) 96 | { 97 | invoke(func, args); 98 | return 0; 99 | } 100 | 101 | template 102 | typename std::enable_if::value, R>::type 103 | FunctionHandler::call_impl(F func, Tuple args) 104 | { 105 | return invoke(func, args); 106 | } 107 | 108 | template 109 | auto FunctionHandler::invoke(F && func, Tuple && t) 110 | { 111 | constexpr auto size = std::tuple_size::type>::value; 112 | return invoke_impl(std::forward(func), std::forward(t), std::make_index_sequence{}); 113 | } 114 | 115 | template 116 | auto FunctionHandler::invoke_impl(F && func, Tuple && t, std::index_sequence) 117 | { 118 | return func(std::get(std::forward(t))...); 119 | } 120 | 121 | template 122 | Tuple FunctionHandler::get_args(DataStream & ds, std::index_sequence) 123 | { 124 | Tuple t; 125 | initializer_list{((get_arg(ds, t)), 0)...}; 126 | return t; 127 | } 128 | 129 | template 130 | void FunctionHandler::get_arg(DataStream & ds, Tuple & t) 131 | { 132 | ds >> std::get(t); 133 | } 134 | 135 | } 136 | } -------------------------------------------------------------------------------- /rpc/Server.cpp: -------------------------------------------------------------------------------- 1 | #include "Server.h" 2 | using namespace yazi::rpc; 3 | 4 | #include "System.h" 5 | #include "Logger.h" 6 | #include "IniFile.h" 7 | #include "Singleton.h" 8 | using namespace yazi::utility; 9 | 10 | #include "TaskDispatcher.h" 11 | using namespace yazi::thread; 12 | 13 | #include "SocketHandler.h" 14 | using namespace yazi::socket; 15 | 16 | Server::Server() 17 | { 18 | System * sys = Singleton::instance(); 19 | sys->init(); 20 | 21 | // init logger 22 | Logger::instance()->open(sys->get_root_path() + "/log/server.log"); 23 | 24 | // init inifile 25 | IniFile * ini = Singleton::instance(); 26 | ini->load(sys->get_root_path() + "/config/server.ini"); 27 | 28 | m_ip = (string)(*ini)["server"]["ip"]; 29 | m_port = (*ini)["server"]["port"]; 30 | m_threads = (*ini)["server"]["threads"]; 31 | m_connects = (*ini)["server"]["max_conn"]; 32 | m_wait_time = (*ini)["server"]["wait_time"]; 33 | } 34 | 35 | Server::~Server() 36 | { 37 | } 38 | 39 | void Server::listen(const string & ip, int port) 40 | { 41 | m_ip = ip; 42 | m_port = port; 43 | } 44 | 45 | void Server::start() 46 | { 47 | // init the thread pool and task queue 48 | TaskDispatcher * dispatcher = Singleton::instance(); 49 | dispatcher->init(m_threads); 50 | 51 | // init the socket handler 52 | SocketHandler * socket_handler = Singleton::instance(); 53 | socket_handler->listen(m_ip, m_port); 54 | socket_handler->handle(m_connects, m_wait_time); 55 | } 56 | 57 | void Server::set_threads(int threads) 58 | { 59 | m_threads = threads; 60 | } 61 | 62 | void Server::set_connects(int connects) 63 | { 64 | m_connects = connects; 65 | } 66 | 67 | void Server::set_wait_time(int wait_time) 68 | { 69 | m_wait_time = wait_time; 70 | } 71 | 72 | -------------------------------------------------------------------------------- /rpc/Server.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | using namespace std; 5 | 6 | #include "Singleton.h" 7 | using namespace yazi::utility; 8 | 9 | #include "FunctionHandler.h" 10 | 11 | namespace yazi { 12 | namespace rpc { 13 | 14 | class Server 15 | { 16 | public: 17 | Server(); 18 | ~Server(); 19 | 20 | void listen(const string & ip, int port); 21 | void start(); 22 | void set_threads(int threads); 23 | void set_connects(int connects); 24 | void set_wait_time(int wait_time); 25 | 26 | template 27 | void bind(const string & name, F func) 28 | { 29 | m_handler.bind(name, func); 30 | } 31 | 32 | void call(const string & name, DataStream & in, DataStream & out) 33 | { 34 | m_handler.call(name, in, out); 35 | } 36 | 37 | private: 38 | string m_ip; 39 | int m_port; 40 | int m_threads; 41 | int m_connects; 42 | int m_wait_time; 43 | 44 | FunctionHandler m_handler; 45 | }; 46 | 47 | }} 48 | -------------------------------------------------------------------------------- /serialize/DataStream.cpp: -------------------------------------------------------------------------------- 1 | #include "DataStream.h" 2 | using namespace yazi::serialize; 3 | 4 | DataStream::DataStream() : m_pos(0) 5 | { 6 | m_byteorder = byteorder(); 7 | } 8 | 9 | DataStream::DataStream(const string & str) : m_pos(0) 10 | { 11 | m_byteorder = byteorder(); 12 | m_buf.clear(); 13 | reserve(str.size()); 14 | write(str.data(), str.size()); 15 | } 16 | 17 | DataStream::~DataStream() 18 | { 19 | } 20 | 21 | void DataStream::reserve(int len) 22 | { 23 | int size = m_buf.size(); 24 | int cap = m_buf.capacity(); 25 | if (size + len > cap) 26 | { 27 | while (size + len > cap) 28 | { 29 | if (cap == 0) 30 | { 31 | cap = 1; 32 | } 33 | else 34 | { 35 | cap *= 2; 36 | } 37 | } 38 | m_buf.reserve(cap); 39 | } 40 | } 41 | 42 | DataStream::ByteOrder DataStream::byteorder() 43 | { 44 | int n = 0x12345678; 45 | char str[4]; 46 | memcpy(str, &n, sizeof(int)); 47 | if (str[0] == 0x12) 48 | { 49 | return ByteOrder::BigEndian; 50 | } 51 | else 52 | { 53 | return ByteOrder::LittleEndian; 54 | } 55 | } 56 | 57 | void DataStream::show() const 58 | { 59 | int size = m_buf.size(); 60 | std::cout << "data size = " << size << std::endl; 61 | int i = 0; 62 | while (i < size) 63 | { 64 | switch ((DataType)m_buf[i]) 65 | { 66 | case DataType::BOOL: 67 | if ((int)m_buf[++i] == 0) 68 | { 69 | std::cout << "false"; 70 | } 71 | else 72 | { 73 | std::cout << "true"; 74 | } 75 | ++i; 76 | break; 77 | case DataType::CHAR: 78 | std::cout << m_buf[++i]; 79 | ++i; 80 | break; 81 | case DataType::INT32: 82 | std::cout << *((int32_t *)(&m_buf[++i])); 83 | i += 4; 84 | break; 85 | case DataType::INT64: 86 | std::cout << *((int64_t *)(&m_buf[++i])); 87 | i += 8; 88 | break; 89 | case DataType::FLOAT: 90 | std::cout << *((float *)(&m_buf[++i])); 91 | i += 4; 92 | break; 93 | case DataType::DOUBLE: 94 | std::cout << *((double *)(&m_buf[++i])); 95 | i += 8; 96 | break; 97 | case DataType::STRING: 98 | if ((DataType)m_buf[++i] == DataType::INT32) 99 | { 100 | int len = *((int *)(&m_buf[++i])); 101 | i += 4; 102 | std::cout << string(&m_buf[i], len); 103 | i += len; 104 | } 105 | else 106 | { 107 | throw std::logic_error("parse string error"); 108 | } 109 | break; 110 | case DataType::VECTOR: 111 | if ((DataType)m_buf[++i] == DataType::INT32) 112 | { 113 | int len = *((int *)(&m_buf[++i])); 114 | i += 4; 115 | } 116 | else 117 | { 118 | throw std::logic_error("parse vector error"); 119 | } 120 | break; 121 | case DataType::MAP: 122 | if ((DataType)m_buf[++i] == DataType::INT32) 123 | { 124 | int len = *((int *)(&m_buf[++i])); 125 | i += 4; 126 | } 127 | else 128 | { 129 | throw std::logic_error("parse map error"); 130 | } 131 | break; 132 | case DataType::SET: 133 | if ((DataType)m_buf[++i] == DataType::INT32) 134 | { 135 | int len = *((int *)(&m_buf[++i])); 136 | i += 4; 137 | } 138 | else 139 | { 140 | throw std::logic_error("parse set error"); 141 | } 142 | break; 143 | case DataType::CUSTOM: 144 | break; 145 | default: 146 | break; 147 | } 148 | } 149 | std::cout << std::endl; 150 | } 151 | 152 | void DataStream::write(const char * data, int len) 153 | { 154 | reserve(len); 155 | int size = m_buf.size(); 156 | m_buf.resize(m_buf.size() + len); 157 | std::memcpy(&m_buf[size], data, len); 158 | } 159 | 160 | void DataStream::write(bool value) 161 | { 162 | char type = DataType::BOOL; 163 | write((char *)&type, sizeof(char)); 164 | write((char *)&value, sizeof(char)); 165 | } 166 | 167 | void DataStream::write(char value) 168 | { 169 | char type = DataType::CHAR; 170 | write((char *)&type, sizeof(char)); 171 | write((char *)&value, sizeof(char)); 172 | } 173 | 174 | void DataStream::write(int32_t value) 175 | { 176 | char type = DataType::INT32; 177 | write((char *)&type, sizeof(char)); 178 | if (m_byteorder == ByteOrder::BigEndian) 179 | { 180 | char * first = (char *)&value; 181 | char * last = first + sizeof(int32_t); 182 | std::reverse(first, last); 183 | } 184 | write((char *)&value, sizeof(int32_t)); 185 | } 186 | 187 | void DataStream::write(int64_t value) 188 | { 189 | char type = DataType::INT64; 190 | write((char *)&type, sizeof(char)); 191 | if (m_byteorder == ByteOrder::BigEndian) 192 | { 193 | char * first = (char *)&value; 194 | char * last = first + sizeof(int64_t); 195 | std::reverse(first, last); 196 | } 197 | write((char *)&value, sizeof(int64_t)); 198 | } 199 | 200 | void DataStream::write(float value) 201 | { 202 | char type = DataType::FLOAT; 203 | write((char *)&type, sizeof(char)); 204 | if (m_byteorder == ByteOrder::BigEndian) 205 | { 206 | char * first = (char *)&value; 207 | char * last = first + sizeof(float); 208 | std::reverse(first, last); 209 | } 210 | write((char *)&value, sizeof(float)); 211 | } 212 | 213 | void DataStream::write(double value) 214 | { 215 | char type = DataType::DOUBLE; 216 | write((char *)&type, sizeof(char)); 217 | if (m_byteorder == ByteOrder::BigEndian) 218 | { 219 | char * first = (char *)&value; 220 | char * last = first + sizeof(double); 221 | std::reverse(first, last); 222 | } 223 | write((char *)&value, sizeof(double)); 224 | } 225 | 226 | void DataStream::write(const char * value) 227 | { 228 | char type = DataType::STRING; 229 | write((char *)&type, sizeof(char)); 230 | int len = strlen(value); 231 | write(len); 232 | write(value, len); 233 | } 234 | 235 | void DataStream::write(const string & value) 236 | { 237 | char type = DataType::STRING; 238 | write((char *)&type, sizeof(char)); 239 | int len = value.size(); 240 | write(len); 241 | write(value.data(), len); 242 | } 243 | 244 | void DataStream::write(const Serializable & value) 245 | { 246 | value.serialize(*this); 247 | } 248 | 249 | 250 | void DataStream::write_args() 251 | { 252 | } 253 | 254 | bool DataStream::read(char * data, int len) 255 | { 256 | std::memcpy(data, (char *)&m_buf[m_pos], len); 257 | m_pos += len; 258 | return true; 259 | } 260 | 261 | bool DataStream::read(bool & value) 262 | { 263 | if (m_buf[m_pos] != DataType::BOOL) 264 | { 265 | return false; 266 | } 267 | ++m_pos; 268 | value = m_buf[m_pos]; 269 | ++m_pos; 270 | return true; 271 | } 272 | 273 | bool DataStream::read(char & value) 274 | { 275 | if (m_buf[m_pos] != DataType::CHAR) 276 | { 277 | return false; 278 | } 279 | ++m_pos; 280 | value = m_buf[m_pos]; 281 | ++m_pos; 282 | return true; 283 | } 284 | 285 | bool DataStream::read(int32_t & value) 286 | { 287 | if (m_buf[m_pos] != DataType::INT32) 288 | { 289 | return false; 290 | } 291 | ++m_pos; 292 | value = *((int32_t *)(&m_buf[m_pos])); 293 | if (m_byteorder == ByteOrder::BigEndian) 294 | { 295 | char * first = (char *)&value; 296 | char * last = first + sizeof(int32_t); 297 | std::reverse(first, last); 298 | } 299 | m_pos += 4; 300 | return true; 301 | } 302 | 303 | bool DataStream::read(int64_t & value) 304 | { 305 | if (m_buf[m_pos] != DataType::INT64) 306 | { 307 | return false; 308 | } 309 | ++m_pos; 310 | value = *((int64_t *)(&m_buf[m_pos])); 311 | if (m_byteorder == ByteOrder::BigEndian) 312 | { 313 | char * first = (char *)&value; 314 | char * last = first + sizeof(int64_t); 315 | std::reverse(first, last); 316 | } 317 | m_pos += 8; 318 | return true; 319 | } 320 | 321 | bool DataStream::read(float & value) 322 | { 323 | if (m_buf[m_pos] != DataType::FLOAT) 324 | { 325 | return false; 326 | } 327 | ++m_pos; 328 | value = *((float *)(&m_buf[m_pos])); 329 | if (m_byteorder == ByteOrder::BigEndian) 330 | { 331 | char * first = (char *)&value; 332 | char * last = first + sizeof(float); 333 | std::reverse(first, last); 334 | } 335 | m_pos += 4; 336 | return true; 337 | } 338 | 339 | bool DataStream::read(double & value) 340 | { 341 | if (m_buf[m_pos] != DataType::DOUBLE) 342 | { 343 | return false; 344 | } 345 | ++m_pos; 346 | value = *((double *)(&m_buf[m_pos])); 347 | if (m_byteorder == ByteOrder::BigEndian) 348 | { 349 | char * first = (char *)&value; 350 | char * last = first + sizeof(double); 351 | std::reverse(first, last); 352 | } 353 | m_pos += 8; 354 | return true; 355 | } 356 | 357 | bool DataStream::read(string & value) 358 | { 359 | if (m_buf[m_pos] != DataType::STRING) 360 | { 361 | return false; 362 | } 363 | ++m_pos; 364 | int len; 365 | read(len); 366 | if (len < 0) 367 | { 368 | return false; 369 | } 370 | value.assign((char *)&(m_buf[m_pos]), len); 371 | m_pos += len; 372 | return true; 373 | } 374 | 375 | bool DataStream::read(Serializable & value) 376 | { 377 | return value.unserialize(*this); 378 | } 379 | 380 | 381 | bool DataStream::read_args() 382 | { 383 | return true; 384 | } 385 | 386 | const char * DataStream::data() const 387 | { 388 | return m_buf.data(); 389 | } 390 | 391 | int DataStream::size() const 392 | { 393 | return m_buf.size(); 394 | } 395 | 396 | void DataStream::clear() 397 | { 398 | m_buf.clear(); 399 | } 400 | 401 | void DataStream::reset() 402 | { 403 | m_pos = 0; 404 | } 405 | 406 | void DataStream::save(const string & filename) 407 | { 408 | ofstream fout(filename); 409 | fout.write(data(), size()); 410 | fout.flush(); 411 | fout.close(); 412 | } 413 | 414 | void DataStream::load(const string & filename) 415 | { 416 | ifstream fin(filename); 417 | stringstream ss; 418 | ss << fin.rdbuf(); 419 | const string & str = ss.str(); 420 | m_buf.clear(); 421 | reserve(str.size()); 422 | write(str.data(), str.size()); 423 | } 424 | 425 | DataStream & DataStream::operator << (bool value) 426 | { 427 | write(value); 428 | return *this; 429 | } 430 | 431 | DataStream & DataStream::operator << (char value) 432 | { 433 | write(value); 434 | return *this; 435 | } 436 | 437 | DataStream & DataStream::operator << (int32_t value) 438 | { 439 | write(value); 440 | return *this; 441 | } 442 | 443 | DataStream & DataStream::operator << (int64_t value) 444 | { 445 | write(value); 446 | return *this; 447 | } 448 | 449 | DataStream & DataStream::operator << (float value) 450 | { 451 | write(value); 452 | return *this; 453 | } 454 | 455 | DataStream & DataStream::operator << (double value) 456 | { 457 | write(value); 458 | return *this; 459 | } 460 | 461 | DataStream & DataStream::operator << (const char * value) 462 | { 463 | write(value); 464 | return *this; 465 | } 466 | 467 | DataStream & DataStream::operator << (const string & value) 468 | { 469 | write(value); 470 | return *this; 471 | } 472 | 473 | DataStream & DataStream::operator << (const Serializable & value) 474 | { 475 | write(value); 476 | return *this; 477 | } 478 | 479 | DataStream & DataStream::operator >> (bool & value) 480 | { 481 | read(value); 482 | return *this; 483 | } 484 | 485 | DataStream & DataStream::operator >> (char & value) 486 | { 487 | read(value); 488 | return *this; 489 | } 490 | 491 | DataStream & DataStream::operator >> (int32_t & value) 492 | { 493 | read(value); 494 | return *this; 495 | } 496 | 497 | DataStream & DataStream::operator >> (int64_t & value) 498 | { 499 | read(value); 500 | return *this; 501 | } 502 | 503 | DataStream & DataStream::operator >> (float & value) 504 | { 505 | read(value); 506 | return *this; 507 | } 508 | 509 | DataStream & DataStream::operator >> (double & value) 510 | { 511 | read(value); 512 | return *this; 513 | } 514 | 515 | DataStream & DataStream::operator >> (string & value) 516 | { 517 | read(value); 518 | return *this; 519 | } 520 | 521 | DataStream & DataStream::operator >> (Serializable & value) 522 | { 523 | read(value); 524 | return *this; 525 | } -------------------------------------------------------------------------------- /serialize/DataStream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | using namespace std; 15 | 16 | #include "Serializable.h" 17 | 18 | namespace yazi { 19 | namespace serialize { 20 | 21 | class DataStream 22 | { 23 | public: 24 | enum DataType 25 | { 26 | BOOL = 0, 27 | CHAR, 28 | INT32, 29 | INT64, 30 | FLOAT, 31 | DOUBLE, 32 | STRING, 33 | VECTOR, 34 | LIST, 35 | MAP, 36 | SET, 37 | CUSTOM 38 | }; 39 | 40 | enum ByteOrder 41 | { 42 | BigEndian, 43 | LittleEndian 44 | }; 45 | 46 | DataStream(); 47 | DataStream(const string & data); 48 | ~DataStream(); 49 | 50 | void show() const; 51 | void write(const char * data, int len); 52 | void write(bool value); 53 | void write(char value); 54 | void write(int32_t value); 55 | void write(int64_t value); 56 | void write(float value); 57 | void write(double value); 58 | void write(const char * value); 59 | void write(const string & value); 60 | void write(const Serializable & value); 61 | 62 | template 63 | void write(const std::vector & value); 64 | 65 | template 66 | void write(const std::list & value); 67 | 68 | template 69 | void write(const std::map & value); 70 | 71 | template 72 | void write(const std::set & value); 73 | 74 | template 75 | void write_args(const T & head, const Args&... args); 76 | 77 | void write_args(); 78 | 79 | bool read(char * data, int len); 80 | bool read(bool & value); 81 | bool read(char & value); 82 | bool read(int32_t & value); 83 | bool read(int64_t & value); 84 | bool read(float & value); 85 | bool read(double & value); 86 | bool read(string & value); 87 | bool read(Serializable & value); 88 | 89 | template 90 | bool read(std::vector & value); 91 | 92 | template 93 | bool read(std::list & value); 94 | 95 | template 96 | bool read(std::map & value); 97 | 98 | template 99 | bool read(std::set & value); 100 | 101 | template 102 | bool read_args(T & head, Args&... args); 103 | 104 | bool read_args(); 105 | 106 | const char * data() const; 107 | int size() const; 108 | void clear(); 109 | void reset(); 110 | void save(const string & filename); 111 | void load(const string & filename); 112 | 113 | DataStream & operator << (bool value); 114 | DataStream & operator << (char value); 115 | DataStream & operator << (int32_t value); 116 | DataStream & operator << (int64_t value); 117 | DataStream & operator << (float value); 118 | DataStream & operator << (double value); 119 | DataStream & operator << (const char * value); 120 | DataStream & operator << (const string & value); 121 | DataStream & operator << (const Serializable & value); 122 | 123 | template 124 | DataStream & operator << (const std::vector & value); 125 | 126 | template 127 | DataStream & operator << (const std::list & value); 128 | 129 | template 130 | DataStream & operator << (const std::map & value); 131 | 132 | template 133 | DataStream & operator << (const std::set & value); 134 | 135 | DataStream & operator >> (bool & value); 136 | DataStream & operator >> (char & value); 137 | DataStream & operator >> (int32_t & value); 138 | DataStream & operator >> (int64_t & value); 139 | DataStream & operator >> (float & value); 140 | DataStream & operator >> (double & value); 141 | DataStream & operator >> (string & value); 142 | DataStream & operator >> (Serializable & value); 143 | 144 | template 145 | DataStream & operator >> (std::vector & value); 146 | 147 | template 148 | DataStream & operator >> (std::list & value); 149 | 150 | template 151 | DataStream & operator >> (std::map & value); 152 | 153 | template 154 | DataStream & operator >> (std::set & value); 155 | 156 | private: 157 | void reserve(int len); 158 | ByteOrder byteorder(); 159 | 160 | private: 161 | std::vector m_buf; 162 | int m_pos; 163 | ByteOrder m_byteorder; 164 | }; 165 | 166 | template 167 | void DataStream::write(const std::vector & value) 168 | { 169 | char type = DataType::VECTOR; 170 | write((char *)&type, sizeof(char)); 171 | int len = value.size(); 172 | write(len); 173 | for (int i = 0; i < len; i++) 174 | { 175 | write(value[i]); 176 | } 177 | } 178 | 179 | template 180 | void DataStream::write(const std::list & value) 181 | { 182 | char type = DataType::LIST; 183 | write((char *)&type, sizeof(char)); 184 | int len = value.size(); 185 | write(len); 186 | for (auto it = value.begin(); it != value.end(); it++) 187 | { 188 | write((*it)); 189 | } 190 | } 191 | 192 | template 193 | void DataStream::write(const std::map & value) 194 | { 195 | char type = DataType::MAP; 196 | write((char *)&type, sizeof(char)); 197 | int len = value.size(); 198 | write(len); 199 | for (auto it = value.begin(); it != value.end(); it++) 200 | { 201 | write(it->first); 202 | write(it->second); 203 | } 204 | } 205 | 206 | template 207 | void DataStream::write(const std::set & value) 208 | { 209 | char type = DataType::SET; 210 | write((char *)&type, sizeof(char)); 211 | int len = value.size(); 212 | write(len); 213 | for (auto it = value.begin(); it != value.end(); it++) 214 | { 215 | write(*it); 216 | } 217 | } 218 | 219 | template 220 | void DataStream::write_args(const T & head, const Args&... args) 221 | { 222 | write(head); 223 | write_args(args...); 224 | } 225 | 226 | template 227 | bool DataStream::read(std::vector & value) 228 | { 229 | value.clear(); 230 | if (m_buf[m_pos] != DataType::VECTOR) 231 | { 232 | return false; 233 | } 234 | ++m_pos; 235 | int len; 236 | read(len); 237 | for (int i = 0; i < len; i++) 238 | { 239 | T v; 240 | read(v); 241 | value.push_back(v); 242 | } 243 | return true; 244 | } 245 | 246 | template 247 | bool DataStream::read(std::list & value) 248 | { 249 | value.clear(); 250 | if (m_buf[m_pos] != DataType::LIST) 251 | { 252 | return false; 253 | } 254 | ++m_pos; 255 | int len; 256 | read(len); 257 | for (int i = 0; i < len; i++) 258 | { 259 | T v; 260 | read(v); 261 | value.push_back(v); 262 | } 263 | return true; 264 | } 265 | 266 | template 267 | bool DataStream::read(std::map & value) 268 | { 269 | value.clear(); 270 | if (m_buf[m_pos] != DataType::MAP) 271 | { 272 | return false; 273 | } 274 | ++m_pos; 275 | int len; 276 | read(len); 277 | for (int i = 0; i < len; i++) 278 | { 279 | K k; 280 | read(k); 281 | 282 | V v; 283 | read(v); 284 | value[k] = v; 285 | } 286 | return true; 287 | } 288 | 289 | template 290 | bool DataStream::read(std::set & value) 291 | { 292 | value.clear(); 293 | if (m_buf[m_pos] != DataType::SET) 294 | { 295 | return false; 296 | } 297 | ++m_pos; 298 | int len; 299 | read(len); 300 | for (int i = 0; i < len; i++) 301 | { 302 | T v; 303 | read(v); 304 | value.insert(v); 305 | } 306 | return true; 307 | } 308 | 309 | template 310 | bool DataStream::read_args(T & head, Args&... args) 311 | { 312 | read(head); 313 | return read_args(args...); 314 | } 315 | 316 | template 317 | DataStream & DataStream::operator << (const std::vector & value) 318 | { 319 | write(value); 320 | return *this; 321 | } 322 | 323 | template 324 | DataStream & DataStream::operator << (const std::map & value) 325 | { 326 | write(value); 327 | return *this; 328 | } 329 | 330 | template 331 | DataStream & DataStream::operator << (const std::set & value) 332 | { 333 | write(value); 334 | return *this; 335 | } 336 | 337 | template 338 | DataStream & DataStream::operator >> (std::vector & value) 339 | { 340 | read(value); 341 | return *this; 342 | } 343 | 344 | template 345 | DataStream & DataStream::operator >> (std::list & value) 346 | { 347 | read(value); 348 | return *this; 349 | } 350 | 351 | template 352 | DataStream & DataStream::operator >> (std::map & value) 353 | { 354 | read(value); 355 | return *this; 356 | } 357 | 358 | template 359 | DataStream & DataStream::operator >> (std::set & value) 360 | { 361 | read(value); 362 | return *this; 363 | } 364 | 365 | } 366 | } -------------------------------------------------------------------------------- /serialize/Serializable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace yazi { 4 | namespace serialize { 5 | 6 | class DataStream; 7 | 8 | class Serializable 9 | { 10 | public: 11 | virtual void serialize(DataStream & stream) const = 0; 12 | virtual bool unserialize(DataStream & stream) = 0; 13 | }; 14 | 15 | #define SERIALIZE(...) \ 16 | void serialize(DataStream & stream) const \ 17 | { \ 18 | char type = DataStream::CUSTOM; \ 19 | stream.write((char *)&type, sizeof(char)); \ 20 | stream.write_args(__VA_ARGS__); \ 21 | } \ 22 | \ 23 | bool unserialize(DataStream & stream) \ 24 | { \ 25 | char type; \ 26 | stream.read(&type, sizeof(char)); \ 27 | if (type != DataStream::CUSTOM) \ 28 | { \ 29 | return false; \ 30 | } \ 31 | stream.read_args(__VA_ARGS__); \ 32 | return true; \ 33 | } 34 | 35 | } 36 | } -------------------------------------------------------------------------------- /server.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | #include "Server.h" 6 | using namespace yazi::rpc; 7 | 8 | string hello(const string & name) 9 | { 10 | return "hello, " + name; 11 | } 12 | 13 | int sum(int a, int b) 14 | { 15 | return a + b; 16 | } 17 | 18 | class Request : public Serializable 19 | { 20 | public: 21 | Request() {} 22 | Request(const string & name) : m_name(name) {} 23 | ~Request() {} 24 | 25 | const string & name() const 26 | { 27 | return m_name; 28 | } 29 | 30 | SERIALIZE(m_name) 31 | 32 | private: 33 | string m_name; 34 | }; 35 | 36 | class Response : public Serializable 37 | { 38 | public: 39 | Response() {} 40 | Response(const string & name) : m_name(name) {} 41 | ~Response() {} 42 | 43 | const string & name() const 44 | { 45 | return m_name; 46 | } 47 | 48 | SERIALIZE(m_name) 49 | 50 | private: 51 | string m_name; 52 | }; 53 | 54 | Response upper(const Request & req) 55 | { 56 | string name = req.name(); 57 | transform(name.begin(), name.end(), name.begin(), ::toupper); 58 | return Response(name); 59 | } 60 | 61 | int main() 62 | { 63 | Server * server = Singleton::instance(); 64 | server->listen("127.0.0.1", 8080); 65 | server->bind("hello", hello); 66 | server->bind("sum", sum); 67 | server->bind("upper", upper); 68 | server->start(); 69 | 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /socket/ClientSocket.cpp: -------------------------------------------------------------------------------- 1 | #include "ClientSocket.h" 2 | #include "Logger.h" 3 | using namespace yazi::utility; 4 | using namespace yazi::socket; 5 | 6 | #include 7 | using namespace std; 8 | 9 | #include 10 | using namespace std; 11 | 12 | ClientSocket::ClientSocket() : Socket() 13 | { 14 | m_sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 15 | if (m_sockfd < 0) 16 | { 17 | error("create client socket error: errno=%d errstr=%s", errno, strerror(errno)); 18 | } 19 | } 20 | 21 | ClientSocket::ClientSocket(const string& ip, int port) : Socket(ip, port) 22 | { 23 | m_sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 24 | if (m_sockfd < 0) 25 | { 26 | error("create client socket error: errno=%d errstr=%s", errno, strerror(errno)); 27 | return; 28 | } 29 | Socket::connect(ip, port); 30 | } 31 | 32 | ClientSocket::~ClientSocket() 33 | { 34 | close(); 35 | } 36 | -------------------------------------------------------------------------------- /socket/ClientSocket.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | using namespace std; 5 | 6 | #include "Socket.h" 7 | 8 | namespace yazi { 9 | namespace socket { 10 | 11 | class ClientSocket : public Socket 12 | { 13 | public: 14 | ClientSocket(); 15 | ClientSocket(const string &ip, int port); 16 | virtual ~ClientSocket(); 17 | }; 18 | 19 | }} 20 | -------------------------------------------------------------------------------- /socket/EventPoller.cpp: -------------------------------------------------------------------------------- 1 | #include "EventPoller.h" 2 | 3 | using namespace yazi::socket; 4 | 5 | EventPoller::EventPoller(bool et) : m_epfd(0), m_max_connections(0), m_events(NULL), m_et(et) 6 | { 7 | } 8 | 9 | EventPoller::~EventPoller() 10 | { 11 | if (m_epfd > 0) 12 | { 13 | close(m_epfd); 14 | m_epfd = 0; 15 | } 16 | 17 | if (m_events != NULL) 18 | { 19 | delete[] m_events; 20 | m_events = NULL; 21 | } 22 | } 23 | 24 | void EventPoller::ctrl(int fd, void * ptr, __uint32_t events, int op) 25 | { 26 | struct epoll_event ev; 27 | ev.data.ptr = ptr; 28 | if (m_et) 29 | { 30 | ev.events = events | EPOLLET; 31 | } 32 | else 33 | { 34 | ev.events = events; 35 | } 36 | epoll_ctl(m_epfd, op, fd, &ev); 37 | } 38 | 39 | void EventPoller::create(int max_connections) 40 | { 41 | m_max_connections = max_connections; 42 | m_epfd = epoll_create(max_connections + 1); 43 | if (m_epfd < 0) 44 | { 45 | return; 46 | } 47 | if (m_events != NULL) 48 | { 49 | delete[] m_events; 50 | m_events = NULL; 51 | } 52 | m_events = new epoll_event[max_connections + 1]; 53 | } 54 | 55 | void EventPoller::add(int fd, void * ptr, __uint32_t events) 56 | { 57 | ctrl(fd, ptr, events, EPOLL_CTL_ADD); 58 | } 59 | 60 | void EventPoller::mod(int fd, void * ptr, __uint32_t events) 61 | { 62 | ctrl(fd, ptr, events, EPOLL_CTL_MOD); 63 | } 64 | 65 | void EventPoller::del(int fd, void * ptr, __uint32_t events) 66 | { 67 | ctrl(fd, ptr, events, EPOLL_CTL_DEL); 68 | } 69 | 70 | int EventPoller::wait(int millsecond) 71 | { 72 | return epoll_wait(m_epfd, m_events, m_max_connections + 1, millsecond); 73 | } 74 | -------------------------------------------------------------------------------- /socket/EventPoller.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace yazi { 9 | namespace socket { 10 | 11 | class EventPoller 12 | { 13 | friend class SocketHandler; 14 | 15 | public: 16 | /** 17 | * @brief 构造函数. 18 | * @param et 默认是ET模式 19 | */ 20 | EventPoller(bool et = true); 21 | ~EventPoller(); 22 | 23 | /** 24 | * @brief 生成 epoll句柄. 25 | * @param max_connections epoll服务需要支持的最大连接数 26 | */ 27 | void create(int max_connections); 28 | 29 | /** 30 | * @brief 添加监听句柄. 31 | * @param fd 句柄 32 | * @param ptr 辅助的数据, 可以后续在epoll_event中获取到 33 | * @param event 需要监听的事件EPOLLIN|EPOLLOUT 34 | * 35 | */ 36 | void add(int fd, void * ptr, __uint32_t events); 37 | 38 | /** 39 | * @brief 修改句柄事件. 40 | * @param fd 句柄 41 | * @param ptr 辅助的数据, 可以后续在epoll_event中获取到 42 | * @param event 需要监听的事件EPOLLIN|EPOLLOUT 43 | */ 44 | void mod(int fd, void * ptr, __uint32_t events); 45 | 46 | /** 47 | * @brief 删除句柄事件. 48 | * @param fd 句柄 49 | * @param ptr 辅助的数据, 可以后续在epoll_event中获取到 50 | * @param event 需要监听的事件EPOLLIN|EPOLLOUT 51 | */ 52 | void del(int fd, void * ptr, __uint32_t events); 53 | 54 | /** 55 | * @brief 等待时间. 56 | * @param millsecond 毫秒 57 | * @return int 有事件触发的句柄数 58 | */ 59 | int wait(int millsecond); 60 | 61 | protected: 62 | 63 | /** 64 | * @brief 控制 epoll,将EPOLL设为边缘触发EPOLLET模式 65 | * @param fd 句柄,在create函数时被赋值 66 | * @param ptr 辅助的数据, 可以后续在epoll_event中获取到 67 | * @param events 需要监听的事件 68 | * EPOLLIN 表示对应的文件描述符可以读 69 | * EPOLLOUT 表示对应的文件描述符可以写 70 | * EPOLLPRI 表示对应的文件描述符有紧急的数据可读 71 | * EPOLLERR 表示对应的文件描述符发生错误 72 | * EPOLLHUP 表示对应的文件描述符被挂断 73 | * EPOLLET 表示对应的文件描述符有事件发生 74 | * @param op 控制 epoll 文件描述符上的事件:注册、修改、删除 75 | * EPOLL_CTL_ADD:注册新的fd到epfd中 76 | * EPOLL_CTL_MOD:修改已经注册的fd的监听事件 77 | * EPOLL_CTL_DEL:从 epfd中删除一个fd; 78 | * 79 | */ 80 | void ctrl(int fd, void * ptr, __uint32_t events, int op); 81 | 82 | protected: 83 | 84 | /** 85 | * epoll 86 | */ 87 | int m_epfd; 88 | 89 | /** 90 | * 最大连接数 91 | */ 92 | int m_max_connections; 93 | 94 | /** 95 | * 事件集 96 | */ 97 | struct epoll_event * m_events; 98 | 99 | /** 100 | * 是否是ET模式 101 | */ 102 | bool m_et; 103 | }; 104 | 105 | }} 106 | -------------------------------------------------------------------------------- /socket/ServerSocket.cpp: -------------------------------------------------------------------------------- 1 | #include "ServerSocket.h" 2 | #include "Logger.h" 3 | 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | using namespace yazi::utility; 9 | using namespace yazi::socket; 10 | 11 | ServerSocket::ServerSocket() : Socket() 12 | { 13 | } 14 | 15 | ServerSocket::ServerSocket(const string &ip, int port) : Socket(ip, port) 16 | { 17 | m_sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 18 | if (m_sockfd < 0) 19 | { 20 | error("create server socket error: errno=%d errstr=%s", errno, strerror(errno)); 21 | return; 22 | } 23 | 24 | set_non_blocking(); 25 | set_recv_buffer(10 * 1024); 26 | set_send_buffer(10 * 1024); 27 | set_linger(true, 0); 28 | set_keep_alive(); 29 | set_reuse_addr(); 30 | bind(ip, port); 31 | listen(1024); 32 | } 33 | 34 | ServerSocket::~ServerSocket() 35 | { 36 | close(); 37 | } 38 | -------------------------------------------------------------------------------- /socket/ServerSocket.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | using namespace std; 5 | 6 | #include "Socket.h" 7 | 8 | namespace yazi { 9 | namespace socket { 10 | 11 | class ServerSocket : public Socket 12 | { 13 | public: 14 | ServerSocket(); 15 | ServerSocket(const string &ip, int port); 16 | virtual ~ServerSocket(); 17 | }; 18 | 19 | }} 20 | -------------------------------------------------------------------------------- /socket/Socket.cpp: -------------------------------------------------------------------------------- 1 | #include "Socket.h" 2 | #include "Logger.h" 3 | 4 | using namespace yazi::utility; 5 | using namespace yazi::socket; 6 | 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | Socket::Socket() : m_sockfd(0) 13 | { 14 | } 15 | 16 | Socket::Socket(const string &ip, int port) : m_ip(ip), m_port(port), m_sockfd(0) 17 | { 18 | } 19 | 20 | Socket::~Socket() 21 | { 22 | close(); 23 | } 24 | 25 | bool Socket::bind(const string &ip, int port) 26 | { 27 | struct sockaddr_in sockaddr; 28 | memset(&sockaddr, 0, sizeof(sockaddr)); 29 | sockaddr.sin_family = AF_INET; 30 | if (ip != "") 31 | { 32 | sockaddr.sin_addr.s_addr = inet_addr(ip.c_str()); 33 | } 34 | else 35 | { 36 | sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); 37 | } 38 | sockaddr.sin_port = htons(port); 39 | 40 | if (::bind(m_sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) 41 | { 42 | error("socket bind error: errno=%d errstr=%s", errno, strerror(errno)); 43 | return false; 44 | } 45 | return true; 46 | } 47 | 48 | bool Socket::listen(int backlog) 49 | { 50 | if (::listen(m_sockfd, backlog) < 0) 51 | { 52 | error("socket listen error: errno=%d errstr=%s", errno, strerror(errno)); 53 | return false; 54 | } 55 | return true; 56 | } 57 | 58 | bool Socket::connect(const string &ip, int port) 59 | { 60 | struct sockaddr_in sockaddr; 61 | memset(&sockaddr, 0, sizeof(sockaddr)); 62 | sockaddr.sin_family = AF_INET; 63 | sockaddr.sin_addr.s_addr = inet_addr(ip.c_str()); 64 | sockaddr.sin_port = htons(port); 65 | if (::connect(m_sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) 66 | { 67 | error("socket connect error: errno=%d errstr=%s", errno, strerror(errno)); 68 | return false; 69 | } 70 | return true; 71 | } 72 | 73 | bool Socket::close() 74 | { 75 | if (m_sockfd > 0) 76 | { 77 | ::close(m_sockfd); 78 | m_sockfd = 0; 79 | } 80 | return true; 81 | } 82 | 83 | int Socket::accept() 84 | { 85 | int sockfd = ::accept(m_sockfd, NULL, NULL); 86 | if (sockfd < 0) 87 | { 88 | error("accept call error: errno=%d errstr=%s", errno, strerror(errno)); 89 | sockfd = -1; 90 | } 91 | return sockfd; 92 | } 93 | 94 | int Socket::recv(char * buf, int len) 95 | { 96 | return ::recv(m_sockfd, buf, len, 0); 97 | } 98 | 99 | int Socket::send(const char * buf, int len) 100 | { 101 | return ::send(m_sockfd, buf, len, 0); 102 | } 103 | 104 | bool Socket::set_non_blocking() 105 | { 106 | int flags = fcntl(m_sockfd, F_GETFL, 0); 107 | if (flags < 0) 108 | { 109 | error("Socket::set_non_blocking(F_GETFL, O_NONBLOCK): errno=%d errstr=%s", errno, strerror(errno)); 110 | return false; 111 | } 112 | flags |= O_NONBLOCK; 113 | if (fcntl(m_sockfd, F_SETFL, flags) < 0) 114 | { 115 | error("Socket::set_non_blocking(F_SETFL, O_NONBLOCK): errno=%d errstr=%s", errno, strerror(errno)); 116 | return false; 117 | } 118 | return true; 119 | } 120 | 121 | bool Socket::set_send_buffer(int size) 122 | { 123 | int buff_size = size; 124 | if (setsockopt(m_sockfd, SOL_SOCKET, SO_SNDBUF, &buff_size, sizeof(buff_size)) < 0) 125 | { 126 | error("socket set send buffer error: errno=%d errstr=%s", errno, strerror(errno)); 127 | return false; 128 | } 129 | return true; 130 | } 131 | 132 | bool Socket::set_recv_buffer(int size) 133 | { 134 | int buff_size = size; 135 | if (setsockopt(m_sockfd, SOL_SOCKET, SO_RCVBUF, &buff_size, sizeof(buff_size)) < 0) 136 | { 137 | error("socket set recv buffer error: errno=%d errstr=%s", errno, strerror(errno)); 138 | return false; 139 | } 140 | return true; 141 | } 142 | 143 | bool Socket::set_linger(bool active, int seconds) 144 | { 145 | struct linger l; 146 | memset(&l, 0, sizeof(l)); 147 | 148 | if (active) 149 | l.l_onoff = 1; 150 | else 151 | l.l_onoff = 0; 152 | l.l_linger = seconds; 153 | 154 | if (setsockopt(m_sockfd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) 155 | { 156 | error("socket set sock linger error: errno=%d errstr=%s", errno, strerror(errno)); 157 | return false; 158 | } 159 | return true; 160 | } 161 | 162 | bool Socket::set_keep_alive() 163 | { 164 | int flag = 1; 165 | if (setsockopt(m_sockfd, SOL_SOCKET, SO_KEEPALIVE, &flag, sizeof(flag)) < 0) 166 | { 167 | error("socket set sock keep alive error: errno=%d errstr=%s", errno, strerror(errno)); 168 | return false; 169 | } 170 | return true; 171 | } 172 | 173 | bool Socket::set_reuse_addr() 174 | { 175 | int flag = 1; 176 | if (setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) < 0) 177 | { 178 | error("socket set sock reuser addr error: errno=%s errstr=%s", errno, strerror(errno)); 179 | return false; 180 | } 181 | return true; 182 | } 183 | 184 | bool Socket::set_reuse_port() 185 | { 186 | int flag = 1; 187 | if (setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEPORT, &flag, sizeof(flag)) < 0) 188 | { 189 | error("socket set sock reuser port error: errno=%d errstr=%s", errno, strerror(errno)); 190 | return false; 191 | } 192 | return true; 193 | } 194 | -------------------------------------------------------------------------------- /socket/Socket.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | using namespace std; 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | using namespace std; 14 | 15 | namespace yazi { 16 | namespace socket { 17 | 18 | class Socket 19 | { 20 | friend class SocketHandler; 21 | 22 | public: 23 | Socket(); 24 | Socket(const string &ip, int port); 25 | virtual ~Socket(); 26 | 27 | bool bind(const string &ip, int port); 28 | bool listen(int backlog); 29 | bool connect(const string &ip, int port); 30 | bool close(); 31 | 32 | int accept(); 33 | int recv(char * buf, int len); 34 | int send(const char * buf, int len); 35 | 36 | bool set_non_blocking(); 37 | bool set_send_buffer(int size); 38 | bool set_recv_buffer(int size); 39 | bool set_linger(bool active, int seconds); 40 | bool set_keep_alive(); 41 | bool set_reuse_addr(); 42 | bool set_reuse_port(); 43 | 44 | protected: 45 | string m_ip; 46 | int m_port; 47 | int m_sockfd; 48 | }; 49 | 50 | }} 51 | -------------------------------------------------------------------------------- /socket/SocketHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "SocketHandler.h" 2 | 3 | #include "Logger.h" 4 | #include "IniFile.h" 5 | #include "Singleton.h" 6 | using namespace yazi::utility; 7 | 8 | #include "Task.h" 9 | #include "AutoLock.h" 10 | #include "TaskDispatcher.h" 11 | using namespace yazi::thread; 12 | 13 | #include "ServerSocket.h" 14 | using namespace yazi::socket; 15 | 16 | #include "TaskFactory.h" 17 | using namespace yazi::task; 18 | 19 | SocketHandler::SocketHandler() 20 | { 21 | } 22 | 23 | SocketHandler::~SocketHandler() 24 | { 25 | if (m_epoll != NULL) 26 | { 27 | delete m_epoll; 28 | m_epoll = NULL; 29 | } 30 | if (m_server != NULL) 31 | { 32 | delete m_server; 33 | m_server = NULL; 34 | } 35 | } 36 | 37 | void SocketHandler::listen(const string & ip, int port) 38 | { 39 | m_server = new ServerSocket(ip, port); 40 | } 41 | 42 | void SocketHandler::attach(Socket * socket) 43 | { 44 | AutoLock lock(&m_mutex); 45 | m_epoll->add(socket->m_sockfd, (void *)socket, (EPOLLONESHOT | EPOLLIN | EPOLLHUP | EPOLLERR)); 46 | } 47 | 48 | void SocketHandler::detach(Socket * socket) 49 | { 50 | AutoLock lock(&m_mutex); 51 | m_epoll->del(socket->m_sockfd, (void *)socket, (EPOLLONESHOT | EPOLLIN | EPOLLHUP | EPOLLERR)); 52 | } 53 | 54 | void SocketHandler::remove(Socket * socket) 55 | { 56 | socket->close(); 57 | m_sockpool.release(socket); 58 | } 59 | 60 | void SocketHandler::handle(int max_connections, int wait_time) 61 | { 62 | m_epoll = new EventPoller(false); 63 | m_epoll->create(max_connections); 64 | m_epoll->add(m_server->m_sockfd, m_server, (EPOLLIN | EPOLLHUP | EPOLLERR)); 65 | m_sockpool.init(max_connections); 66 | 67 | debug("epoll wait time: %dms", wait_time); 68 | while (true) 69 | { 70 | int num = m_epoll->wait(wait_time); 71 | if (num == 0) 72 | { 73 | // debug("no events"); 74 | continue; 75 | } 76 | for (int i = 0; i < num; i++) 77 | { 78 | if (m_server == static_cast(m_epoll->m_events[i].data.ptr)) 79 | { 80 | debug("socket accept event"); 81 | int soctfd = m_server->accept(); 82 | Socket * socket = m_sockpool.allocate(); 83 | if (socket == NULL) 84 | { 85 | error("socket pool is empty"); 86 | break; 87 | } 88 | socket->m_sockfd = soctfd; 89 | socket->set_non_blocking(); 90 | attach(socket); 91 | } 92 | else 93 | { 94 | Socket * socket = static_cast(m_epoll->m_events[i].data.ptr); 95 | if (m_epoll->m_events[i].events & EPOLLHUP) 96 | { 97 | error("socket %d closed by peer.", socket->m_sockfd); 98 | detach(socket); 99 | remove(socket); 100 | } 101 | else if (m_epoll->m_events[i].events & EPOLLERR) 102 | { 103 | error("socket %d error.", socket->m_sockfd); 104 | detach(socket); 105 | remove(socket); 106 | } 107 | else if (m_epoll->m_events[i].events & EPOLLIN) 108 | { 109 | debug("socket read event"); 110 | detach(socket); 111 | Task * task = TaskFactory::create(socket); 112 | Singleton::instance()->assign(task); 113 | } 114 | } 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /socket/SocketHandler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | using std::list; 5 | 6 | #include 7 | using std::string; 8 | 9 | #include "Socket.h" 10 | #include "EventPoller.h" 11 | 12 | #include "ObjectPool.h" 13 | using namespace yazi::utility; 14 | 15 | #include "Mutex.h" 16 | #include "Task.h" 17 | using namespace yazi::thread; 18 | 19 | namespace yazi { 20 | namespace socket { 21 | 22 | class SocketHandler 23 | { 24 | public: 25 | SocketHandler(); 26 | ~SocketHandler(); 27 | 28 | void listen(const string & ip, int port); 29 | void attach(Socket * socket); 30 | void detach(Socket * socket); 31 | void remove(Socket * socket); 32 | void handle(int max_connections, int wait_time); 33 | 34 | private: 35 | EventPoller * m_epoll; 36 | Socket * m_server; 37 | ObjectPool m_sockpool; 38 | Mutex m_mutex; 39 | }; 40 | 41 | }} 42 | -------------------------------------------------------------------------------- /task/TaskFactory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Socket.h" 4 | using namespace yazi::socket; 5 | 6 | #include "Task.h" 7 | using namespace yazi::thread; 8 | 9 | #include "WorkTask.h" 10 | using namespace yazi::task; 11 | 12 | namespace yazi { 13 | namespace task { 14 | 15 | class TaskFactory 16 | { 17 | public: 18 | static Task * create(Socket * socket) 19 | { 20 | return new WorkTask(socket); 21 | } 22 | }; 23 | 24 | }} -------------------------------------------------------------------------------- /task/WorkTask.cpp: -------------------------------------------------------------------------------- 1 | #include "WorkTask.h" 2 | using namespace yazi::task; 3 | 4 | #include "Logger.h" 5 | #include "Singleton.h" 6 | using namespace yazi::utility; 7 | 8 | #include "SocketHandler.h" 9 | using namespace yazi::socket; 10 | 11 | #include "Server.h" 12 | using namespace yazi::rpc; 13 | 14 | #include "DataStream.h" 15 | using namespace yazi::serialize; 16 | 17 | #include 18 | using std::ostringstream; 19 | 20 | 21 | WorkTask::WorkTask(Socket * socket) : Task(socket) 22 | { 23 | } 24 | 25 | WorkTask::~WorkTask() 26 | { 27 | } 28 | 29 | void WorkTask::run() 30 | { 31 | debug("work task run"); 32 | SocketHandler * handler = Singleton::instance(); 33 | 34 | Socket * socket = static_cast(m_data); 35 | 36 | MsgHead msg_head; 37 | memset(&msg_head, 0, sizeof(msg_head)); 38 | int len = socket->recv((char *)(&msg_head), sizeof(msg_head)); 39 | if (len == 0) 40 | { 41 | warn("socket closed by peer"); 42 | handler->remove(socket); 43 | return; 44 | } 45 | if (len == -1 && errno == EAGAIN) 46 | { 47 | warn("socket recv len: %d, error msg: EAGAIN errno: %d", len, errno); 48 | handler->attach(socket); 49 | return; 50 | } 51 | if (len == -1 && errno == EWOULDBLOCK) 52 | { 53 | warn("socket recv len: %d, error msg: EWOULDBLOCK errno: %d", len, errno); 54 | handler->attach(socket); 55 | return; 56 | } 57 | if (len == -1 && errno == EINTR) 58 | { 59 | warn("socket recv len: %d, error msg: EINTR errno: %d", len, errno); 60 | handler->attach(socket); 61 | return; 62 | } 63 | if (len != sizeof(msg_head)) 64 | { 65 | error("recv msg head error length: %d, errno: %d", len, errno); 66 | handler->remove(socket); 67 | return; 68 | } 69 | info("recv msg head len: %d, flag: %s, cmd: %d, body len: %d", len, msg_head.flag, msg_head.cmd, msg_head.len); 70 | if (strncmp(msg_head.flag, "work", 4) != 0) 71 | { 72 | error("msg head flag error"); 73 | handler->remove(socket); 74 | return; 75 | } 76 | 77 | if (msg_head.len >= uint32_t(recv_buff_size)) 78 | { 79 | error("recv msg body len: %d, large than recv_buff_size: %d", msg_head.len, recv_buff_size); 80 | handler->remove(socket); 81 | return; 82 | } 83 | 84 | char buf[recv_buff_size]; 85 | memset(buf, 0, recv_buff_size); 86 | len = socket->recv(buf, msg_head.len); 87 | if (len == -1 && errno == EAGAIN) 88 | { 89 | warn("socket recv len: %d, error msg: EAGAIN errno: %d", len, errno); 90 | handler->remove(socket); 91 | return; 92 | } 93 | if (len == -1 && errno == EWOULDBLOCK) 94 | { 95 | warn("socket recv len: %d, error msg: EWOULDBLOCK errno: %d", len, errno); 96 | handler->remove(socket); 97 | return; 98 | } 99 | if (len == -1 && errno == EINTR) 100 | { 101 | warn("socket recv len: %d, error msg: EINTR errno: %d", len, errno); 102 | handler->remove(socket); 103 | return; 104 | } 105 | if (len != (int)(msg_head.len)) 106 | { 107 | error("recv msg body error length: %d, body: %s, errno: %d", len, buf, errno); 108 | handler->remove(socket); 109 | return; 110 | } 111 | 112 | info("recv msg body len: %d, msg data: %s", len, buf); 113 | 114 | DataStream in; 115 | in.write(buf, len); 116 | 117 | string func; 118 | in >> func; 119 | 120 | DataStream out; 121 | Server * server = Singleton::instance(); 122 | server->call(func, in, out); 123 | socket->send(out.data(), out.size()); 124 | handler->attach(socket); 125 | } 126 | 127 | void WorkTask::destroy() 128 | { 129 | debug("work task destory"); 130 | delete this; 131 | } 132 | -------------------------------------------------------------------------------- /task/WorkTask.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Task.h" 4 | using namespace yazi::thread; 5 | 6 | #include "Socket.h" 7 | using namespace yazi::socket; 8 | 9 | namespace yazi { 10 | namespace task { 11 | 12 | struct MsgHead { 13 | char flag[8]; 14 | uint32_t cmd; 15 | uint32_t len; 16 | }; 17 | 18 | const uint32_t recv_buff_size = 1024; 19 | 20 | 21 | class WorkTask : public Task 22 | { 23 | public: 24 | WorkTask(Socket * socket); 25 | virtual ~WorkTask(); 26 | 27 | virtual void run(); 28 | virtual void destroy(); 29 | }; 30 | 31 | }} 32 | -------------------------------------------------------------------------------- /thread/AutoLock.cpp: -------------------------------------------------------------------------------- 1 | #include "AutoLock.h" 2 | 3 | using namespace yazi::thread; 4 | 5 | AutoLock::AutoLock(Mutex* mutex) 6 | { 7 | m_mutex = mutex; 8 | m_mutex->lock(); 9 | } 10 | 11 | AutoLock::~AutoLock() 12 | { 13 | m_mutex->unlock(); 14 | } 15 | -------------------------------------------------------------------------------- /thread/AutoLock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Mutex.h" 4 | 5 | namespace yazi { 6 | namespace thread { 7 | 8 | class AutoLock 9 | { 10 | public: 11 | AutoLock(Mutex* mutex); 12 | ~AutoLock(); 13 | 14 | private: 15 | Mutex* m_mutex; 16 | }; 17 | 18 | }} 19 | -------------------------------------------------------------------------------- /thread/Condition.cpp: -------------------------------------------------------------------------------- 1 | #include "Condition.h" 2 | 3 | using namespace yazi::thread; 4 | 5 | Condition::Condition() 6 | { 7 | pthread_cond_init(&m_cond, NULL); 8 | } 9 | 10 | Condition::~Condition() 11 | { 12 | pthread_cond_destroy(&m_cond); 13 | } 14 | 15 | int Condition::wait(Mutex* mutex) 16 | { 17 | return pthread_cond_wait(&m_cond, &(mutex->m_mutex)); 18 | } 19 | 20 | int Condition::signal() 21 | { 22 | return pthread_cond_signal(&m_cond); 23 | } 24 | 25 | int Condition::broadcast() 26 | { 27 | return pthread_cond_broadcast(&m_cond); 28 | } 29 | 30 | 31 | -------------------------------------------------------------------------------- /thread/Condition.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "Mutex.h" 5 | 6 | namespace yazi { 7 | namespace thread { 8 | 9 | class Condition 10 | { 11 | public: 12 | Condition(); 13 | ~Condition(); 14 | 15 | int wait(Mutex* mutex); 16 | int signal(); 17 | int broadcast(); 18 | 19 | protected: 20 | pthread_cond_t m_cond; 21 | //pthread_condattr_t m_attr; 22 | 23 | }; 24 | 25 | }} 26 | -------------------------------------------------------------------------------- /thread/Mutex.cpp: -------------------------------------------------------------------------------- 1 | #include "Mutex.h" 2 | 3 | using namespace yazi::thread; 4 | 5 | Mutex::Mutex() 6 | { 7 | pthread_mutexattr_t attr; 8 | pthread_mutexattr_init(&attr); 9 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); 10 | pthread_mutex_init(&m_mutex, &attr); 11 | pthread_mutexattr_destroy(&attr); 12 | } 13 | 14 | Mutex::~Mutex() 15 | { 16 | pthread_mutex_destroy(&m_mutex); 17 | } 18 | 19 | int Mutex::lock() 20 | { 21 | return pthread_mutex_lock(&m_mutex); 22 | } 23 | 24 | int Mutex::try_lock() 25 | { 26 | return pthread_mutex_trylock(&m_mutex); 27 | } 28 | 29 | int Mutex::unlock() 30 | { 31 | return pthread_mutex_unlock(&m_mutex); 32 | } 33 | 34 | 35 | -------------------------------------------------------------------------------- /thread/Mutex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace yazi { 5 | namespace thread { 6 | 7 | class Mutex 8 | { 9 | friend class Condition; 10 | 11 | public: 12 | Mutex(); 13 | ~Mutex(); 14 | 15 | // lock 16 | int lock(); 17 | 18 | // try to lock 19 | int try_lock(); 20 | 21 | // unlock 22 | int unlock(); 23 | 24 | private: 25 | pthread_mutex_t m_mutex; 26 | }; 27 | 28 | }} 29 | -------------------------------------------------------------------------------- /thread/Task.cpp: -------------------------------------------------------------------------------- 1 | #include "Task.h" 2 | #include "AutoLock.h" 3 | 4 | using namespace yazi::thread; 5 | 6 | Task::Task() : m_data(NULL) 7 | { 8 | } 9 | 10 | Task::Task(void* data) : m_data(data) 11 | { 12 | } 13 | 14 | Task::~Task() 15 | { 16 | } 17 | 18 | void* Task::get_data() 19 | { 20 | AutoLock lock(&m_mutex); 21 | return m_data; 22 | } 23 | 24 | void Task::set_data(void *data) 25 | { 26 | AutoLock lock(&m_mutex); 27 | m_data = data; 28 | } 29 | -------------------------------------------------------------------------------- /thread/Task.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Mutex.h" 3 | 4 | namespace yazi { 5 | namespace thread { 6 | 7 | class Task 8 | { 9 | public: 10 | Task(); 11 | Task(void* data); 12 | virtual ~Task(); 13 | 14 | void* get_data(); 15 | void set_data(void* data); 16 | 17 | virtual void run() = 0; 18 | virtual void destroy() = 0; 19 | 20 | protected: 21 | void* m_data; 22 | Mutex m_mutex; 23 | }; 24 | 25 | }} 26 | -------------------------------------------------------------------------------- /thread/TaskDispatcher.cpp: -------------------------------------------------------------------------------- 1 | #include "TaskDispatcher.h" 2 | #include "Logger.h" 3 | #include "Singleton.h" 4 | 5 | using namespace yazi::utility; 6 | using namespace yazi::thread; 7 | 8 | TaskDispatcher::TaskDispatcher() 9 | { 10 | } 11 | 12 | TaskDispatcher::~TaskDispatcher() 13 | { 14 | } 15 | 16 | void TaskDispatcher::init(int threads) 17 | { 18 | Singleton::instance()->create(threads); 19 | start(); 20 | } 21 | 22 | void TaskDispatcher::assign(Task* task) 23 | { 24 | debug("task dispatcher assign task"); 25 | m_mutex.lock(); 26 | m_tasks.push_back(task); 27 | m_mutex.unlock(); 28 | m_cond.signal(); 29 | } 30 | 31 | void TaskDispatcher::handle(Task* task) 32 | { 33 | debug("task dispatcher handle task"); 34 | ThreadPool * threadpool = Singleton::instance(); 35 | if (threadpool->get_idle_thread_numbers() > 0) 36 | { 37 | threadpool->assign(task); 38 | } 39 | else 40 | { 41 | m_mutex.lock(); 42 | m_tasks.push_front(task); 43 | m_mutex.unlock(); 44 | debug("all threads are busy!"); 45 | } 46 | } 47 | 48 | void TaskDispatcher::run() 49 | { 50 | sigset_t mask; 51 | if (0 != sigfillset(&mask)) 52 | { 53 | error("thread manager sigfillset failed!"); 54 | return; 55 | } 56 | if (0 != pthread_sigmask(SIG_SETMASK, &mask, NULL)) 57 | { 58 | error("thread manager pthread_sigmask failed!"); 59 | return; 60 | } 61 | while (true) 62 | { 63 | //debug("task list: %d", m_actions.size()); 64 | m_mutex.lock(); 65 | while (m_tasks.empty()) 66 | m_cond.wait(&m_mutex); 67 | Task* task = m_tasks.front(); 68 | m_tasks.pop_front(); 69 | m_mutex.unlock(); 70 | handle(task); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /thread/TaskDispatcher.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "Thread.h" 7 | #include "ThreadPool.h" 8 | #include "Task.h" 9 | 10 | 11 | namespace yazi { 12 | namespace thread { 13 | 14 | class TaskDispatcher : public Thread 15 | { 16 | public: 17 | TaskDispatcher(); 18 | ~TaskDispatcher(); 19 | 20 | void init(int threads); 21 | void assign(Task* task); 22 | void handle(Task* task); 23 | virtual void run(); 24 | 25 | protected: 26 | std::list m_tasks; 27 | }; 28 | 29 | }} 30 | -------------------------------------------------------------------------------- /thread/Thread.cpp: -------------------------------------------------------------------------------- 1 | #include "Thread.h" 2 | #include "AutoLock.h" 3 | using namespace yazi::thread; 4 | 5 | Thread::Thread() : m_tid(0), m_task(NULL) 6 | { 7 | } 8 | 9 | Thread::~Thread() 10 | { 11 | } 12 | 13 | void Thread::start() 14 | { 15 | pthread_attr_t attr; 16 | pthread_attr_init(&attr); 17 | pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); 18 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 19 | pthread_create(&m_tid, &attr, thread_func, (void *)this); 20 | pthread_attr_destroy(&attr); 21 | } 22 | 23 | void Thread::stop() 24 | { 25 | pthread_exit(PTHREAD_CANCELED); 26 | } 27 | 28 | void* Thread::thread_func(void* ptr) 29 | { 30 | Thread* thread = (Thread *)ptr; 31 | thread->run(); 32 | return ptr; 33 | } 34 | 35 | void Thread::set_task(Task* task) 36 | { 37 | m_mutex.lock(); 38 | m_task = task; 39 | m_cond.signal(); 40 | m_mutex.unlock(); 41 | } 42 | 43 | Task* Thread::get_task() 44 | { 45 | AutoLock lock(&m_mutex); 46 | return m_task; 47 | } 48 | -------------------------------------------------------------------------------- /thread/Thread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "Mutex.h" 5 | #include "Condition.h" 6 | #include "Task.h" 7 | 8 | namespace yazi { 9 | namespace thread { 10 | 11 | class Thread 12 | { 13 | public: 14 | Thread(); 15 | virtual ~Thread(); 16 | 17 | virtual void run() = 0; 18 | 19 | void start(); 20 | void stop(); 21 | 22 | void set_task(Task* task); 23 | Task* get_task(); 24 | 25 | protected: 26 | static void* thread_func(void* ptr); 27 | 28 | protected: 29 | pthread_t m_tid; 30 | Task* m_task; 31 | Mutex m_mutex; 32 | Condition m_cond; 33 | }; 34 | 35 | }} 36 | -------------------------------------------------------------------------------- /thread/ThreadPool.cpp: -------------------------------------------------------------------------------- 1 | #include "ThreadPool.h" 2 | #include "WorkerThread.h" 3 | #include "Logger.h" 4 | 5 | using namespace yazi::utility; 6 | using namespace yazi::thread; 7 | 8 | ThreadPool::ThreadPool() : m_threads(0) 9 | { 10 | } 11 | 12 | ThreadPool::~ThreadPool() 13 | { 14 | } 15 | 16 | void ThreadPool::create(int threads) 17 | { 18 | AutoLock lock(&m_mutex_idle); 19 | m_threads = threads; 20 | for (int i = 0; i < threads; i++) 21 | { 22 | Thread* thread = new WorkerThread(); 23 | debug("create thread %x", thread); 24 | m_list_idle.insert(thread); 25 | thread->start(); 26 | } 27 | } 28 | 29 | Thread* ThreadPool::get_idle_thread() 30 | { 31 | AutoLock lock(&m_mutex_idle); 32 | while (m_list_idle.size() == 0) 33 | m_cond_idle.wait(&m_mutex_idle); 34 | return *m_list_idle.begin(); 35 | } 36 | 37 | void ThreadPool::move_to_idle_list(Thread *thread) 38 | { 39 | m_mutex_idle.lock(); 40 | m_list_idle.insert(thread); 41 | m_cond_idle.signal(); 42 | m_mutex_idle.unlock(); 43 | 44 | m_mutex_busy.lock(); 45 | std::set::iterator it = m_list_busy.find(thread); 46 | if (it != m_list_busy.end()) 47 | m_list_busy.erase(it); 48 | m_cond_busy.signal(); 49 | m_mutex_busy.unlock(); 50 | } 51 | 52 | void ThreadPool::move_to_busy_list(Thread* thread) 53 | { 54 | m_mutex_busy.lock(); 55 | while (m_list_busy.size() == (size_t)(m_threads)) 56 | m_cond_busy.wait(&m_mutex_busy); 57 | m_list_busy.insert(thread); 58 | m_mutex_busy.unlock(); 59 | 60 | m_mutex_idle.lock(); 61 | std::set::iterator it = m_list_idle.find(thread); 62 | if (it != m_list_idle.end()) 63 | m_list_idle.erase(it); 64 | m_mutex_idle.unlock(); 65 | } 66 | 67 | int ThreadPool::get_idle_thread_numbers() 68 | { 69 | AutoLock lock(&m_mutex_idle); 70 | return m_list_idle.size(); 71 | } 72 | 73 | int ThreadPool::get_busy_thread_numbers() 74 | { 75 | AutoLock lock(&m_mutex_busy); 76 | return m_list_busy.size(); 77 | } 78 | 79 | void ThreadPool::assign(Task *task) 80 | { 81 | if (task == NULL) 82 | { 83 | error("assign a null task to thread pool"); 84 | return; 85 | } 86 | debug("assign a new task: %x to thread pool", task); 87 | 88 | Thread* thread = get_idle_thread(); 89 | if (thread != NULL) 90 | { 91 | move_to_busy_list(thread); 92 | thread->set_task(task); 93 | } 94 | else 95 | { 96 | error("thread is null, assign a task failed"); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /thread/ThreadPool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "Thread.h" 4 | #include "Mutex.h" 5 | #include "AutoLock.h" 6 | #include "Condition.h" 7 | #include "Task.h" 8 | 9 | namespace yazi { 10 | namespace thread { 11 | 12 | 13 | class ThreadPool 14 | { 15 | public: 16 | ThreadPool(); 17 | ~ThreadPool(); 18 | 19 | void create(int threads); 20 | 21 | Thread* get_idle_thread(); 22 | 23 | void move_to_idle_list(Thread* thread); 24 | void move_to_busy_list(Thread* thread); 25 | 26 | int get_idle_thread_numbers(); 27 | int get_busy_thread_numbers(); 28 | 29 | void assign(Task* task); 30 | 31 | private: 32 | int m_threads; 33 | 34 | std::set m_list_idle; 35 | std::set m_list_busy; 36 | 37 | Mutex m_mutex_idle; 38 | Mutex m_mutex_busy; 39 | 40 | Condition m_cond_idle; 41 | Condition m_cond_busy; 42 | }; 43 | 44 | }} 45 | -------------------------------------------------------------------------------- /thread/WorkerThread.cpp: -------------------------------------------------------------------------------- 1 | #include "WorkerThread.h" 2 | 3 | #include "Logger.h" 4 | #include "Singleton.h" 5 | using namespace yazi::utility; 6 | 7 | #include "Task.h" 8 | #include "ThreadPool.h" 9 | using namespace yazi::thread; 10 | 11 | WorkerThread::WorkerThread() : Thread() 12 | { 13 | } 14 | 15 | WorkerThread::~WorkerThread() 16 | { 17 | } 18 | 19 | void WorkerThread::cleanup(void* ptr) 20 | { 21 | info("worker thread cleanup handler: %x", ptr); 22 | } 23 | 24 | void WorkerThread::run() 25 | { 26 | sigset_t mask; 27 | if (0 != sigfillset(&mask)) 28 | { 29 | error("worker thread sigfillset faile!"); 30 | } 31 | if (0 != pthread_sigmask(SIG_SETMASK, &mask, NULL)) 32 | { 33 | error("worker thread pthread_sigmask failed"); 34 | } 35 | pthread_cleanup_push(cleanup, this); 36 | 37 | while (true) 38 | { 39 | // start wait for task 40 | m_mutex.lock(); 41 | while (m_task == NULL) 42 | m_cond.wait(&m_mutex); 43 | m_mutex.unlock(); 44 | // end wait for task 45 | 46 | int rc = 0; 47 | int old_state = 0; 48 | rc = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state); 49 | 50 | m_task->run(); 51 | m_task->destroy(); 52 | m_task = NULL; 53 | 54 | Singleton::instance()->move_to_idle_list(this); 55 | 56 | rc = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_state); 57 | pthread_testcancel(); // cancel-point 58 | } 59 | pthread_cleanup_pop(1); 60 | } 61 | -------------------------------------------------------------------------------- /thread/WorkerThread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "Thread.h" 7 | 8 | namespace yazi { 9 | namespace thread { 10 | 11 | class WorkerThread : public Thread 12 | { 13 | public: 14 | WorkerThread(); 15 | virtual ~WorkerThread(); 16 | 17 | virtual void run(); 18 | 19 | static void cleanup(void* ptr); 20 | }; 21 | 22 | }} 23 | -------------------------------------------------------------------------------- /utility/IniFile.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "IniFile.h" 5 | 6 | using namespace yazi::utility; 7 | 8 | Value::Value() 9 | { 10 | } 11 | 12 | Value::Value(bool value) 13 | { 14 | *this = value; 15 | } 16 | 17 | Value::Value(int value) 18 | { 19 | *this = value; 20 | } 21 | 22 | Value::Value(double value) 23 | { 24 | *this = value; 25 | } 26 | 27 | Value::Value(const string & value) : m_value(value) 28 | { 29 | } 30 | 31 | Value::~Value() 32 | { 33 | } 34 | 35 | Value & Value::operator = (bool value) 36 | { 37 | if (value) 38 | m_value = "true"; 39 | else 40 | m_value = "false"; 41 | return *this; 42 | } 43 | 44 | Value & Value::operator = (int value) 45 | { 46 | ostringstream os; 47 | os << value; 48 | m_value = os.str(); 49 | return *this; 50 | } 51 | 52 | Value & Value::operator = (double value) 53 | { 54 | ostringstream os; 55 | os << value; 56 | m_value = os.str(); 57 | return *this; 58 | } 59 | 60 | Value & Value::operator = (const string & value) 61 | { 62 | m_value = value; 63 | return *this; 64 | } 65 | 66 | Value::operator bool() 67 | { 68 | if (m_value == "true") 69 | return true; 70 | else if (m_value == "false") 71 | return false; 72 | return false; 73 | } 74 | 75 | Value::operator int() 76 | { 77 | return std::atoi(m_value.c_str()); 78 | } 79 | 80 | Value::operator double() 81 | { 82 | return std::atof(m_value.c_str()); 83 | } 84 | 85 | Value::operator string() 86 | { 87 | return m_value; 88 | } 89 | 90 | Value::operator string() const 91 | { 92 | return m_value; 93 | } 94 | 95 | IniFile::IniFile() 96 | { 97 | } 98 | 99 | IniFile::IniFile(const string &filename) 100 | { 101 | load(filename); 102 | } 103 | 104 | IniFile::~IniFile() 105 | { 106 | } 107 | 108 | string IniFile::trim(string s) 109 | { 110 | if (s.empty()) 111 | { 112 | return s; 113 | } 114 | s.erase(0, s.find_first_not_of(" \r\n")); 115 | s.erase(s.find_last_not_of(" \r\n") + 1); 116 | return s; 117 | } 118 | 119 | bool IniFile::load(const string &filename) 120 | { 121 | m_filename = filename; 122 | m_inifile.clear(); 123 | 124 | string name; 125 | string line; 126 | // open the INI file for reading 127 | ifstream fin(filename.c_str()); 128 | if (fin.fail()) 129 | { 130 | printf("loading file failed: %s is not found.\n", m_filename.c_str()); 131 | return false; 132 | } 133 | while (std::getline(fin, line)) 134 | { 135 | line = trim(line); 136 | if ('[' == line[0]) // it is a section 137 | { 138 | int pos = line.find_first_of(']'); 139 | if (-1 != pos) 140 | { 141 | name = trim(line.substr(1, pos - 1)); 142 | m_inifile[name]; 143 | } 144 | } 145 | else if ('#' == line[0]) // it is a comment 146 | { 147 | continue; 148 | } 149 | else // it is the "key=value" line 150 | { 151 | int pos = line.find_first_of('='); 152 | if (pos > 0) 153 | { 154 | //add new key to the last section in the storage 155 | string key = trim(line.substr(0, pos)); 156 | string value = trim(line.substr(pos + 1, line.size() - pos - 1)); 157 | std::map::iterator it = m_inifile.find(name); 158 | if (it == m_inifile.end()) 159 | { 160 | printf("parsing error: section=%s key=%s\n", name.c_str(), key.c_str()); 161 | return false; 162 | } 163 | m_inifile[name][key] = value; 164 | } 165 | } 166 | } 167 | return true; 168 | } 169 | 170 | void IniFile::save(const string &filename) 171 | { 172 | //open the INI file for writing 173 | ofstream fout(filename.c_str()); 174 | std::map::iterator it; 175 | for (it = m_inifile.begin(); it != m_inifile.end(); ++it) 176 | { 177 | //write section line 178 | fout << "[" << it->first << "]" << endl; 179 | for (Section::iterator iter = it->second.begin(); iter != it->second.end(); ++iter) 180 | { 181 | //write "key = value" line 182 | fout << iter->first << " = " << (string)iter->second << endl; 183 | } 184 | fout << endl; 185 | } 186 | } 187 | 188 | void IniFile::show() 189 | { 190 | std::map::iterator it; 191 | for (it = m_inifile.begin(); it != m_inifile.end(); ++it) 192 | { 193 | //write section line 194 | cout << "[" << it->first << "]" << endl; 195 | Section::iterator iter; 196 | for (iter = it->second.begin(); iter != it->second.end(); ++iter) 197 | { 198 | //write "key = value" line 199 | cout << iter->first << " = " << (string)iter->second << endl; 200 | } 201 | cout << endl; 202 | } 203 | } 204 | 205 | void IniFile::clear() 206 | { 207 | m_inifile.clear(); 208 | } 209 | 210 | bool IniFile::has(const string §ion) 211 | { 212 | return (m_inifile.find(section) != m_inifile.end()); 213 | } 214 | 215 | bool IniFile::has(const string §ion, const string& key) 216 | { 217 | std::map::iterator it = m_inifile.find(section); 218 | if (it != m_inifile.end()) 219 | { 220 | return (it->second.find(key) != it->second.end()); 221 | } 222 | return false; 223 | } 224 | 225 | Value & IniFile::get(const string §ion, const string &key) 226 | { 227 | return m_inifile[section][key]; 228 | } 229 | 230 | void IniFile::set(const string §ion, const string &key, bool value) 231 | { 232 | m_inifile[section][key] = value; 233 | } 234 | 235 | void IniFile::set(const string §ion, const string &key, int value) 236 | { 237 | m_inifile[section][key] = value; 238 | } 239 | 240 | void IniFile::set(const string §ion, const string &key, double value) 241 | { 242 | m_inifile[section][key] = value; 243 | } 244 | 245 | void IniFile::set(const string §ion, const string &key, const string &value) 246 | { 247 | m_inifile[section][key] = value; 248 | } 249 | 250 | void IniFile::remove(const string §ion) 251 | { 252 | std::map::iterator it = m_inifile.find(section); 253 | if (it != m_inifile.end()) 254 | m_inifile.erase(it); 255 | } 256 | 257 | void IniFile::remove(const string §ion, const string &key) 258 | { 259 | std::map::iterator it = m_inifile.find(section); 260 | if (it != m_inifile.end()) 261 | { 262 | Section::iterator iter = it->second.find(key); 263 | if (iter != it->second.end()) 264 | it->second.erase(iter); 265 | } 266 | } 267 | 268 | -------------------------------------------------------------------------------- /utility/IniFile.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | #include 9 | using std::ostringstream; 10 | 11 | namespace yazi { 12 | namespace utility { 13 | 14 | class Value 15 | { 16 | public: 17 | Value(); 18 | Value(bool value); 19 | Value(int value); 20 | Value(double value); 21 | Value(const string & value); 22 | ~Value(); 23 | 24 | Value & operator = (bool value); 25 | Value & operator = (int value); 26 | Value & operator = (double value); 27 | Value & operator = (const string & value); 28 | 29 | operator bool(); 30 | operator int(); 31 | operator double(); 32 | operator string(); 33 | operator string() const; 34 | 35 | private: 36 | string m_value; 37 | }; 38 | 39 | class IniFile 40 | { 41 | public: 42 | IniFile(); 43 | IniFile(const string &filename); 44 | ~IniFile(); 45 | 46 | bool load(const string &filename); 47 | void save(const string &filename); 48 | void show(); 49 | void clear(); 50 | 51 | // read values in different formats 52 | Value & get(const string §ion, const string &key); 53 | 54 | // set values in different formats 55 | void set(const string §ion, const string &key, bool value); 56 | void set(const string §ion, const string &key, int value); 57 | void set(const string §ion, const string &key, double value); 58 | void set(const string §ion, const string &key, const string &value); 59 | 60 | bool has(const string §ion); 61 | bool has(const string §ion, const string &key); 62 | 63 | void remove(const string §ion); 64 | void remove(const string §ion, const string &key); 65 | 66 | typedef std::map Section; 67 | Section & operator [] (const string & key) 68 | { 69 | return m_inifile[key]; 70 | } 71 | 72 | private: 73 | string trim(string s); 74 | 75 | private: 76 | string m_filename; 77 | 78 | std::map m_inifile; 79 | }; 80 | 81 | }} 82 | -------------------------------------------------------------------------------- /utility/Logger.cpp: -------------------------------------------------------------------------------- 1 | #include "Logger.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace yazi::utility; 8 | 9 | const char* Logger::s_level[LEVEL_COUNT] = 10 | { 11 | "DEBUG", 12 | "INFO", 13 | "WARN", 14 | "ERROR", 15 | "FATAL" 16 | }; 17 | 18 | Logger *Logger::m_instance = NULL; 19 | 20 | Logger::Logger() : m_max(0), m_len(0), m_level(DEBUG) 21 | { 22 | } 23 | 24 | Logger::~Logger() 25 | { 26 | close(); 27 | } 28 | 29 | Logger* Logger::instance() 30 | { 31 | if (m_instance == NULL) 32 | m_instance = new Logger(); 33 | return m_instance; 34 | } 35 | 36 | void Logger::open(const string &filename) 37 | { 38 | m_filename = filename; 39 | m_fout.open(filename.c_str(), ios::app); 40 | if (m_fout.fail()) 41 | { 42 | throw std::logic_error("open log file failed: " + filename); 43 | } 44 | m_fout.seekp(0, ios::end); 45 | m_len = m_fout.tellp(); 46 | } 47 | 48 | void Logger::close() 49 | { 50 | m_fout.close(); 51 | } 52 | 53 | void Logger::log(Level level, const char* file, int line, const char* format, ...) 54 | { 55 | if (m_level > level) 56 | { 57 | return; 58 | } 59 | 60 | if (m_fout.fail()) 61 | { 62 | throw std::logic_error("open log file failed: " + m_filename); 63 | } 64 | 65 | time_t ticks = time(NULL); 66 | struct tm* ptm = localtime(&ticks); 67 | char timestamp[32]; 68 | memset(timestamp, 0, sizeof(timestamp)); 69 | strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", ptm); 70 | 71 | int len = 0; 72 | const char * fmt = "%s %s %s:%d "; 73 | len = snprintf(NULL, 0, fmt, timestamp, s_level[level], file, line); 74 | if (len > 0) 75 | { 76 | char * buffer = new char[len + 1]; 77 | snprintf(buffer, len + 1, fmt, timestamp, s_level[level], file, line); 78 | buffer[len] = 0; 79 | m_fout << buffer; 80 | delete buffer; 81 | m_len += len; 82 | } 83 | 84 | va_list arg_ptr; 85 | va_start(arg_ptr, format); 86 | len = vsnprintf(NULL, 0, format, arg_ptr); 87 | va_end(arg_ptr); 88 | if (len > 0) 89 | { 90 | char * content = new char[len + 1]; 91 | va_start(arg_ptr, format); 92 | vsnprintf(content, len + 1, format, arg_ptr); 93 | va_end(arg_ptr); 94 | content[len] = 0; 95 | m_fout << content; 96 | delete content; 97 | m_len += len; 98 | } 99 | 100 | m_fout << "\n"; 101 | m_fout.flush(); 102 | 103 | if (m_max > 0 && m_len >= m_max) 104 | { 105 | rotate(); 106 | } 107 | } 108 | 109 | void Logger::max(int bytes) 110 | { 111 | m_max = bytes; 112 | } 113 | 114 | void Logger::level(int level) 115 | { 116 | m_level = level; 117 | } 118 | 119 | void Logger::rotate() 120 | { 121 | close(); 122 | time_t ticks = time(NULL); 123 | struct tm* ptm = localtime(&ticks); 124 | char timestamp[32]; 125 | memset(timestamp, 0, sizeof(timestamp)); 126 | strftime(timestamp, sizeof(timestamp), ".%Y-%m-%d_%H-%M-%S", ptm); 127 | string filename = m_filename + timestamp; 128 | if (rename(m_filename.c_str(), filename.c_str()) != 0) 129 | { 130 | throw std::logic_error("rename log file failed: " + string(strerror(errno))); 131 | } 132 | open(m_filename); 133 | } 134 | 135 | 136 | -------------------------------------------------------------------------------- /utility/Logger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | namespace yazi { 8 | namespace utility { 9 | 10 | #define debug(format, ...) \ 11 | Logger::instance()->log(Logger::DEBUG, __FILE__, __LINE__, format, ##__VA_ARGS__) 12 | 13 | #define info(format, ...) \ 14 | Logger::instance()->log(Logger::INFO, __FILE__, __LINE__, format, ##__VA_ARGS__) 15 | 16 | #define warn(format, ...) \ 17 | Logger::instance()->log(Logger::WARN, __FILE__, __LINE__, format, ##__VA_ARGS__) 18 | 19 | #define error(format, ...) \ 20 | Logger::instance()->log(Logger::ERROR, __FILE__, __LINE__, format, ##__VA_ARGS__) 21 | 22 | #define fatal(format, ...) \ 23 | Logger::instance()->log(Logger::FATAL, __FILE__, __LINE__, format, ##__VA_ARGS__) 24 | 25 | 26 | class Logger 27 | { 28 | public: 29 | enum Level 30 | { 31 | DEBUG = 0, 32 | INFO, 33 | WARN, 34 | ERROR, 35 | FATAL, 36 | LEVEL_COUNT 37 | }; 38 | 39 | static Logger* instance(); 40 | void open(const string &filename); 41 | void close(); 42 | void log(Level level, const char* file, int line, const char* format, ...); 43 | void max(int bytes); 44 | void level(int level); 45 | 46 | private: 47 | Logger(); 48 | ~Logger(); 49 | void rotate(); 50 | 51 | private: 52 | string m_filename; 53 | ofstream m_fout; 54 | int m_max; 55 | int m_len; 56 | int m_level; 57 | static const char* s_level[LEVEL_COUNT]; 58 | static Logger *m_instance; 59 | }; 60 | 61 | }} 62 | -------------------------------------------------------------------------------- /utility/ObjectPool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "Mutex.h" 5 | #include "AutoLock.h" 6 | 7 | using namespace yazi::thread; 8 | 9 | namespace yazi { 10 | namespace utility { 11 | 12 | template 13 | class ObjectPool 14 | { 15 | public: 16 | ObjectPool(); 17 | ~ObjectPool(); 18 | 19 | void init(int max); 20 | T * allocate(); 21 | void release(T * p); 22 | 23 | private: 24 | std::list m_pool; 25 | Mutex m_mutex; 26 | }; 27 | 28 | template 29 | ObjectPool::ObjectPool() 30 | { 31 | } 32 | 33 | template 34 | ObjectPool::~ObjectPool() 35 | { 36 | AutoLock lock(&m_mutex); 37 | for (typename std::list::iterator it = m_pool.begin(); it != m_pool.end(); it++) 38 | { 39 | if ((*it) != NULL) 40 | { 41 | delete (*it); 42 | } 43 | } 44 | m_pool.clear(); 45 | } 46 | 47 | template 48 | void ObjectPool::init(int max) 49 | { 50 | AutoLock lock(&m_mutex); 51 | for (int i = 0; i < max; i++) 52 | { 53 | T * p = new T(); 54 | m_pool.push_back(p); 55 | } 56 | } 57 | 58 | template 59 | T * ObjectPool::allocate() 60 | { 61 | AutoLock lock(&m_mutex); 62 | if (m_pool.size() == 0) 63 | { 64 | return NULL; 65 | } 66 | T * p = m_pool.front(); 67 | m_pool.pop_front(); 68 | return p; 69 | } 70 | 71 | template 72 | void ObjectPool::release(T * p) 73 | { 74 | AutoLock lock(&m_mutex); 75 | m_pool.push_back(p); 76 | } 77 | 78 | }} 79 | -------------------------------------------------------------------------------- /utility/Singleton.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace yazi { 4 | namespace utility { 5 | 6 | template 7 | class Singleton 8 | { 9 | public: 10 | static T * instance() 11 | { 12 | if (m_instance == NULL) 13 | m_instance = new T(); 14 | return m_instance; 15 | } 16 | 17 | private: 18 | Singleton() {} 19 | Singleton(const Singleton &); 20 | Singleton & operator = (const Singleton &); 21 | ~Singleton() {} 22 | 23 | private: 24 | static T * m_instance; 25 | }; 26 | 27 | template 28 | T * Singleton::m_instance = NULL; 29 | 30 | }} 31 | -------------------------------------------------------------------------------- /utility/System.cpp: -------------------------------------------------------------------------------- 1 | #include "System.h" 2 | using namespace yazi::utility; 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "Logger.h" 11 | #include "IniFile.h" 12 | #include "Singleton.h" 13 | using namespace yazi::utility; 14 | 15 | 16 | System::System() 17 | { 18 | } 19 | 20 | System::~System() 21 | { 22 | } 23 | 24 | void System::init() 25 | { 26 | core_dump(); 27 | m_root_path = get_root_path(); 28 | 29 | const string & logdir = m_root_path + "/log"; 30 | DIR * dp = opendir(logdir.c_str()); 31 | if (dp == NULL) 32 | { 33 | mkdir(logdir.c_str(), 0755); 34 | } 35 | else 36 | { 37 | closedir(dp); 38 | } 39 | } 40 | 41 | void System::core_dump() 42 | { 43 | // core dump 44 | struct rlimit x; 45 | int ret = getrlimit(RLIMIT_CORE, &x); 46 | x.rlim_cur = x.rlim_max; 47 | ret = setrlimit(RLIMIT_CORE, &x); 48 | 49 | ret = getrlimit(RLIMIT_DATA, &x); 50 | x.rlim_cur = 768000000; 51 | ret = setrlimit(RLIMIT_DATA, &x); 52 | } 53 | 54 | string System::get_root_path() 55 | { 56 | if (m_root_path != "") 57 | { 58 | return m_root_path; 59 | } 60 | char path[1024]; 61 | memset(path, 0, 1024); 62 | int cnt = readlink("/proc/self/exe", path, 1024); 63 | if (cnt < 0 || cnt >= 1024) 64 | { 65 | return ""; 66 | } 67 | for (int i = cnt; i >= 0; --i) 68 | { 69 | if (path[i] == '/') 70 | { 71 | path[i] = '\0'; 72 | break; 73 | } 74 | } 75 | return string(path); 76 | } 77 | -------------------------------------------------------------------------------- /utility/System.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | using namespace std; 5 | 6 | namespace yazi { 7 | namespace utility { 8 | 9 | class System 10 | { 11 | public: 12 | System(); 13 | ~System(); 14 | 15 | void init(); 16 | string get_root_path(); 17 | 18 | private: 19 | void core_dump(); 20 | 21 | private: 22 | string m_root_path; 23 | }; 24 | 25 | }} 26 | --------------------------------------------------------------------------------