├── RR-Mode ├── conf │ ├── config.ini │ └── log.conf ├── Makefile ├── global_settings.h ├── init_configure.h ├── master_thread.h ├── defines.h ├── init_configure.cc ├── threadSafe_container.h ├── RRMode.cpp ├── utils.h ├── .project ├── socket_wrapper.h ├── worker_threads.h ├── master_thread.cc ├── .cproject ├── worker_threads.cc └── config_file.h ├── test └── echo.py └── README.md /RR-Mode/conf/config.ini: -------------------------------------------------------------------------------- 1 | remote.listen.port=12006 2 | worker.thread.num = 4 3 | client.heartbeat.timeout.s = 1200 4 | -------------------------------------------------------------------------------- /RR-Mode/Makefile: -------------------------------------------------------------------------------- 1 | CXXFLAGS = -O0 -g -Wall -fmessage-length=0 2 | 3 | OBJS = RRMode.o master_thread.o worker_threads.o init_configure.o 4 | 5 | LIBS = 6 | 7 | TARGET = RRMode 8 | 9 | $(TARGET): $(OBJS) 10 | $(CXX) -o $(TARGET) $(OBJS) $(LIBS) -llog4cxx -lboost_system -lboost_filesystem -levent -Wl,-rpath,/usr/local/lib 11 | 12 | all: $(TARGET) 13 | 14 | clean: 15 | rm -f $(OBJS) $(TARGET) 16 | -------------------------------------------------------------------------------- /RR-Mode/global_settings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * global_settings.h 3 | * 4 | * Created on: Mar 12, 2013 5 | * Author: yaowei 6 | */ 7 | 8 | #ifndef GLOBAL_SETTINGS_H_ 9 | #define GLOBAL_SETTINGS_H_ 10 | 11 | class CGlobalSettings 12 | { 13 | public: 14 | int remote_listen_port_; 15 | unsigned int thread_num_; 16 | 17 | int client_heartbeat_timeout_; 18 | }; 19 | 20 | #endif /* GLOBAL_SETTINGS_H_ */ 21 | -------------------------------------------------------------------------------- /test/echo.py: -------------------------------------------------------------------------------- 1 | __author__ = 'yaocoder' 2 | from socket import * 3 | 4 | TOKEN_LENGTH = 5 5 | TOKEN_STR = "12345" 6 | 7 | sfd = socket(AF_INET, SOCK_STREAM) 8 | 9 | ip = '192.168.14.234' 10 | port = 12006 11 | sfd.connect((ip, port)) 12 | 13 | ch = ['yaocoder', 'wht', 'xty', 'zfd'] 14 | for i in ch: 15 | message = TOKEN_STR + 'hello world!' + i + '\r\n' 16 | sfd.send(message) 17 | data = sfd.recv(20) 18 | print 'the data received is ',data 19 | else: 20 | print 'done!' 21 | -------------------------------------------------------------------------------- /RR-Mode/conf/log.conf: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=TRACE, stdout, logfile 2 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 3 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 4 | log4j.appender.stdout.layout.ConversionPattern=%d [%t] %-5p %c - %m%n 5 | 6 | log4j.appender.logfile=org.apache.log4j.RollingFileAppender 7 | log4j.appender.logfile.File=./RRMode.log 8 | log4j.appender.logfile.Append=false 9 | log4j.appender.logfile.MaxFileSize=100KB 10 | log4j.appender.logfile.MaxBackupIndex=10 11 | log4j.appender.logfile.layout=org.apache.log4j.PatternLayout 12 | log4j.appender.logfile.layout.ConversionPattern=%d [%t] %-5p %c - %m%n 13 | -------------------------------------------------------------------------------- /RR-Mode/init_configure.h: -------------------------------------------------------------------------------- 1 | /* 2 | * init_log4cxx.h 3 | * 4 | * Created on: 2012-9-12 5 | * Author: yaowei 6 | */ 7 | 8 | #ifndef INIT_LOG4CXX_H_ 9 | #define INIT_LOG4CXX_H_ 10 | 11 | #include "defines.h" 12 | 13 | class CInitConfig 14 | { 15 | public: 16 | CInitConfig(); 17 | virtual ~CInitConfig(); 18 | 19 | public: 20 | 21 | void InitLog4cxx(std::string project_name); 22 | 23 | bool LoadConfiguration(); 24 | 25 | void SetConfigFilePath(const std::string& config_file_path) 26 | { 27 | config_file_path_ = config_file_path; 28 | } 29 | 30 | private: 31 | 32 | DISALLOW_COPY_AND_ASSIGN(CInitConfig); 33 | std::string config_file_path_; 34 | }; 35 | 36 | #endif /* INIT_LOG4CXX_H_ */ 37 | -------------------------------------------------------------------------------- /RR-Mode/master_thread.h: -------------------------------------------------------------------------------- 1 | /* 2 | * master_thread.h 3 | * 4 | * Created on: Mar 4, 2013 5 | * Author: yaowei 6 | */ 7 | 8 | #ifndef MASTER_THREAD__H_ 9 | #define MASTER_THREAD__H_ 10 | 11 | #include "defines.h" 12 | 13 | class CWorkerThread; 14 | 15 | class CMasterThread 16 | { 17 | public: 18 | CMasterThread(); 19 | virtual ~CMasterThread(); 20 | 21 | public: 22 | 23 | bool InitMasterThread(); 24 | 25 | void Run(); 26 | 27 | private: 28 | 29 | bool CheckLibeventVersion(); 30 | 31 | bool InitRemoteListenSocket(evutil_socket_t& listen_socket); 32 | 33 | static void AccepCb(evutil_socket_t listen_socket, short event, void* arg); 34 | 35 | private: 36 | 37 | struct event_base *main_base_; 38 | evutil_socket_t remote_listen_socket_; 39 | struct event *listen_event_; 40 | 41 | CWorkerThread *worker_thread_ptr_; 42 | }; 43 | 44 | 45 | #endif /* NET_CORE_H_ */ 46 | -------------------------------------------------------------------------------- /RR-Mode/defines.h: -------------------------------------------------------------------------------- 1 | /* 2 | * defines.h 3 | * 4 | * Created on: 2012-9-12 5 | * Author: yaowei 6 | */ 7 | 8 | #ifndef DEFINES_H_ 9 | #define DEFINES_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | using namespace log4cxx; 28 | extern LoggerPtr g_logger; 29 | 30 | #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ 31 | TypeName(const TypeName&); \ 32 | void operator=(const TypeName&) 33 | 34 | 35 | #define CRLF "\r\n" 36 | 37 | #define TOKEN_LENGTH 5 38 | #define TOKEN_STR "12345" 39 | 40 | #endif /* DEFINES_H_ */ 41 | -------------------------------------------------------------------------------- /RR-Mode/init_configure.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Init_log4cxx.cc 3 | * 4 | * Created on: 2012-9-12 5 | * Author: yaowei 6 | */ 7 | 8 | #include "init_configure.h" 9 | #include "config_file.h" 10 | #include "utils.h" 11 | 12 | #define LOG_CON_FILE "/conf/log.conf" 13 | #define CONF_FILE "/conf/config.ini" 14 | 15 | LoggerPtr g_logger; 16 | 17 | 18 | CInitConfig::CInitConfig() 19 | { 20 | } 21 | 22 | CInitConfig::~CInitConfig() 23 | { 24 | } 25 | 26 | void CInitConfig::InitLog4cxx(std::string project_name) 27 | { 28 | PropertyConfigurator::configure(config_file_path_ + LOG_CON_FILE); 29 | g_logger = Logger::getLogger(project_name); 30 | LOG4CXX_INFO(g_logger, "Run..."); 31 | } 32 | 33 | bool CInitConfig::LoadConfiguration() 34 | { 35 | std::locale old_locale = std::locale::global(std::locale("")); 36 | std::string file_path = config_file_path_ + CONF_FILE; 37 | std::ifstream conf_file(file_path.c_str()); 38 | std::locale::global(old_locale); 39 | if (!conf_file) 40 | { 41 | LOG4CXX_ERROR(g_logger, "CInitConfig::LoadConfiguration failed."); 42 | return false; 43 | } 44 | conf_file >> utils::G(); 45 | return true; 46 | } 47 | 48 | 49 | -------------------------------------------------------------------------------- /RR-Mode/threadSafe_container.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | class CThreadSafeList 6 | { 7 | public: 8 | CThreadSafeList() {} 9 | ~CThreadSafeList() 10 | { 11 | if (!list_.empty()) 12 | { 13 | list_.clear(); 14 | } 15 | 16 | } 17 | 18 | void push_back(const T &pt) 19 | { 20 | boost::mutex::scoped_lock oLock(mutex_); 21 | list_.push_back(pt); 22 | } 23 | 24 | bool pop_front(T &pt) 25 | { 26 | boost::mutex::scoped_lock oLock(mutex_); 27 | if (list_.size() > 0) 28 | { 29 | pt = list_.front(); 30 | list_.pop_front(); 31 | return true; 32 | } 33 | 34 | return false; 35 | } 36 | 37 | void earse(T &Object) 38 | { 39 | boost::mutex::scoped_lock oLock(mutex_); 40 | list_.remove(Object); 41 | } 42 | 43 | void clear() 44 | { 45 | boost::mutex::scoped_lock oLock(mutex_); 46 | if (!list_.empty()) 47 | { 48 | list_.clear(); 49 | } 50 | 51 | return; 52 | } 53 | 54 | int size() 55 | { 56 | boost::mutex::scoped_lock oLock(mutex_); 57 | return list_.size(); 58 | } 59 | 60 | bool empty() 61 | { 62 | boost::mutex::scoped_lock oLock(mutex_); 63 | return list_.empty(); 64 | } 65 | 66 | 67 | private: 68 | std::list list_; 69 | boost::mutex mutex_; 70 | }; 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | high Performance Network Server 2 | ============================= 3 | ----- 4 | **目标**: 高性能TCP网络服务器程序 5 | 6 | **简介**: 程序架构采用[master-worker模型](http://yaocoder.blog.51cto.com/2668309/1170944),并利用libevent网络库来实现one loop per thread(一个事件循环一个线程)的IO模型,采用Round-Robin轮询调度模式。 7 | 8 | **运行环境**: 9 | * **支持平台**: x86-64 linux 10 | * **开发语言**: C++ 11 | * **开发平台**: CentOS release 6.3 12 | * **linux内核版本**: 2.6.32-279.el6.x86_64 13 | * **gcc 版本**: 4.4.6 14 | * **[libevent](http://libevent.org/)版本**: 2.0.21 15 | 16 | 17 | **参考文章** 18 | 19 | * [网络编程释疑之:单台服务器上的并发TCP连接数可以有多少](http://yaocoder.blog.51cto.com/2668309/1312821) 20 | 21 | * [网络编程释疑之:TCP半开连接的处理](http://yaocoder.blog.51cto.com/2668309/1309358) 22 | 23 | * [网络编程释疑之:TCP的TIME_WAIT状态在服务器开发中的影响?](http://yaocoder.blog.51cto.com/2668309/1338567) 24 | 25 | * [我的网络开发之旅——socket编程](http://yaocoder.blog.51cto.com/2668309/1556742) 26 | 27 | **将其改造为网关服务实现的一个简单微服务框架** 28 | * 演化开源项目——[simple_microservices_framework](https://github.com/yaocoder/simple_microservices_framework) 29 | :包括一个网关(类似于Nginx,承载前端网络层处理、后端微服务调度等),一个后端应用微服务示例 30 | 31 | **配和客户端库使用** 32 | * 配套开源项目——[RPC_Framework: 基于TCP协议的远程过程调用框架(客户端)](https://github.com/yaocoder/RPC_Framework) 33 | 1. 客户端和服务端均分为业务层,协议层(JSON),网络层(libevent),可以根据自己的业务定制每一层的接口; 34 | 35 | 2. 客户端实现了与服务端的短连接请求,长连接请求,服务端的推送消息; 36 | 37 | 3. 客户端提供跨平台的支持,目前已经经过windows,linux,android,ios的测试; 38 | 39 | -------------------------------------------------------------------------------- /RR-Mode/RRMode.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "defines.h" 3 | #include "config_file.h" 4 | #include "global_settings.h" 5 | #include "master_thread.h" 6 | #include "init_configure.h" 7 | #include "utils.h" 8 | 9 | static void InitConfigure(); 10 | static void SettingsAndPrint(); 11 | static void Run(); 12 | static void SigUsr(int signo); 13 | 14 | int main(void) 15 | { 16 | InitConfigure(); 17 | 18 | SettingsAndPrint(); 19 | 20 | if (signal(SIGUSR1, SigUsr) == SIG_ERR ) 21 | { 22 | LOG4CXX_FATAL(g_logger, "Configure signal failed."); 23 | exit(EXIT_FAILURE); 24 | } 25 | 26 | Run(); 27 | 28 | return EXIT_SUCCESS; 29 | } 30 | 31 | void Run() 32 | { 33 | CMasterThread masterThread; 34 | if(!masterThread.InitMasterThread()) 35 | { 36 | LOG4CXX_FATAL(g_logger, "InitNetCore failed."); 37 | exit(EXIT_FAILURE); 38 | } 39 | 40 | masterThread.Run(); 41 | } 42 | 43 | void SigUsr(int signo) 44 | { 45 | if(signo == SIGUSR1) 46 | { 47 | /* 重新加载应用配置文件(仅仅是连接超时时间),log4cxx日志配置文件*/ 48 | InitConfigure(); 49 | SettingsAndPrint(); 50 | LOG4CXX_INFO(g_logger, "reload configure."); 51 | return; 52 | } 53 | } 54 | 55 | void InitConfigure() 56 | { 57 | CInitConfig initConfObj; 58 | std::string current_path; 59 | if(!utils::GetCurrentPath(current_path)) 60 | { 61 | LOG4CXX_FATAL(g_logger, "GetCurrentPath failed."); 62 | exit(EXIT_FAILURE); 63 | } 64 | initConfObj.SetConfigFilePath(std::string(current_path)); 65 | initConfObj.InitLog4cxx("RRMode"); 66 | if (!initConfObj.LoadConfiguration()) 67 | { 68 | LOG4CXX_FATAL(g_logger, "LoadConfiguration failed."); 69 | exit(EXIT_FAILURE); 70 | } 71 | } 72 | 73 | void SettingsAndPrint() 74 | { 75 | utils::G().remote_listen_port_ = utils::G().read ("remote.listen.port", 12006); 76 | utils::G().thread_num_ = utils::G().read ("worker.thread.num", 4); 77 | utils::G().client_heartbeat_timeout_ = utils::G().read("client.heartbeat.timeout.s", 70); 78 | 79 | LOG4CXX_INFO(g_logger, "******remote.listen.port=" << utils::G().remote_listen_port_ << "******"); 80 | LOG4CXX_INFO(g_logger, "******worker.thread.num =" << utils::G().thread_num_ << "******"); 81 | LOG4CXX_INFO(g_logger, "******client.heartbeat.timeout.s =" << utils::G().client_heartbeat_timeout_ << "******"); 82 | } 83 | -------------------------------------------------------------------------------- /RR-Mode/utils.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @created: 2012/05/16 3 | * 4 | * @file 5 | * 6 | * @author wei yao 7 | * 8 | * @version 1.0 9 | * 10 | * @LICENSE 11 | * 12 | * @brief 通用工具方法 13 | * 14 | */ 15 | #ifndef UTILS_H__ 16 | #define UTILS_H__ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | using namespace std; 28 | 29 | namespace utils 30 | { 31 | 32 | static inline bool GetCurrentPath(std::string& current_path) 33 | { 34 | try 35 | { 36 | boost::filesystem::path path = boost::filesystem::current_path(); 37 | current_path = path.string(); 38 | return true; 39 | } 40 | catch (boost::filesystem::filesystem_error & e) 41 | { 42 | cout << "current_path : " << current_path << ", error description :" << e.what() << endl; 43 | return false; 44 | } 45 | } 46 | 47 | static inline void SplitData(const std::string& str, const std::string& delimiter, std::vector& vec_data) 48 | { 49 | std::string s = str; 50 | size_t pos = 0; 51 | std::string token; 52 | while ((pos = s.find(delimiter)) != std::string::npos) 53 | { 54 | token = s.substr(0, pos); 55 | vec_data.push_back(token); 56 | s.erase(0, pos + delimiter.length()); 57 | } 58 | } 59 | 60 | static inline bool FindCRLF(const std::string& s) 61 | { 62 | if(s.find("\r\n") != std::string::npos) 63 | return true; 64 | else 65 | return false; 66 | } 67 | 68 | static inline std::string int2str(int v) 69 | { 70 | std::stringstream ss; 71 | ss << v; 72 | return ss.str(); 73 | } 74 | 75 | template 76 | class Singleton: private T 77 | { 78 | public: 79 | static T &Instance() 80 | { 81 | static Singleton _instance; 82 | return _instance; 83 | } 84 | private: 85 | Singleton() 86 | { 87 | } 88 | ~Singleton() 89 | { 90 | } 91 | }; 92 | 93 | template 94 | T& G() 95 | { 96 | return Singleton::Instance(); 97 | } 98 | 99 | template inline void SafeDeleteArray(T*& p) 100 | { 101 | if (NULL != p) 102 | { 103 | delete[] p; 104 | p = 0; 105 | } 106 | } 107 | 108 | template inline void SafeDelete(T*& p) 109 | { 110 | if (NULL != p) 111 | { 112 | delete p; 113 | p = 0; 114 | } 115 | } 116 | 117 | } 118 | #endif 119 | -------------------------------------------------------------------------------- /RR-Mode/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | RR-Mode 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | ?name? 14 | 15 | 16 | 17 | org.eclipse.cdt.make.core.append_environment 18 | true 19 | 20 | 21 | org.eclipse.cdt.make.core.autoBuildTarget 22 | all 23 | 24 | 25 | org.eclipse.cdt.make.core.buildArguments 26 | 27 | 28 | 29 | org.eclipse.cdt.make.core.buildCommand 30 | make 31 | 32 | 33 | org.eclipse.cdt.make.core.cleanBuildTarget 34 | clean 35 | 36 | 37 | org.eclipse.cdt.make.core.contents 38 | org.eclipse.cdt.make.core.activeConfigSettings 39 | 40 | 41 | org.eclipse.cdt.make.core.enableAutoBuild 42 | false 43 | 44 | 45 | org.eclipse.cdt.make.core.enableCleanBuild 46 | true 47 | 48 | 49 | org.eclipse.cdt.make.core.enableFullBuild 50 | true 51 | 52 | 53 | org.eclipse.cdt.make.core.fullBuildTarget 54 | all 55 | 56 | 57 | org.eclipse.cdt.make.core.stopOnError 58 | true 59 | 60 | 61 | org.eclipse.cdt.make.core.useDefaultBuildCmd 62 | true 63 | 64 | 65 | 66 | 67 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 68 | full,incremental, 69 | 70 | 71 | 72 | 73 | 74 | org.eclipse.cdt.core.cnature 75 | org.eclipse.cdt.core.ccnature 76 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 77 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 78 | 79 | 80 | -------------------------------------------------------------------------------- /RR-Mode/socket_wrapper.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_WRAPPER_H__ 2 | #define SOCKET_WRAPPER_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | #define BACKLOG 50 13 | 14 | namespace SocketOperate 15 | { 16 | /** 17 | * @brief 设置socket为非阻塞 18 | * @param [in] 19 | * @return If successful true is returned, if not false is returned. 20 | */ 21 | static inline bool SetSocketNoBlock(const int sock_fd) 22 | { 23 | int flags = fcntl(sock_fd, F_GETFL, 0); 24 | 25 | if(-1 == flags) { 26 | return false; 27 | } 28 | 29 | flags |= O_NONBLOCK; 30 | 31 | if(-1 == fcntl(sock_fd, F_SETFL, flags)) { 32 | return false; 33 | } 34 | 35 | return true; 36 | } 37 | 38 | /** 39 | * @brief 关闭socket 40 | * @param [in] 41 | * @return If successful true is returned, if not false is returned. 42 | */ 43 | static inline bool CloseSocket(const int sock_fd) 44 | { 45 | if(sock_fd < 0) 46 | return true; 47 | 48 | if(shutdown(sock_fd, SHUT_WR) < 0) 49 | { 50 | //log 51 | } 52 | 53 | if(close(sock_fd) < 0) 54 | return false; 55 | return true; 56 | } 57 | 58 | static inline bool WriteSfd(const int sfd, const char* buf, const int buf_len) 59 | { 60 | int write_len = 0; 61 | while (write_len < buf_len) 62 | { 63 | int len = 0; 64 | len = write(sfd, buf + write_len, buf_len - write_len); 65 | if (len < 0) 66 | { 67 | if (errno == EINTR) 68 | { 69 | continue; 70 | } 71 | else if (errno == EAGAIN) /* EAGAIN : Resource temporarily unavailable*/ 72 | { 73 | sleep(0.1); 74 | continue; 75 | } 76 | else 77 | { 78 | return false; 79 | } 80 | } 81 | else 82 | { 83 | write_len = write_len + len; 84 | } 85 | } 86 | return true; 87 | } 88 | 89 | /** 90 | * @brief 通过sockaddr_in结构信息得到主机port 91 | * @param [in] 92 | * @return int 主机类型 port 93 | */ 94 | static inline int GetHostPort(const sockaddr_in sock_addr_in) 95 | { 96 | return ntohs(sock_addr_in.sin_port); 97 | } 98 | 99 | /** 100 | * @brief 通过sockaddr_in结构信息得到主机ip 101 | * @param [in] 102 | * @return string 主机类型 ip地址 103 | */ 104 | static inline std::string GetHostAddr(const sockaddr_in* sock_addr_in) 105 | { 106 | char ip_buf[32]; 107 | std::string stradd = ::inet_ntop(AF_INET, &sock_addr_in->sin_addr, ip_buf, sizeof(ip_buf)); 108 | return stradd; 109 | } 110 | 111 | }; 112 | #endif 113 | -------------------------------------------------------------------------------- /RR-Mode/worker_threads.h: -------------------------------------------------------------------------------- 1 | /* 2 | * worker_threads.h 3 | * 4 | * Created on: Mar 4, 2013 5 | * Author: yaowei 6 | */ 7 | 8 | #ifndef WORK_THREAD_H_ 9 | #define WORK_THREAD_H_ 10 | 11 | #include 12 | #include 13 | #include "defines.h" 14 | #include "threadSafe_container.h" 15 | 16 | #define DATA_BUFFER_SIZE 2048 17 | 18 | typedef struct 19 | { 20 | char buf[DATA_BUFFER_SIZE]; 21 | unsigned int len; 22 | int sfd; 23 | }LOCAL_REV_DATA; 24 | 25 | typedef struct { 26 | int sfd; 27 | }CONN_INFO; 28 | 29 | typedef struct { 30 | pthread_t thread_id; /* unique ID of this thread */ 31 | struct event_base *base; /* libevent handle this thread uses */ 32 | struct event notify_event; /* listen event for notify pipe */ 33 | int notify_receive_fd; /* receiving end of notify pipe */ 34 | int notify_send_fd; /* sending end of notify pipe */ 35 | CThreadSafeList list_conn; /* queue of new connections to handle */ 36 | } LIBEVENT_THREAD; 37 | 38 | typedef struct{ 39 | int sfd; 40 | char* rBuf; 41 | int rlen; 42 | char* wBuf; 43 | int wlen; 44 | bool isVerify; 45 | LIBEVENT_THREAD *thread; /* Pointer to the thread object serving this connection */ 46 | }CONN; 47 | 48 | 49 | class CWorkerThread 50 | { 51 | public: 52 | CWorkerThread(); 53 | virtual ~CWorkerThread(); 54 | 55 | public: 56 | 57 | bool InitThreads(struct event_base* main_base); 58 | 59 | void DispatchSfdToWorker(int sfd); 60 | 61 | private: 62 | 63 | bool SetupThread(LIBEVENT_THREAD* me); 64 | 65 | static void RegisterThreadInitialized(void); 66 | static void WaitForThreadRegistration(int nthreads); 67 | 68 | static void ReadPipeCb(int fd, short event, void* arg); 69 | static CONN*InitNewConn(const CONN_INFO& conn_info, LIBEVENT_THREAD* libevent_thread_ptr); 70 | 71 | static void CreateWorker(void *(*func)(void *), void *arg); 72 | static void *WorkerLibevent(void *arg); 73 | 74 | static void ClientTcpReadCb(struct bufferevent *bev, void *arg); 75 | static void ClientTcpErrorCb(struct bufferevent *bev, short event, void *arg); 76 | 77 | /* 为了重复利用连接内存资源 */ 78 | static void InitFreeConns(); 79 | static CONN *GetConnFromFreelist(); 80 | static bool AddConnToFreelist(CONN *conn); 81 | static void FreeConn(CONN *conn); 82 | static void CloseConn(CONN *conn, struct bufferevent *bev); 83 | 84 | private: 85 | 86 | std::vector vec_libevent_thread_; 87 | int last_thread_; 88 | 89 | static int init_count_; 90 | static pthread_mutex_t init_lock_; 91 | static pthread_cond_t init_cond_; 92 | 93 | static boost::mutex mutex_; 94 | static std::vector vec_freeconn_; 95 | static int freetotal_; 96 | static int freecurr_; 97 | 98 | }; 99 | 100 | #endif /* CTHREAD_H_ */ 101 | -------------------------------------------------------------------------------- /RR-Mode/master_thread.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * net_core.cc 3 | * 4 | * Created on: Mar 4, 2013 5 | * Author: yaowei 6 | */ 7 | 8 | #include "master_thread.h" 9 | #include "global_settings.h" 10 | #include "utils.h" 11 | #include "worker_threads.h" 12 | #include "socket_wrapper.h" 13 | 14 | CMasterThread::CMasterThread() 15 | { 16 | main_base_ = NULL; 17 | listen_event_ = NULL; 18 | remote_listen_socket_ = 0; 19 | worker_thread_ptr_ = new CWorkerThread; 20 | } 21 | 22 | CMasterThread::~CMasterThread() 23 | { 24 | utils::SafeDelete(worker_thread_ptr_); 25 | event_base_free(main_base_); 26 | } 27 | 28 | bool CMasterThread::CheckLibeventVersion() 29 | { 30 | const char* libevent_version = event_get_version(); 31 | assert(libevent_version != NULL); 32 | 33 | LOG4CXX_TRACE(g_logger, "The libevent version is " << libevent_version); 34 | 35 | if (strncmp(libevent_version, "2", 1) == 0) 36 | return true; 37 | else 38 | return false; 39 | } 40 | 41 | bool CMasterThread::InitMasterThread() 42 | { 43 | if(!CheckLibeventVersion()) 44 | { 45 | LOG4CXX_ERROR(g_logger, "CMasterThread::InitMasterThread:The libevent version Require at 2.0.*"); 46 | return false; 47 | } 48 | 49 | main_base_ = event_base_new(); 50 | assert(main_base_ != NULL); 51 | 52 | /* 监听来自客户端的连接 */ 53 | if(!InitRemoteListenSocket(remote_listen_socket_)) 54 | return false; 55 | 56 | evutil_make_socket_nonblocking(remote_listen_socket_); 57 | 58 | listen_event_ = event_new(main_base_, remote_listen_socket_, EV_READ|EV_PERSIST, AccepCb, (void*)this); 59 | assert(listen_event_ != NULL); 60 | 61 | if(event_add(listen_event_, NULL) == -1) 62 | { 63 | int error_code = EVUTIL_SOCKET_ERROR(); 64 | LOG4CXX_ERROR(g_logger, "CMasterThread::InitMasterThread:event_add errorCode = " << error_code 65 | << ", description = " << evutil_socket_error_to_string(error_code)); 66 | return false; 67 | } 68 | 69 | /* 创建worker线程,用来处理来自客户端的连接 */ 70 | if(!worker_thread_ptr_->InitThreads(main_base_)) 71 | return false; 72 | 73 | return true; 74 | } 75 | 76 | void CMasterThread::Run() 77 | { 78 | 79 | LOG4CXX_INFO(g_logger, "CMasterThread::Run:Master thread has start..."); 80 | 81 | int ret = event_base_dispatch(main_base_); 82 | if (-1 == ret) 83 | { 84 | int error_code = EVUTIL_SOCKET_ERROR(); 85 | LOG4CXX_FATAL(g_logger, "CMasterThread::Run():event_base_dispatch errorCode = " << error_code 86 | << ", description = " << evutil_socket_error_to_string(error_code)); 87 | exit(1); 88 | } 89 | else if(1 == ret) 90 | { 91 | LOG4CXX_FATAL(g_logger, "CMasterThread::Run():no events were registered."); 92 | exit(1); 93 | } 94 | } 95 | 96 | void CMasterThread::AccepCb(evutil_socket_t listen_socket, short event, void* arg) 97 | { 98 | CMasterThread* pThis = static_cast(arg); 99 | 100 | evutil_socket_t sfd; 101 | struct sockaddr_in sin; 102 | socklen_t slen = sizeof(sin); 103 | 104 | sfd = accept(listen_socket, (struct sockaddr *) &sin, &slen); 105 | if (-1 == sfd) 106 | { 107 | LOG4CXX_WARN(g_logger, "CMasterThread::AccepCb:accept error = " << strerror(errno)); 108 | return; 109 | } 110 | 111 | 112 | if (!SocketOperate::SetSocketNoBlock(sfd)) 113 | { 114 | LOG4CXX_WARN(g_logger, "CMasterThread::AccepCb:SetSocketNoBlock error = " << strerror(errno)) 115 | close(sfd); 116 | return; 117 | } 118 | 119 | /* 将客户端新连接分发到各个工作线程 */ 120 | pThis->worker_thread_ptr_->DispatchSfdToWorker(sfd); 121 | } 122 | 123 | bool CMasterThread::InitRemoteListenSocket(evutil_socket_t& listen_socket) 124 | { 125 | listen_socket = socket(AF_INET, SOCK_STREAM, 0); 126 | if (listen_socket < 0) 127 | { 128 | LOG4CXX_ERROR(g_logger, "CMasterThread::InitRemoteListenSocket:socket error = " << strerror(errno)); 129 | return false; 130 | } 131 | 132 | int flags = 1; 133 | if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (void *) &flags, sizeof(flags)) != 0) 134 | { 135 | LOG4CXX_ERROR(g_logger, "CMasterThread::InitRemoteListenSocket:setsockopt SO_REUSEADDR error = " << strerror(errno)); 136 | close(listen_socket); 137 | return false; 138 | } 139 | 140 | if (setsockopt(listen_socket, IPPROTO_TCP, TCP_NODELAY, (void *) &flags, sizeof(flags)) != 0) 141 | { 142 | LOG4CXX_ERROR(g_logger, "CMasterThread::InitRemoteListenSocket:setsockopt TCP_NODELAY error = " << strerror(errno)); 143 | close(listen_socket); 144 | return false; 145 | } 146 | 147 | sockaddr_in servaddr; 148 | bzero(&servaddr, sizeof(servaddr)); 149 | servaddr.sin_family = AF_INET; 150 | servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 151 | servaddr.sin_port = htons(utils::G().remote_listen_port_ ); 152 | 153 | if (bind(listen_socket, (const sockaddr*)&servaddr, sizeof(servaddr)) != 0) 154 | { 155 | LOG4CXX_ERROR(g_logger, "CMasterThread::InitRemoteListenSocket:bind error = " << strerror(errno)); 156 | close(listen_socket); 157 | return false; 158 | } 159 | 160 | if(listen(listen_socket, BACKLOG) != 0) 161 | { 162 | LOG4CXX_ERROR(g_logger, "CMasterThread::InitRemoteListenSocket:Listen error = " << strerror(errno)); 163 | close(listen_socket); 164 | return false; 165 | } 166 | 167 | return true; 168 | } 169 | 170 | 171 | -------------------------------------------------------------------------------- /RR-Mode/.cproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /RR-Mode/worker_threads.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * CThread.cc 3 | * 4 | * Created on: Mar 4, 2013 5 | * Author: yaowei 6 | */ 7 | 8 | #include "worker_threads.h" 9 | #include "global_settings.h" 10 | #include "utils.h" 11 | #include "socket_wrapper.h" 12 | 13 | int CWorkerThread::init_count_ = 0; 14 | pthread_mutex_t CWorkerThread::init_lock_ = PTHREAD_MUTEX_INITIALIZER; 15 | pthread_cond_t CWorkerThread::init_cond_ = PTHREAD_COND_INITIALIZER; 16 | 17 | int CWorkerThread::freetotal_ = 0; 18 | int CWorkerThread::freecurr_ = 0; 19 | boost::mutex CWorkerThread::mutex_; 20 | std::vector CWorkerThread::vec_freeconn_; 21 | 22 | 23 | CWorkerThread::CWorkerThread() 24 | { 25 | last_thread_ = -1; 26 | } 27 | 28 | CWorkerThread::~CWorkerThread() 29 | { 30 | } 31 | 32 | /* 初始化worker线程池 */ 33 | bool CWorkerThread::InitThreads(struct event_base* main_base) 34 | { 35 | 36 | InitFreeConns(); 37 | 38 | LOG4CXX_INFO(g_logger, "Initializes worker threads..."); 39 | 40 | for(unsigned int i=0; i().thread_num_; ++i) 41 | { 42 | LIBEVENT_THREAD* libevent_thread_ptr = new LIBEVENT_THREAD; 43 | /* 建立每个worker线程和主监听线程通信的管道 */ 44 | int fds[2]; 45 | if (pipe(fds) != 0) 46 | { 47 | LOG4CXX_ERROR(g_logger, "CThread::InitThreads:Can't create notify pipe"); 48 | return false; 49 | } 50 | libevent_thread_ptr->notify_receive_fd = fds[0]; 51 | libevent_thread_ptr->notify_send_fd = fds[1]; 52 | 53 | if(!SetupThread(libevent_thread_ptr)) 54 | { 55 | utils::SafeDelete(libevent_thread_ptr); 56 | LOG4CXX_ERROR(g_logger, "CThread::InitThreads:SetupThread failed."); 57 | return false; 58 | } 59 | 60 | vec_libevent_thread_.push_back(libevent_thread_ptr); 61 | } 62 | 63 | for (unsigned int i = 0; i < utils::G().thread_num_; i++) 64 | { 65 | CreateWorker(WorkerLibevent, vec_libevent_thread_.at(i)); 66 | } 67 | 68 | /* 等待所有线程都已经启动完毕. */ 69 | WaitForThreadRegistration(utils::G().thread_num_); 70 | 71 | LOG4CXX_INFO(g_logger, "Create threads success. we hava done all the libevent setup."); 72 | 73 | return true; 74 | } 75 | 76 | void CWorkerThread::CreateWorker(void *(*func)(void *), void *arg) 77 | { 78 | pthread_t thread; 79 | pthread_attr_t attr; 80 | int ret; 81 | 82 | pthread_attr_init(&attr); 83 | 84 | if ((ret = pthread_create(&thread, &attr, func, arg)) != 0) 85 | { 86 | LOG4CXX_FATAL(g_logger, "CWorkerThread::CreateWorker:Can't create thread:" << strerror(ret)); 87 | exit(1); 88 | } 89 | } 90 | 91 | 92 | void *CWorkerThread::WorkerLibevent(void *arg) 93 | { 94 | LIBEVENT_THREAD *me = static_cast(arg); 95 | 96 | me->thread_id = pthread_self(); 97 | 98 | RegisterThreadInitialized(); 99 | 100 | event_base_dispatch(me->base); 101 | 102 | return NULL; 103 | } 104 | 105 | bool CWorkerThread::SetupThread(LIBEVENT_THREAD* me) 106 | { 107 | me->base = event_base_new(); 108 | assert(me != NULL); 109 | 110 | /* 通过每个worker线程的读管道监听来自master的通知 */ 111 | me->notify_event = *event_new(me->base, me->notify_receive_fd, EV_READ|EV_PERSIST, ReadPipeCb, (void*)me); 112 | assert(&me->notify_event != NULL); 113 | 114 | if (event_add(&me->notify_event, NULL) == -1) 115 | { 116 | int error_code = EVUTIL_SOCKET_ERROR(); 117 | LOG4CXX_ERROR(g_logger, "CWorkerThread::SetupThread:event_add errorCode = " << error_code 118 | << ", description = " << evutil_socket_error_to_string(error_code)); 119 | return false; 120 | } 121 | 122 | return true; 123 | } 124 | 125 | void CWorkerThread::ReadPipeCb(int fd, short event, void* arg) 126 | { 127 | 128 | LIBEVENT_THREAD *libevent_thread_ptr = static_cast(arg); 129 | assert(libevent_thread_ptr != NULL); 130 | 131 | /* read from master-thread had write, a byte 代表一个客户端连接 */ 132 | char buf[1]; 133 | if (read(fd, buf, 1) != 1) 134 | { 135 | LOG4CXX_ERROR(g_logger, "CWorkerThread::ThreadLibeventProcess:Can't read from libevent pipe."); 136 | return; 137 | } 138 | 139 | /* 将主线程塞到队列中的连接pop出来 */ 140 | CONN_INFO connInfo; 141 | if(!libevent_thread_ptr->list_conn.pop_front(connInfo)) 142 | { 143 | LOG4CXX_ERROR(g_logger, "CWorkerThread::ThreadLibeventProcess:list_conn.pop_front NULL."); 144 | return; 145 | } 146 | 147 | /*初始化新连接,将连接事件注册入libevent */ 148 | if(connInfo.sfd != 0) 149 | { 150 | CONN* conn = InitNewConn(connInfo, libevent_thread_ptr); 151 | if(NULL == conn) 152 | { 153 | LOG4CXX_ERROR(g_logger, "CWorkerThread::ReadPipeCb:Can't listen for events on sfd = " << connInfo.sfd); 154 | close(connInfo.sfd); 155 | } 156 | LOG4CXX_TRACE(g_logger, "CWorkerThread::ReadPipeCb thread id = " << conn->thread->thread_id); 157 | } 158 | } 159 | 160 | CONN* CWorkerThread::InitNewConn(const CONN_INFO& conn_info, LIBEVENT_THREAD* libevent_thread_ptr) 161 | { 162 | CONN* conn = GetConnFromFreelist(); 163 | if (NULL == conn) 164 | { 165 | conn = new CONN; 166 | if (NULL == conn) 167 | { 168 | LOG4CXX_ERROR(g_logger, "CWorkerThread::InitNewConn:new conn error."); 169 | return NULL; 170 | } 171 | 172 | try 173 | { 174 | conn->rBuf = new char[DATA_BUFFER_SIZE]; 175 | conn->wBuf = new char[DATA_BUFFER_SIZE]; 176 | } catch (std::bad_alloc &) 177 | { 178 | FreeConn(conn); 179 | LOG4CXX_ERROR(g_logger, "CWorkerThread::InitNewConn:new buf error."); 180 | return NULL; 181 | } 182 | } 183 | 184 | conn->sfd = conn_info.sfd; 185 | conn->rlen = 0; 186 | conn->wlen = 0; 187 | conn->thread = libevent_thread_ptr; 188 | 189 | /* 将新连接加入此线程libevent事件循环 */ 190 | int flag = EV_READ | EV_PERSIST; 191 | struct bufferevent *client_tcp_event = bufferevent_socket_new(libevent_thread_ptr->base, conn->sfd, BEV_OPT_CLOSE_ON_FREE); 192 | if (NULL == client_tcp_event) 193 | { 194 | if(!AddConnToFreelist(conn)) 195 | { 196 | FreeConn(conn); 197 | } 198 | int error_code = EVUTIL_SOCKET_ERROR(); 199 | LOG4CXX_ERROR(g_logger, 200 | "CWorkerThread::conn_new:bufferevent_socket_new errorCode = " << error_code << ", description = " << evutil_socket_error_to_string(error_code)); 201 | 202 | return NULL; 203 | } 204 | bufferevent_setcb(client_tcp_event, ClientTcpReadCb, NULL, ClientTcpErrorCb, (void*) conn); 205 | 206 | /* 利用客户端心跳超时机制处理半开连接 */ 207 | struct timeval heartbeat_sec; 208 | heartbeat_sec.tv_sec = utils::G().client_heartbeat_timeout_; 209 | heartbeat_sec.tv_usec= 0; 210 | bufferevent_set_timeouts(client_tcp_event, &heartbeat_sec, NULL); 211 | 212 | bufferevent_enable(client_tcp_event, flag); 213 | 214 | return conn; 215 | } 216 | 217 | 218 | void CWorkerThread::ClientTcpReadCb(struct bufferevent *bev, void *arg) 219 | { 220 | CONN* conn = static_cast(arg); 221 | assert(conn != NULL); 222 | 223 | int recv_size = 0; 224 | if ((recv_size = bufferevent_read(bev, conn->rBuf + conn->rlen, DATA_BUFFER_SIZE - conn->rlen)) > 0) 225 | { 226 | conn->rlen = conn->rlen + recv_size; 227 | //防止恶意连接,进行token校验,不满足校验条件的为恶意连接,直接关闭 228 | if (conn->rlen >= TOKEN_LENGTH && conn->isVerify == false) 229 | { 230 | conn->isVerify = true; 231 | std::string str_verify(conn->rBuf, TOKEN_LENGTH); 232 | if (str_verify.compare(std::string(TOKEN_STR)) != 0) 233 | { 234 | LOG4CXX_WARN(g_logger, "CWorkerThread::ClientTcpReadCb DDOS. str = " << str_verify); 235 | CloseConn(conn, bev); 236 | return; 237 | } else 238 | { 239 | conn->rlen = conn->rlen - TOKEN_LENGTH; 240 | memmove(conn->rBuf, conn->rBuf + TOKEN_LENGTH, conn->rlen); 241 | } 242 | } 243 | } 244 | 245 | std::string str_recv(conn->rBuf, conn->rlen); 246 | if (utils::FindCRLF(str_recv)) 247 | { 248 | /* 有可能同时收到多条信息 */ 249 | std::vector vec_str; 250 | utils::SplitData(str_recv, CRLF, vec_str); 251 | 252 | for (unsigned int i = 0; i < vec_str.size(); ++i) 253 | { 254 | if(!SocketOperate::WriteSfd(conn->sfd, vec_str.at(i).c_str(), vec_str.at(i).length())) 255 | { 256 | LOG4CXX_ERROR(g_logger, "CWorkerThread::ClientTcpReadCb:send sfd .error = " << strerror(errno)); 257 | } 258 | } 259 | 260 | int len = str_recv.find_last_of(CRLF) + 1; 261 | memmove(conn->rBuf, conn->rBuf + len, DATA_BUFFER_SIZE - len); 262 | conn->rlen = conn->rlen - len; 263 | } 264 | } 265 | 266 | void CWorkerThread::ClientTcpErrorCb(struct bufferevent *bev, short event, void *arg) 267 | { 268 | CONN* conn = static_cast(arg); 269 | 270 | if (event & BEV_EVENT_TIMEOUT) 271 | { 272 | LOG4CXX_WARN(g_logger, "CWorkerThread::ClientTcpErrorCb:TimeOut."); 273 | } 274 | else if (event & BEV_EVENT_EOF) 275 | { 276 | } 277 | else if (event & BEV_EVENT_ERROR) 278 | { 279 | int error_code = EVUTIL_SOCKET_ERROR(); 280 | LOG4CXX_WARN(g_logger, 281 | "CWorkerThread::ClientTcpErrorCb:some other errorCode = " << error_code << ", description = " << evutil_socket_error_to_string(error_code)); 282 | } 283 | 284 | CloseConn(conn, bev); 285 | } 286 | 287 | void CWorkerThread::DispatchSfdToWorker(int sfd) 288 | { 289 | /* Round Robin*/ 290 | int tid = (last_thread_ + 1) % utils::G().thread_num_; 291 | LIBEVENT_THREAD *libevent_thread_ptr = vec_libevent_thread_.at(tid); 292 | last_thread_ = tid; 293 | 294 | /* 将新连接的加入此worker线程连接队列 */ 295 | CONN_INFO connInfo; 296 | connInfo.sfd = sfd; 297 | libevent_thread_ptr->list_conn.push_back(connInfo); 298 | 299 | /* 通知此worker线程有新连接到来,可以读取了 */ 300 | char buf[1]; 301 | buf[0] = 'c'; 302 | if (write(libevent_thread_ptr->notify_send_fd, buf, 1) != 1) 303 | { 304 | LOG4CXX_WARN(g_logger, "CWorkerThread::DispatchSfdToWorker:Writing to thread notify pipe"); 305 | } 306 | } 307 | 308 | void CWorkerThread::RegisterThreadInitialized(void) 309 | { 310 | pthread_mutex_lock(&init_lock_); 311 | init_count_++; 312 | if(init_count_ == int(utils::G().thread_num_)) 313 | { 314 | pthread_cond_signal(&init_cond_); 315 | } 316 | pthread_mutex_unlock(&init_lock_); 317 | } 318 | 319 | void CWorkerThread::WaitForThreadRegistration(int nthreads) 320 | { 321 | pthread_mutex_lock(&init_lock_); 322 | pthread_cond_wait(&init_cond_, &init_lock_); 323 | pthread_mutex_unlock(&init_lock_); 324 | } 325 | 326 | void CWorkerThread::InitFreeConns() 327 | { 328 | freetotal_ = 200; 329 | freecurr_ = 0; 330 | 331 | vec_freeconn_.resize(freetotal_); 332 | } 333 | 334 | CONN* CWorkerThread::GetConnFromFreelist() 335 | { 336 | CONN *conn = NULL; 337 | 338 | boost::mutex::scoped_lock Lock(mutex_); 339 | if(freecurr_ > 0) 340 | { 341 | conn = vec_freeconn_.at(--freecurr_); 342 | } 343 | 344 | return conn; 345 | } 346 | 347 | bool CWorkerThread::AddConnToFreelist(CONN* conn) 348 | { 349 | bool ret = false; 350 | boost::mutex::scoped_lock Lock(mutex_); 351 | if (freecurr_ < freetotal_) 352 | { 353 | vec_freeconn_.at(freecurr_++) = conn; 354 | ret = true; 355 | } 356 | else 357 | { 358 | /* 增大连接内存池队列 */ 359 | size_t newsize = freetotal_ * 2; 360 | vec_freeconn_.resize(newsize); 361 | freetotal_ = newsize; 362 | vec_freeconn_.at(freecurr_++) = conn; 363 | ret = true; 364 | } 365 | 366 | return ret; 367 | } 368 | 369 | void CWorkerThread::FreeConn(CONN* conn) 370 | { 371 | if (conn) 372 | { 373 | utils::SafeDeleteArray(conn->rBuf); 374 | utils::SafeDeleteArray(conn->wBuf); 375 | utils::SafeDelete (conn); 376 | } 377 | } 378 | 379 | void CWorkerThread::CloseConn(CONN* conn, struct bufferevent* bev) 380 | { 381 | assert(conn != NULL); 382 | 383 | /* 清理资源:the event, the socket and the conn */ 384 | bufferevent_free(bev); 385 | 386 | LOG4CXX_TRACE(g_logger, "CWorkerThread::conn_close sfd = " << conn->sfd); 387 | 388 | /* if the connection has big buffers, just free it */ 389 | if (!AddConnToFreelist (conn)) 390 | { 391 | FreeConn(conn); 392 | } 393 | 394 | return; 395 | } 396 | -------------------------------------------------------------------------------- /RR-Mode/config_file.h: -------------------------------------------------------------------------------- 1 | // ConfigFile.h 2 | // Class for reading named values from configuration files 3 | // Richard J. Wagner v2.1 24 May 2004 wagnerr@umich.edu 4 | 5 | // Copyright (c) 2004 Richard J. Wagner 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to 9 | // deal in the Software without restriction, including without limitation the 10 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 | // sell copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23 | // IN THE SOFTWARE. 24 | 25 | // Typical usage 26 | // ------------- 27 | // 28 | // Given a configuration file "settings.inp": 29 | // atoms = 25 30 | // length = 8.0 # nanometers 31 | // name = Reece Surcher 32 | // 33 | // Named values are read in various ways, with or without default values: 34 | // ConfigFile config( "settings.inp" ); 35 | // int atoms = config.read( "atoms" ); 36 | // double length = config.read( "length", 10.0 ); 37 | // string author, title; 38 | // config.readInto( author, "name" ); 39 | // config.readInto( title, "title", string("Untitled") ); 40 | // 41 | // See file example.cpp for more examples. 42 | 43 | #ifndef SECPLATFORM_COMMON_CONFIGFILE_H 44 | #define SECPLATFORM_COMMON_CONFIGFILE_H 45 | 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | 53 | class ConfigFile { 54 | // Data 55 | protected: 56 | std::string myDelimiter; // separator between key and value 57 | std::string myComment; // separator between value and comments 58 | std::string mySentry; // optional string to signal end of file 59 | std::map myContents; // extracted keys and values 60 | 61 | typedef std::map::iterator mapi; 62 | typedef std::map::const_iterator mapci; 63 | 64 | // Methods 65 | public: 66 | ConfigFile( std::string filename, 67 | std::string delimiter = "=", 68 | std::string comment = "#", 69 | std::string sentry = "EndConfigFile" ) 70 | : myDelimiter(delimiter), myComment(comment), mySentry(sentry) 71 | { 72 | // Construct a ConfigFile, getting keys and values from given file 73 | std::locale old_locale = std::locale::global(std::locale("")); 74 | std::ifstream in( filename.c_str() ); 75 | std::locale::global(old_locale); 76 | 77 | if( !in ) throw file_not_found( filename ); 78 | 79 | in >> (*this); 80 | } 81 | 82 | ConfigFile() 83 | : myDelimiter( std::string(1,'=') ), myComment( std::string(1,'#') ) 84 | { 85 | // Construct a ConfigFile without a file; empty 86 | } 87 | 88 | // Search for key and read value or optional default value 89 | template T read( const std::string& key ) const; // call as read 90 | template T read( const std::string& key, const T& value ) const; 91 | template bool readInto( T& var, const std::string& key ) const; 92 | template 93 | bool readInto( T& var, const std::string& key, const T& value ) const; 94 | 95 | // Modify keys and values 96 | template void add( std::string key, const T& value ); 97 | void remove( const std::string& key ) 98 | { 99 | // Remove key and its value 100 | myContents.erase( myContents.find( key ) ); 101 | return; 102 | } 103 | // Check whether key exists in configuration 104 | bool keyExists( const std::string& key ) const 105 | { 106 | // Indicate whether key is found 107 | mapci p = myContents.find( key ); 108 | return ( p != myContents.end() ); 109 | } 110 | 111 | 112 | // Check or change configuration syntax 113 | std::string getDelimiter() const { return myDelimiter; } 114 | std::string getComment() const { return myComment; } 115 | std::string getSentry() const { return mySentry; } 116 | std::string setDelimiter( const std::string& s ) 117 | { std::string old = myDelimiter; myDelimiter = s; return old; } 118 | std::string setComment( const std::string& s ) 119 | { std::string old = myComment; myComment = s; return old; } 120 | 121 | // Write or read configuration 122 | friend std::ostream& operator<<( std::ostream& os, const ConfigFile& cf ); 123 | friend std::istream& operator>>( std::istream& is, ConfigFile& cf ); 124 | 125 | protected: 126 | template static std::string T_as_string( const T& t ); 127 | template static T string_as_T( const std::string& s ); 128 | static void trim( std::string& s ) 129 | { 130 | // Remove leading and trailing whitespace 131 | static const char whitespace[] = " \n\t\v\r\f"; 132 | s.erase( 0, s.find_first_not_of(whitespace) ); 133 | s.erase( s.find_last_not_of(whitespace) + 1U ); 134 | } 135 | 136 | 137 | // Exception types 138 | public: 139 | struct file_not_found { 140 | std::string filename; 141 | file_not_found( const std::string& filename_ = std::string() ) 142 | : filename(filename_) {} }; 143 | struct key_not_found { // thrown only by T read(key) variant of read() 144 | std::string key; 145 | key_not_found( const std::string& key_ = std::string() ) 146 | : key(key_) {} }; 147 | }; 148 | 149 | 150 | /* static */ 151 | template 152 | std::string ConfigFile::T_as_string( const T& t ) 153 | { 154 | // Convert from a T to a string 155 | // Type T must support << operator 156 | std::ostringstream ost; 157 | ost << t; 158 | return ost.str(); 159 | } 160 | 161 | 162 | /* static */ 163 | template 164 | T ConfigFile::string_as_T( const std::string& s ) 165 | { 166 | // Convert from a string to a T 167 | // Type T must support >> operator 168 | T t; 169 | std::istringstream ist(s); 170 | ist >> t; 171 | return t; 172 | } 173 | 174 | 175 | /* static */ 176 | template<> 177 | inline std::string ConfigFile::string_as_T( const std::string& s ) 178 | { 179 | // Convert from a string to a string 180 | // In other words, do nothing 181 | return s; 182 | } 183 | 184 | 185 | /* static */ 186 | template<> 187 | inline bool ConfigFile::string_as_T( const std::string& s ) 188 | { 189 | // Convert from a string to a bool 190 | // Interpret "false", "F", "no", "n", "0" as false 191 | // Interpret "true", "T", "yes", "y", "1", "-1", or anything else as true 192 | bool b = true; 193 | std::string sup = s; 194 | for( std::string::iterator p = sup.begin(); p != sup.end(); ++p ) 195 | *p = (char)toupper(*p); // make string all caps 196 | if( sup==std::string("FALSE") || sup==std::string("F") || 197 | sup==std::string("NO") || sup==std::string("N") || 198 | sup==std::string("0") || sup==std::string("NONE") ) 199 | b = false; 200 | return b; 201 | } 202 | 203 | 204 | template 205 | T ConfigFile::read( const std::string& key ) const 206 | { 207 | // Read the value corresponding to key 208 | mapci p = myContents.find(key); 209 | if( p == myContents.end() ) throw key_not_found(key); 210 | return string_as_T( p->second ); 211 | } 212 | 213 | 214 | template 215 | T ConfigFile::read( const std::string& key, const T& value ) const 216 | { 217 | // Return the value corresponding to key or given default value 218 | // if key is not found 219 | mapci p = myContents.find(key); 220 | if( p == myContents.end() ) return value; 221 | return string_as_T( p->second ); 222 | } 223 | 224 | 225 | template 226 | bool ConfigFile::readInto( T& var, const std::string& key ) const 227 | { 228 | // Get the value corresponding to key and store in var 229 | // Return true if key is found 230 | // Otherwise leave var untouched 231 | mapci p = myContents.find(key); 232 | bool found = ( p != myContents.end() ); 233 | if( found ) var = string_as_T( p->second ); 234 | return found; 235 | } 236 | 237 | 238 | template 239 | bool ConfigFile::readInto( T& var, const std::string& key, const T& value ) const 240 | { 241 | // Get the value corresponding to key and store in var 242 | // Return true if key is found 243 | // Otherwise set var to given default 244 | mapci p = myContents.find(key); 245 | bool found = ( p != myContents.end() ); 246 | if( found ) 247 | var = string_as_T( p->second ); 248 | else 249 | var = value; 250 | return found; 251 | } 252 | 253 | 254 | template 255 | void ConfigFile::add( std::string key, const T& value ) 256 | { 257 | // Add a key with given value 258 | std::string v = T_as_string( value ); 259 | trim(key); 260 | trim(v); 261 | myContents[key] = v; 262 | return; 263 | } 264 | 265 | 266 | inline std::ostream& operator<<( std::ostream& os, const ConfigFile& cf ) 267 | { 268 | // Save a ConfigFile to os 269 | for( ConfigFile::mapci p = cf.myContents.begin(); 270 | p != cf.myContents.end(); 271 | ++p ) 272 | { 273 | os << p->first << " " << cf.myDelimiter << " "; 274 | os << p->second << std::endl; 275 | } 276 | return os; 277 | } 278 | 279 | 280 | inline std::istream& operator>>( std::istream& is, ConfigFile& cf ) 281 | { 282 | // Load a ConfigFile from is 283 | // Read in keys and values, keeping internal whitespace 284 | typedef std::string::size_type pos; 285 | const std::string& delim = cf.myDelimiter; // separator 286 | const std::string& comm = cf.myComment; // comment 287 | const std::string& sentry = cf.mySentry; // end of file sentry 288 | const pos skip = delim.length(); // length of separator 289 | 290 | std::string nextline = ""; // might need to read ahead to see where value ends 291 | 292 | while( is || nextline.length() > 0 ) 293 | { 294 | // Read an entire line at a time 295 | std::string line; 296 | if( nextline.length() > 0 ) 297 | { 298 | line = nextline; // we read ahead; use it now 299 | nextline = ""; 300 | } 301 | else 302 | { 303 | std::getline( is, line ); 304 | } 305 | 306 | // Ignore comments 307 | line = line.substr( 0, line.find(comm) ); 308 | 309 | // Check for end of file sentry 310 | if( sentry != "" && line.find(sentry) != std::string::npos ) return is; 311 | 312 | // Parse the line if it contains a delimiter 313 | pos delimPos = line.find( delim ); 314 | if( delimPos < std::string::npos ) 315 | { 316 | // Extract the key 317 | std::string key = line.substr( 0, delimPos ); 318 | line.replace( 0, delimPos+skip, "" ); 319 | 320 | // See if value continues on the next line 321 | // Stop at blank line, next line with a key, end of stream, 322 | // or end of file sentry 323 | bool terminate = false; 324 | while( !terminate && is ) 325 | { 326 | std::getline( is, nextline ); 327 | terminate = true; 328 | 329 | std::string nlcopy = nextline; 330 | ConfigFile::trim(nlcopy); 331 | if( nlcopy == "" ) continue; 332 | 333 | nextline = nextline.substr( 0, nextline.find(comm) ); 334 | if( nextline.find(delim) != std::string::npos ) 335 | continue; 336 | if( sentry != "" && nextline.find(sentry) != std::string::npos ) 337 | continue; 338 | 339 | nlcopy = nextline; 340 | ConfigFile::trim(nlcopy); 341 | if( nlcopy != "" ) line += "\n"; 342 | line += nextline; 343 | terminate = false; 344 | } 345 | 346 | // Store key and value 347 | ConfigFile::trim(key); 348 | ConfigFile::trim(line); 349 | cf.myContents[key] = line; // overwrites if key is repeated 350 | } 351 | } 352 | 353 | return is; 354 | } 355 | 356 | #endif // SECPLATFORM_COMMON_CONFIGFILE_H 357 | 358 | // Release notes: 359 | // v1.0 21 May 1999 360 | // + First release 361 | // + Template read() access only through non-member readConfigFile() 362 | // + ConfigurationFileBool is only built-in helper class 363 | // 364 | // v2.0 3 May 2002 365 | // + Shortened name from ConfigurationFile to ConfigFile 366 | // + Implemented template member functions 367 | // + Changed default comment separator from % to # 368 | // + Enabled reading of multiple-line values 369 | // 370 | // v2.1 24 May 2004 371 | // + Made template specializations inline to avoid compiler-dependent linkage 372 | // + Allowed comments within multiple-line values 373 | // + Enabled blank line termination for multiple-line values 374 | // + Added optional sentry to detect end of configuration file 375 | // + Rewrote messy trimWhitespace() function as elegant trim() 376 | --------------------------------------------------------------------------------