├── client_test ├── Makefile ├── simulation_stb_connect_to_g_net.c ├── simulation_stb_connect_to_g_net.exe ├── simulation_stb_connect_to_g_net.h └── simulation_stb_connect_to_g_net.o └── server ├── .gitignore ├── LICENSE ├── README.md ├── config_info.c ├── config_info.h ├── database_process.c ├── database_process.h ├── epoll_connect.c ├── epoll_connect.h ├── file_operations.c ├── file_operations.h ├── g_net_global.h ├── g_net_update.c ├── g_net_update.h ├── ini.ini ├── log.c ├── log.h ├── makefile.txt ├── sql_pool.c ├── sql_pool.h ├── thread_pool.c ├── thread_pool.h └── thread_pool_global.h /client_test/Makefile: -------------------------------------------------------------------------------- 1 | # ======================================================================================== 2 | # Makefile for Client test 3 | # ======================================================================================== 4 | 5 | 6 | # ======================================================================================== 7 | # Set include directories. 8 | INCLUDEDIR = /usr/local/include 9 | 10 | # ======================================================================================== 11 | # Compile flags 12 | CPPFLAGS = 13 | CC=gcc 14 | #compile 15 | # ======================================================================================== 16 | # TARGET/Source definitions 17 | SRCDIR = . 18 | TARGET = epoll_client 19 | OBJS = $(TARGET).o 20 | SRC = $(wildcard $(SRCDIR)/*.c) 21 | 22 | # ======================================================================================== 23 | # Make all option. 24 | LDLIBS = 25 | LIBS = -l pthread 26 | 27 | all: $(TARGET) 28 | $(TARGET): $(SRC:.cpp=.o) 29 | $(CC) $(CPPFLAGS) $(LDFLAGS) $^ -o $@ $(LDLIBS) $(LIBS) 30 | 31 | # ======================================================================================== 32 | # Clean all option 33 | 34 | clean: 35 | rm -f $(SRCDIR)*.o $(SRCDIR)*~ $(SRCDIR)fcs $(SRCDIR).depend 36 | rm -f *.o *~ $(TARGET) .depend $(TARGET) 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /client_test/simulation_stb_connect_to_g_net.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leoge0113/epoll-threadpool/bc2cd737f22b3acf73e4a77bd71f49841b6dda12/client_test/simulation_stb_connect_to_g_net.c -------------------------------------------------------------------------------- /client_test/simulation_stb_connect_to_g_net.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leoge0113/epoll-threadpool/bc2cd737f22b3acf73e4a77bd71f49841b6dda12/client_test/simulation_stb_connect_to_g_net.exe -------------------------------------------------------------------------------- /client_test/simulation_stb_connect_to_g_net.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leoge0113/epoll-threadpool/bc2cd737f22b3acf73e4a77bd71f49841b6dda12/client_test/simulation_stb_connect_to_g_net.h -------------------------------------------------------------------------------- /client_test/simulation_stb_connect_to_g_net.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leoge0113/epoll-threadpool/bc2cd737f22b3acf73e4a77bd71f49841b6dda12/client_test/simulation_stb_connect_to_g_net.o -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | 31 | # Debug files 32 | *.dSYM/ 33 | *.su 34 | -------------------------------------------------------------------------------- /server/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 leoge0113 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 | -------------------------------------------------------------------------------- /server/README.md: -------------------------------------------------------------------------------- 1 | # epoll-threadpool 2 | A epoll server,using epoll and thread pool 3 | -------------------------------------------------------------------------------- /server/config_info.c: -------------------------------------------------------------------------------- 1 | /* 2 | * config_info.c 3 | * 4 | * Created on: 2016.11 5 | * Author: Leo 6 | */ 7 | 8 | #include "file_operations.h" 9 | #include "config_info.h" 10 | //Below variable should correspond with structure CONFIG_INFO_KEY_WORD_ID and CONFIG_INFO. 11 | static char *config_file_key_word[MAX_NO_OF_CONFIG_KEY_WORD] = 12 | { 13 | "Version", 14 | "LogLevel", 15 | "MySqlBranchServerAddr", 16 | "MySqlServerPort", 17 | "MySqlDbName", 18 | "MySqlUserName", 19 | "MySqlPassword", 20 | }; 21 | static BOOL parse_config_key_word(char *data, char *key_word) 22 | { 23 | char *p; 24 | int i; 25 | BOOL ret = FALSE; 26 | 27 | p = data; 28 | if (strchr(p, ';') != NULL || strchr(p, '\n') != NULL) 29 | { 30 | i = 0; 31 | while (i < CONFIG_KEY_WORD_BUF_SIZE && p[i] != ';' && p[i] != '\n') 32 | { 33 | key_word[i] = p[i]; 34 | i++; 35 | } 36 | key_word[MIN(i, CONFIG_KEY_WORD_BUF_SIZE-1)] = '\0'; 37 | ret = TRUE; 38 | } 39 | 40 | return ret; 41 | } 42 | 43 | int read_config_info(CONFIG_INFO *config_info) 44 | { 45 | char *config_file_buff = NULL; 46 | char *p = NULL; 47 | int index = 0; 48 | int ret = -1; 49 | char key_word_buf[CONFIG_KEY_WORD_BUF_SIZE] = ""; 50 | 51 | config_file_buff = malloc(INI_FILE_BUF_SIZE); 52 | if (config_file_buff == NULL) 53 | { 54 | printf("[%s %s %d] No enough memory!\n", __FILE__, __FUNCTION__, __LINE__); 55 | return -1; 56 | } 57 | bzero(config_file_buff, INI_FILE_BUF_SIZE); 58 | 59 | if (read_file_to_buff(SERVER_INI_FILE, INI_FILE_BUF_SIZE - 1, config_file_buff) != 0) 60 | { 61 | goto EXIT; 62 | } 63 | 64 | bzero(config_info, sizeof(CONFIG_INFO)); 65 | for (index = 0; index < MAX_NO_OF_CONFIG_KEY_WORD; index++) 66 | { 67 | p = strstr(config_file_buff, config_file_key_word[index]); 68 | if (p == NULL) 69 | { 70 | goto EXIT; 71 | } 72 | 73 | p = strchr(p, '='); 74 | if (p == NULL) 75 | { 76 | goto EXIT; 77 | } 78 | p++; 79 | 80 | /* tab or space */ 81 | while (p[0] == 9 || p[0] == 32) 82 | p++; 83 | 84 | if (!parse_config_key_word(p, key_word_buf)) 85 | { 86 | continue; 87 | } 88 | 89 | switch (index) 90 | { 91 | case CON_VERSION: 92 | snprintf(config_info->version, sizeof(config_info->version), "%s", key_word_buf); 93 | break; 94 | case CON_LOG_LEVEL: 95 | config_info->log_level = atoi(key_word_buf); 96 | break; 97 | case CON_MYSQL_BRANCH_SERVER_ADDR: 98 | snprintf(config_info->mysql_branch_server_addr, MIN(PATH_BUFF_SIZE, CONFIG_KEY_WORD_BUF_SIZE), "%s", key_word_buf); 99 | break; 100 | case CON_MYSQL_SERVER_PORT: 101 | config_info->mysql_server_port = atol(key_word_buf); 102 | break; 103 | case CON_MYSQL_DB_NAME: 104 | snprintf(config_info->mysql_db_name, MIN(sizeof(config_info->mysql_db_name), CONFIG_KEY_WORD_BUF_SIZE), "%s", key_word_buf); 105 | break; 106 | case CON_MYSQL_USER_NAME: 107 | snprintf(config_info->mysql_user_name, MIN(sizeof(config_info->mysql_user_name), CONFIG_KEY_WORD_BUF_SIZE), "%s", key_word_buf); 108 | break; 109 | case CON_MYSQL_PASSWORD: 110 | snprintf(config_info->mysql_password, MIN(sizeof(config_info->mysql_password), CONFIG_KEY_WORD_BUF_SIZE), "%s", key_word_buf); 111 | break; 112 | } 113 | } 114 | ret = 0; 115 | 116 | EXIT: 117 | free(config_file_buff); 118 | return ret; 119 | } 120 | void print_config_info(CONFIG_INFO config_info) 121 | { 122 | printf("[%s %s %d] config_info.version: %s\n", __FILE__, __FUNCTION__, __LINE__, config_info.version); 123 | printf("[%s %s %d] config_info.LogLevel: %d\n", __FILE__, __FUNCTION__, __LINE__, config_info.log_level); 124 | printf("[%s %s %d] config_info.mysql_branch_server_addr: %s\n", __FILE__, __FUNCTION__, __LINE__, config_info.mysql_branch_server_addr); 125 | printf("[%s %s %d] config_info.mysql_server_port: %d\n", __FILE__, __FUNCTION__, __LINE__, config_info.mysql_server_port); 126 | printf("[%s %s %d] config_info.mysql_db_name: %s\n", __FILE__, __FUNCTION__, __LINE__, config_info.mysql_db_name); 127 | printf("[%s %s %d] config_info.mysql_user_name: %s\n", __FILE__, __FUNCTION__, __LINE__, config_info.mysql_user_name); 128 | printf("[%s %s %d] config_info.mysql_password: %s\n", __FILE__, __FUNCTION__, __LINE__, config_info.mysql_password); 129 | } 130 | 131 | -------------------------------------------------------------------------------- /server/config_info.h: -------------------------------------------------------------------------------- 1 | /* 2 | * config_info.h 3 | * 4 | * Created on: 2016/11 5 | * Author: Leo 6 | */ 7 | 8 | #ifndef CONFIG_INFO_H_ 9 | #define CONFIG_INFO_H_ 10 | #include "g_net_global.h" 11 | 12 | #define FILE_NAME_LEN 128 13 | #define SIZE_OF_VERSION_DATA_BUF 64 14 | #define PATH_BUFF_SIZE 128 15 | #define DB_NAME_SIZE 64 16 | #define DB_USER_NAME_SIZE 64 17 | #define DB_PASSWORD_NAME_SIZE 128 18 | 19 | #define CONFIG_KEY_WORD_BUF_SIZE 128 20 | #define INI_FILE_BUF_SIZE (10 * 1024) 21 | 22 | #define SERVER_INI_FILE "ini.ini" 23 | 24 | 25 | enum 26 | { 27 | CON_VERSION, 28 | CON_LOG_LEVEL, 29 | CON_MYSQL_BRANCH_SERVER_ADDR, 30 | CON_MYSQL_SERVER_PORT, 31 | CON_MYSQL_DB_NAME, 32 | CON_MYSQL_USER_NAME, 33 | CON_MYSQL_PASSWORD, 34 | MAX_NO_OF_CONFIG_KEY_WORD, 35 | } CONFIG_INFO_KEY_WORD_ID; //Should correspond with structure CONFIG_INFO. 36 | 37 | typedef struct _CONIFG_INFO 38 | { 39 | char version[32]; 40 | char log_level; 41 | char mysql_branch_server_addr[PATH_BUFF_SIZE]; 42 | unsigned int mysql_server_port; 43 | char mysql_db_name[DB_NAME_SIZE]; 44 | char mysql_user_name[DB_USER_NAME_SIZE]; 45 | char mysql_password[DB_PASSWORD_NAME_SIZE]; 46 | }CONFIG_INFO; //Should correspond with structure CONFIG_INFO_KEY_WORD_ID and CONFIG_INFO. 47 | 48 | int read_config_info(CONFIG_INFO *config_info); 49 | void print_config_info(CONFIG_INFO config_info); 50 | #endif /* _CONIFG_INFO */ 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /server/database_process.c: -------------------------------------------------------------------------------- 1 | /* 2 | * database_process.c 3 | * 4 | * Created on: 11.13 2014 5 | * Author: LEO 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "g_net_global.h" 15 | #include "config_info.h" 16 | #include "log.h" 17 | #include "g_net_update.h" 18 | #include "thread_pool.h" 19 | #include "sql_pool.h" 20 | #include "config_info.h" 21 | #include "database_process.h" 22 | 23 | #define MYSQL_SELECT_UPGRADE_COUNT_STATEMENT "select sw_count from cust_sw_ver where (sw_from & 1) and sw_public = 1 and pid = %d and cid = %d and mid = %d \ 24 | and sw_ver = %d" 25 | #define MYSQL_SELECT_UPGRADE_COUNT_STATEMENT_TEST "select sw_count from cust_sw_ver where (sw_from & 1) and sw_public = 1 and pid = 5 and cid = 20 and mid = 9 \ 26 | and sw_ver = 172" 27 | 28 | // select the upgrade count from database 29 | int get_upgrade_count_from_database () 30 | { 31 | MYSQL_RES *res; 32 | MYSQL_FIELD *fd ; 33 | MYSQL_ROW row ; 34 | SQL_SOCK_NODE *socket_node = NULL; 35 | char log_str_buf[LOG_STR_BUF_LEN]; 36 | int upgrade_count = -1; // -1: mean no find the upgrade count 37 | 38 | socket_node = get_db_connect_from_pool(); 39 | if (NULL == socket_node) 40 | { 41 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "Get socket node error.\n"); 42 | LOG_INFO(LOG_LEVEL_ERROR, log_str_buf); 43 | return upgrade_count; 44 | } 45 | if(mysql_query(&(socket_node->fd), MYSQL_SELECT_UPGRADE_COUNT_STATEMENT_TEST)) 46 | { 47 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "Query failed (%s).\n", mysql_error(&(socket_node->fd))); 48 | LOG_INFO(LOG_LEVEL_ERROR, log_str_buf); 49 | goto EXIT; 50 | } 51 | 52 | if (!(res=mysql_store_result(&(socket_node->fd)))) 53 | { 54 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "Couldn't get result from %s\n", mysql_error(&(socket_node->fd))); 55 | LOG_INFO(LOG_LEVEL_INFO, log_str_buf); 56 | goto EXIT; 57 | } 58 | 59 | if ((row = mysql_fetch_row(res)) != NULL) 60 | { 61 | upgrade_count = atoi(row[0]); 62 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "Get the count success count is %d.\n", upgrade_count); 63 | LOG_INFO(LOG_LEVEL_INFO, log_str_buf); 64 | } 65 | else 66 | { 67 | LOG_INFO(LOG_LEVEL_INFO, "Get the count fail!\n"); 68 | } 69 | mysql_free_result(res); 70 | EXIT: 71 | release_sock_to_sql_pool(socket_node); 72 | return upgrade_count; 73 | } 74 | 75 | 76 | -------------------------------------------------------------------------------- /server/database_process.h: -------------------------------------------------------------------------------- 1 | /* 2 | * database_process.h 3 | * 4 | * Created on: 20161.11 5 | * Author: LEO 6 | */ 7 | 8 | #ifndef DATABASE_PROCESS_H_ 9 | #define DATABASE_PROCESS_H_ 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define ENABLE_DB_POOL 1 17 | 18 | typedef struct 19 | { 20 | BOOL is_mysql_init; // may be when server start cann't connect to database 21 | MYSQL mysql; 22 | MYSQL *mysql_sock; 23 | 24 | } MYSQL_CONNECT_INFO; 25 | 26 | int get_upgrade_count_from_database (); 27 | 28 | 29 | #endif /* DATABASE_PROCESS_H_ */ 30 | -------------------------------------------------------------------------------- /server/epoll_connect.c: -------------------------------------------------------------------------------- 1 | /* 2 | * epoll_connect.c 3 | * 4 | * Created on: 201610 5 | * Author: leo 6 | */ 7 | 8 | #include "log.h" 9 | #include "epoll_connect.h" 10 | 11 | static char log_str_buf[LOG_STR_BUF_LEN]; 12 | static EPOLL_CONNECT epoll_connect_client[MAX_EVENTS]; 13 | 14 | static void lock_event_state(int iEvent, int iLock) 15 | { 16 | int iRet; 17 | 18 | if (iLock) 19 | { 20 | iRet = pthread_mutex_lock(&epoll_connect_client[iEvent].mutex); 21 | } 22 | else 23 | { 24 | iRet = pthread_mutex_unlock(&epoll_connect_client[iEvent].mutex); 25 | } 26 | if (iRet != 0) 27 | { 28 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "Event[%d] mutex Lock[%d]\n", iEvent, iLock); 29 | log_string(LOG_LEVEL_ERROR, log_str_buf); 30 | } 31 | } 32 | 33 | void init_epoll_connect(void) 34 | { 35 | int iIndex; 36 | int iRet; 37 | 38 | memset((char*)epoll_connect_client, 0, sizeof(epoll_connect_client)); 39 | for (iIndex = 0; iIndex < MAX_EVENTS; iIndex++) 40 | { 41 | epoll_connect_client[iIndex].connect_fd = -1; 42 | epoll_connect_client[iIndex].socket_status = 0; 43 | iRet = pthread_mutex_init(&epoll_connect_client[iIndex].mutex, NULL); 44 | if (iRet != 0) 45 | { 46 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "file connection.c Event[%d] mutex init\n", iRet); 47 | log_string(LOG_LEVEL_INFO, log_str_buf); 48 | } 49 | } 50 | } 51 | 52 | int get_epoll_connect_free_event_index(void) 53 | { 54 | int iIndex; 55 | 56 | for (iIndex = 0; iIndex < MAX_EVENTS; iIndex++) 57 | { 58 | if (epoll_connect_client[iIndex].connect_fd == -1) 59 | { 60 | return iIndex; 61 | } 62 | } 63 | return (-1); 64 | } 65 | 66 | void init_epoll_connect_by_index(int iEvent, int iConnectFD, char *uiClientIP) 67 | { 68 | time_t now; 69 | 70 | time(&now); 71 | lock_event_state(iEvent, 1); 72 | epoll_connect_client[iEvent].now = now; 73 | memset(epoll_connect_client[iEvent].client_ip_addr, 0, IP_ADDR_LENGTH); 74 | memcpy(epoll_connect_client[iEvent].client_ip_addr, uiClientIP, IP_ADDR_LENGTH); 75 | epoll_connect_client[iEvent].connect_fd = iConnectFD; 76 | epoll_connect_client[iEvent].socket_status = 1; 77 | lock_event_state(iEvent, 0); 78 | } 79 | 80 | int get_matched_event_index_by_fd(int iConnectFD) 81 | { 82 | int iIndex; 83 | 84 | for (iIndex = 0; iIndex < MAX_EVENTS; iIndex++) 85 | { 86 | if (epoll_connect_client[iIndex].connect_fd == iConnectFD) 87 | { 88 | return iIndex; 89 | } 90 | } 91 | return (-1); 92 | } 93 | 94 | void free_event_by_index(int index) 95 | { 96 | if (index >=0 && index < MAX_EVENTS) 97 | { 98 | lock_event_state(index, 1); 99 | epoll_connect_client[index].connect_fd = -1; 100 | epoll_connect_client[index].socket_status = 0; 101 | lock_event_state(index, 0); 102 | } 103 | } 104 | 105 | int get_fd_by_event_index(int index) 106 | { 107 | if (index >=0 && index < MAX_EVENTS) 108 | { 109 | return epoll_connect_client[index].connect_fd; 110 | } 111 | else 112 | { 113 | return -1; 114 | } 115 | } 116 | 117 | time_t get_event_connect_time_by_index(int index) 118 | { 119 | if (index >=0 && index < MAX_EVENTS) 120 | { 121 | return epoll_connect_client[index].now; 122 | } 123 | else 124 | { 125 | time_t now; 126 | time(&now); 127 | return now; 128 | } 129 | } 130 | 131 | char *get_client_addr_by_index(int index) 132 | { 133 | if (index >=0 && index < MAX_EVENTS) 134 | { 135 | return epoll_connect_client[index].client_ip_addr; 136 | } 137 | else 138 | { 139 | return "0.0.0.0"; 140 | } 141 | } 142 | 143 | -------------------------------------------------------------------------------- /server/epoll_connect.h: -------------------------------------------------------------------------------- 1 | /* 2 | * epoll_connect.h 3 | * 4 | * Created on: 5 | * Author: leo 6 | */ 7 | 8 | #ifndef EPOLL_CONNECT_H_ 9 | #define EPOLL_CONNECT_H_ 10 | #include "g_net_global.h" 11 | #define MAX_FDS 10240 //10240 12 | #define MAX_EVENTS MAX_FDS 13 | #define LISTENQ 4096 14 | #define IP_ADDR_LENGTH 20 15 | 16 | typedef struct _epoll_connect_struct_ 17 | { 18 | int connect_fd; 19 | int socket_status; //0--initial,1--Live,2--need send,3--Need Close 20 | time_t now; 21 | /*********************/ 22 | /*The Client IP address and PORT : TCP*/ 23 | char client_ip_addr[IP_ADDR_LENGTH]; 24 | pthread_mutex_t mutex; 25 | } EPOLL_CONNECT; 26 | 27 | void init_epoll_connect(void); 28 | int get_epoll_connect_free_event_index(void); 29 | int get_matched_event_index_by_fd(int iConnectFD); 30 | void free_event_by_index(int index); 31 | int get_fd_by_event_index(int index); 32 | time_t get_event_connect_time_by_index(int index); 33 | char *get_client_addr_by_index(int index); 34 | 35 | #endif /* EPOLL_CONNECT_H_ */ 36 | -------------------------------------------------------------------------------- /server/file_operations.c: -------------------------------------------------------------------------------- 1 | /* 2 | * file_operations.c 3 | * 4 | * Created on: 2016.11 5 | * Author: Leo 6 | */ 7 | 8 | #include "log.h" 9 | #include "file_operations.h" 10 | 11 | int read_file_to_buff(char *file_path, unsigned long len, char *data) 12 | { 13 | int ret = -1; 14 | FILE *fp = NULL; 15 | int count = -1; 16 | 17 | if ((fp = fopen(file_path, "r")) == NULL) 18 | { 19 | char log_str_buf[LOG_STR_BUF_LEN]; 20 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "[%s %s %d] Can't open %s.\n", __FILE__, __FUNCTION__, __LINE__, file_path); 21 | log_string(LOG_LEVEL_ERROR, log_str_buf); 22 | return -1; 23 | } 24 | 25 | if ((count = fread(data, 1, len, fp)) > 0) 26 | { 27 | ret = 0; 28 | } 29 | 30 | if (fp != NULL) 31 | { 32 | fclose(fp); 33 | } 34 | 35 | return ret; 36 | } 37 | -------------------------------------------------------------------------------- /server/file_operations.h: -------------------------------------------------------------------------------- 1 | /* 2 | * file_operations.h 3 | * 4 | * Created on: 2016.11 5 | * Author: Leo 6 | */ 7 | 8 | #ifndef FILE_OPERATIONS_H_ 9 | #define FILE_OPERATIONS_H_ 10 | #include "g_net_global.h" 11 | 12 | int read_file_to_buff(char *file_path, unsigned long len, char *data); 13 | 14 | 15 | #endif /* FILE_OPERATIONS_H_ */ 16 | -------------------------------------------------------------------------------- /server/g_net_global.h: -------------------------------------------------------------------------------- 1 | /* 2 | * g_net_global.h 3 | * 4 | * Created on: 2016.11 5 | * Author: Leo 6 | */ 7 | 8 | #ifndef G_NET_GLOBAL_H_ 9 | #define G_NET_GLOBAL_H_ 10 | 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include /* offsetof() */ 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include /* statfs() */ 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | #include /* TCP_NODELAY, TCP_CORK */ 38 | #include 39 | #include 40 | #include 41 | 42 | #include /* tzset() */ 43 | #include /* memalign() */ 44 | #include /* IOV_MAX */ 45 | #include 46 | #include 47 | #include 48 | #include /* uname() */ 49 | #include 50 | 51 | #include 52 | #include 53 | #include 54 | 55 | 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | 68 | typedef int BOOL; 69 | 70 | 71 | #ifndef FALSE 72 | #define FALSE (0) 73 | #endif 74 | #ifndef TRUE 75 | #define TRUE (!FALSE) 76 | #endif 77 | 78 | #define MIN(a, b) ((a)<(b)?(a):(b)) 79 | 80 | 81 | #endif /* G_NET_GLOBAL_H_ */ 82 | -------------------------------------------------------------------------------- /server/g_net_update.c: -------------------------------------------------------------------------------- 1 | /* 2 | * g_net_update.c 3 | * 4 | * Created on: 2016.11 5 | * Author: leo 6 | */ 7 | /********************** g_net update version 2.0 ***************************/ 8 | #include "config_info.h" 9 | #include "log.h" 10 | #include "epoll_connect.h" 11 | #include "thread_pool.h" 12 | #include "g_net_update.h" 13 | #include "database_process.h" 14 | 15 | 16 | #define CONNECT_TO_SQL_SUCCESS 0 17 | #define SERVER_TIMEOUT 60 * 1 //60S 18 | 19 | static CONFIG_INFO config_info; 20 | static int epoll_fd = -1; // the epoll fd 21 | static int listen_fd = -1; // the socket fd socket create return 22 | static pthread_t accep_thread_t; 23 | static pthread_t send_thread_t; 24 | 25 | static int current_connected_total = 0; // the connections number 26 | static int exit_accept_flag = 0; // is exit the accept 27 | static int exit_flag = 0; // is exit the epoll wait 28 | static int port = 8111; 29 | 30 | static void closesocket(int fd); 31 | static void dumpInfo(unsigned char *info, int length); 32 | pthread_mutex_t connect_total_count_mutex = PTHREAD_MUTEX_INITIALIZER; 33 | static void connect_total_count_opration(BOOL add_or_subract, int value) 34 | { 35 | pthread_mutex_lock(&connect_total_count_mutex); 36 | if (add_or_subract) 37 | { 38 | current_connected_total = current_connected_total + value; 39 | } 40 | else 41 | { 42 | current_connected_total = current_connected_total - value; 43 | } 44 | pthread_mutex_unlock(&connect_total_count_mutex); 45 | } 46 | 47 | static void signal_handler_reboot(int32_t theSignal) 48 | { 49 | int i; 50 | int sockfd; 51 | char log_str_buf[LOG_STR_BUF_LEN]; 52 | signal(SIGPIPE, SIG_IGN); 53 | if (SIGKILL == theSignal || SIGTERM == theSignal) //we can know when system excute child thread is end 54 | { 55 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "receive kill signal exit the server."); 56 | LOG_INFO(LOG_LEVEL_FATAL, log_str_buf); 57 | if (listen_fd != -1) 58 | { 59 | closesocket(listen_fd); 60 | listen_fd = -1; 61 | } 62 | exit_flag = 1; 63 | exit_accept_flag = 1; 64 | for (i = 0; i < MAX_EVENTS; i++) 65 | { 66 | sockfd = get_fd_by_event_index(i); 67 | if (sockfd != -1) 68 | { 69 | closesocket(sockfd); 70 | } 71 | } 72 | #if CONNECT_TO_SQL_SUCCESS 73 | sql_pool_destroy(); 74 | #endif 75 | } 76 | else if (SIGPIPE == theSignal) 77 | { 78 | LOG_INFO(LOG_LEVEL_INFO, "SIGPIPE received.\n"); 79 | } 80 | } 81 | 82 | static void closesocket(int fd) 83 | { 84 | shutdown(fd, SHUT_RDWR); 85 | close(fd); 86 | } 87 | 88 | static int set_non_blocking(int sock) 89 | { 90 | int opts = -1; 91 | char log_str_buf[LOG_STR_BUF_LEN]; 92 | 93 | opts = fcntl(sock, F_GETFL); 94 | if (opts < 0) 95 | { 96 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "fcntl(sock=%d,GETFL).\n", sock); 97 | LOG_INFO(LOG_LEVEL_ERROR, log_str_buf); 98 | return (-1); 99 | } 100 | opts = opts | O_NONBLOCK; 101 | if (fcntl(sock, F_SETFL, opts) < 0) 102 | { 103 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "fcntl(sock=%d,GETFL).\n", sock); 104 | LOG_INFO(LOG_LEVEL_ERROR, log_str_buf); 105 | return (-1); 106 | } 107 | return 1; 108 | } 109 | 110 | CONFIG_INFO *get_config_info(void) 111 | { 112 | return &config_info; 113 | } 114 | /****************************** accept task ******************************************/ 115 | static void *accept_thread(void *arg) 116 | { 117 | int connect_fd = -1; 118 | socklen_t clilen = 0; 119 | struct sockaddr_in serveraddr; 120 | struct sockaddr_in clientaddr; 121 | struct sockaddr cliaddr; 122 | struct epoll_event ev; 123 | int val = 1; 124 | int err = 0; 125 | int bufsize = 32 * 1024; //1024*2048; 126 | int epoll_connect_event_index = -1; 127 | char log_str_buf[LOG_STR_BUF_LEN] = {0}; 128 | 129 | listen_fd = socket(AF_INET, SOCK_STREAM, 0); 130 | if (-1 == listen_fd) // INVALID_SOCKET 131 | { 132 | LOG_INFO(LOG_LEVEL_ERROR, "create socket error.\n"); 133 | return NULL; 134 | } 135 | //set socket options 136 | err = setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); 137 | if (0 != err) 138 | { 139 | LOG_INFO(LOG_LEVEL_ERROR, "setsockopt SO_REUSEADDR error.\n"); 140 | return NULL; 141 | } 142 | err = setsockopt(listen_fd, SOL_SOCKET, SO_RCVBUF, (char*)(&bufsize), sizeof(int)); 143 | if (0 != err) 144 | { 145 | LOG_INFO(LOG_LEVEL_ERROR, "setsockopt SO_RCVBUF error.\n"); 146 | return NULL; 147 | } 148 | 149 | val = 2; //2 minitues 150 | err = setsockopt(listen_fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &val, sizeof(val)); 151 | if (0 != err) 152 | { 153 | LOG_INFO(LOG_LEVEL_ERROR, "setsockopt TCP_DEFER_ACCEPT error.\n"); 154 | return NULL; 155 | } 156 | 157 | // set_non_blocking(listen_fd); 158 | bzero(&serveraddr, sizeof(serveraddr)); 159 | serveraddr.sin_addr.s_addr = INADDR_ANY; 160 | serveraddr.sin_port = htons(/*config_info.port*/port); //serveraddr.sin_port = htons(SERVER_LISTEN_PORT); 161 | serveraddr.sin_family = AF_INET; 162 | if (-1 == bind(listen_fd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))) // SOCKET_ERROR 163 | { 164 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "bind config port %d error.\n", /*config_info.port*/port); 165 | LOG_INFO(LOG_LEVEL_ERROR, log_str_buf); 166 | printf("bind config port %d error.\n", /*config_info.port*/port); 167 | return NULL; 168 | } 169 | printf("bind config port %d success.\n", /*config_info.port*/port); 170 | 171 | listen(listen_fd, LISTENQ); // 4096 172 | clilen = sizeof(cliaddr); 173 | while (!exit_accept_flag) 174 | { 175 | if (current_connected_total < MAX_EVENTS) // effective 176 | { 177 | if ((connect_fd = accept(listen_fd, (struct sockaddr *)&clientaddr, &clilen)) < 0) 178 | { 179 | if ((errno != EAGAIN) && (errno != ECONNABORTED) && (errno != EPROTO) && (errno != EINTR)) 180 | { 181 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "accept error %d,%s.\n", errno, strerror(errno)); 182 | LOG_INFO(LOG_LEVEL_ERROR, log_str_buf); 183 | } 184 | continue; 185 | } 186 | } 187 | else 188 | { 189 | sleep(1); 190 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "current accept number achieve to maximum(%d) .\n", MAX_EVENTS); 191 | LOG_INFO(LOG_LEVEL_INDISPENSABLE, log_str_buf); 192 | continue; 193 | } 194 | epoll_connect_event_index = get_epoll_connect_free_event_index(); 195 | // no free epoll event 196 | if (epoll_connect_event_index == -1) // no the free connect event 197 | { 198 | LOG_INFO(LOG_LEVEL_ERROR, "Not find free connect.\n"); 199 | if (connect_fd != -1) 200 | { 201 | closesocket(connect_fd); 202 | connect_fd = -1; 203 | } 204 | continue; 205 | } 206 | // set connect fd non blocking 207 | if (set_non_blocking(connect_fd) < 0) 208 | { 209 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "set non-blocking socket = %d error.\n", connect_fd); 210 | LOG_INFO(LOG_LEVEL_ERROR, log_str_buf); 211 | if (connect_fd != -1) 212 | { 213 | closesocket(connect_fd); 214 | connect_fd = -1; 215 | } 216 | continue; 217 | } 218 | err = setsockopt(connect_fd, SOL_SOCKET, SO_RCVBUF, (char *)(&bufsize), sizeof(int)); 219 | if (0 != err) 220 | { 221 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "set socket(%d) setsockopt SO_RCVBUF error.\n", connect_fd); 222 | LOG_INFO(LOG_LEVEL_ERROR, log_str_buf); 223 | if (connect_fd != -1) 224 | { 225 | closesocket(connect_fd); 226 | connect_fd = -1; 227 | } 228 | continue; 229 | } 230 | init_epoll_connect_by_index(epoll_connect_event_index, connect_fd, inet_ntoa(clientaddr.sin_addr)); 231 | // add epoll event 232 | ev.data.fd = connect_fd; 233 | ev.events = EPOLLIN | EPOLLET; // set epoll event type 234 | if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, connect_fd, &ev) == -1) 235 | { 236 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "EPOLL_CTL_ADD %d,%s.\n", errno, strerror(errno)); 237 | LOG_INFO(LOG_LEVEL_ERROR, log_str_buf); 238 | if (connect_fd != -1) 239 | { 240 | closesocket(connect_fd); 241 | connect_fd = -1; 242 | } 243 | continue; 244 | } 245 | connect_total_count_opration(TRUE, 1); 246 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "Epoll event[%d] *****connected from %s*****, fd:%d, current connect total = %d.\n", epoll_connect_event_index, 247 | inet_ntoa(clientaddr.sin_addr), connect_fd, current_connected_total); 248 | LOG_INFO(LOG_LEVEL_INDISPENSABLE, log_str_buf); 249 | } 250 | if (-1 != listen_fd) // out the while then close the socket 251 | { 252 | closesocket(listen_fd); 253 | listen_fd = -1; 254 | } 255 | return NULL; 256 | } 257 | 258 | static int create_accept_task(void) 259 | { 260 | return pthread_create(&accep_thread_t, NULL, accept_thread, NULL); 261 | } 262 | /*************************************************************************/ 263 | 264 | static int recv_buffer_from_fd(int socket_fd, char *recv_buffer, int *recv_length) 265 | { 266 | int rev = -1; 267 | int one_time_need_read = 1024; 268 | int continue_read = 1; 269 | int total_recv_lenght = 0, one_time_recv_lenght = 0; 270 | while (continue_read) 271 | { 272 | one_time_recv_lenght = recv(socket_fd, &recv_buffer[total_recv_lenght], one_time_need_read, 0); 273 | if (one_time_recv_lenght > 0) 274 | { 275 | total_recv_lenght += one_time_recv_lenght; 276 | } 277 | 278 | if (one_time_recv_lenght < 0) // error 279 | { 280 | // if (errno == EAGAIN) 281 | // { 282 | // continue_read = 0; 283 | // break; 284 | // } 285 | continue_read = 0; 286 | rev = -1; 287 | break; 288 | } 289 | else if (one_time_recv_lenght >= 0 && one_time_recv_lenght < one_time_need_read) // read over 290 | { 291 | continue_read = 0; 292 | rev = 0; 293 | *recv_length = total_recv_lenght; 294 | break; 295 | } 296 | else 297 | { 298 | continue_read = 0; 299 | rev = -1; 300 | break; 301 | } 302 | } 303 | return rev; 304 | } 305 | 306 | 307 | static int send_buffer_to_fd(int socket, unsigned char *pucBuf, int iLen) 308 | { 309 | int n; 310 | int nwrite; 311 | char log_str_buf[LOG_STR_BUF_LEN]; 312 | 313 | n = iLen; 314 | 315 | while (n > 0) 316 | { 317 | nwrite = write(socket, pucBuf + iLen - n, n); 318 | if (nwrite < n) 319 | { 320 | if (nwrite == -1) 321 | { 322 | if (errno != EAGAIN) 323 | { 324 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "Write.\n"); 325 | LOG_INFO(LOG_LEVEL_ERROR, log_str_buf); 326 | return 0; 327 | } 328 | else 329 | { 330 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "Write EAGAIN.\n"); 331 | LOG_INFO(LOG_LEVEL_INFO, log_str_buf); 332 | } 333 | } 334 | } 335 | n -= nwrite; 336 | } 337 | return (iLen - n); 338 | } 339 | 340 | 341 | static void dumpInfo(unsigned char *info, int length) 342 | { 343 | char log_str_buf[LOG_STR_BUF_LEN]; 344 | int index = 0; 345 | int j = 0; 346 | char buffer[128] = {0}; 347 | memset(buffer, 0, 128); 348 | for (index = 0; index < length; index++, j+=2) 349 | { 350 | sprintf(&buffer[j],"%02x",info[index]); 351 | } 352 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "dump info length = %d, %s\n", length, buffer); 353 | LOG_INFO(LOG_LEVEL_INDISPENSABLE, log_str_buf); 354 | } 355 | 356 | 357 | void* respons_stb_info(thpool_job_funcion_parameter *parameter, int thread_index) 358 | { 359 | char log_str_buf[LOG_STR_BUF_LEN]; 360 | char send_buffer[1024] = "i have get you data"; 361 | int sockfd = parameter->fd; 362 | printf("get buffer = %s\n", parameter->recv_buffer); 363 | printf("sockfd = %d\n", sockfd); 364 | send_buffer_to_fd(sockfd, send_buffer, strlen(send_buffer)); 365 | // deal with you logic 366 | if (sockfd != -1) 367 | { 368 | int mactched_event_index = get_matched_event_index_by_fd(sockfd); 369 | connect_total_count_opration(FALSE, 1); 370 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "send data to stb over then close the socket(%d), *****client addr(%s)***** , thread_index = %d.\n", sockfd, get_client_addr_by_index(mactched_event_index), thread_index); 371 | LOG_INFO(LOG_LEVEL_INDISPENSABLE, log_str_buf); 372 | free_event_by_index(mactched_event_index); 373 | closesocket(sockfd); 374 | sockfd = -1; 375 | } 376 | 377 | } 378 | /*******************************************************************/ 379 | 380 | int main(int argc, char *argv[]) 381 | { 382 | char log_file_name[128] = {0}; 383 | char log_str_buf[LOG_STR_BUF_LEN]; 384 | struct rlimit rl; 385 | thpool_t *thpool = NULL; 386 | time_t now; 387 | time_t prevTime, eventTime = 0; 388 | struct epoll_event ev, events[MAX_EVENTS]; 389 | int epoll_events_number = 0; 390 | int index = 0; 391 | int connect_socket_fd_temp = -1; 392 | int delete_pool_job_number = 0; 393 | 394 | if (2 != argc) 395 | { 396 | printf("pleanse input the port\n"); 397 | return 0; 398 | } 399 | port = atoi(argv[1]); 400 | // read config info 401 | if (read_config_info(&config_info) != 0) 402 | { 403 | printf("[%s %s %d] read_config_info fail.\n", __FILE__, __FUNCTION__, __LINE__); 404 | return -1; 405 | } 406 | print_config_info(config_info); 407 | 408 | signal(SIGCHLD, SIG_IGN); // Ignore the child to the end of the signal, preventing the zombie process(2015.7.17) 409 | 410 | // init log 411 | sprintf(log_file_name, "log_%d", port); 412 | // for distinguish between different ports 413 | set_log_file_name(log_file_name); 414 | if (log_init() != 0) 415 | { 416 | printf("init log error\n"); 417 | return -1; 418 | } 419 | log_set_level(config_info.log_level); 420 | 421 | // create fork 422 | pid_t pidfd = fork(); 423 | if (pidfd < 0) 424 | { 425 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "fork failed! errorcode = %d[%s].\n", errno, strerror(errno)); 426 | LOG_INFO(LOG_LEVEL_FATAL, log_str_buf); 427 | log_close(); 428 | return (-1); 429 | } 430 | if (pidfd != 0) 431 | { 432 | LOG_INFO(LOG_LEVEL_INFO, "parent fork over.\n"); 433 | exit(0); 434 | } 435 | setsid(); 436 | LOG_INFO(LOG_LEVEL_INFO, "children fork start.\n"); 437 | 438 | //set max number of open files(also for tcp connections) 439 | rl.rlim_cur = MAX_EVENTS; 440 | rl.rlim_max = MAX_EVENTS; 441 | setrlimit(RLIMIT_NOFILE, &rl); 442 | getrlimit(RLIMIT_NOFILE, &rl); 443 | fprintf(stderr, "cur:%d\n", (int)rl.rlim_cur); 444 | fprintf(stderr, "max:%d\n", (int)rl.rlim_max); 445 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "information about rlimit cur:%d max:%d.\n", (int)rl.rlim_cur, (int)rl.rlim_max); 446 | LOG_INFO(LOG_LEVEL_INFO, log_str_buf); 447 | 448 | sleep(1); 449 | signal(SIGKILL, signal_handler_reboot); // register the signal 450 | signal(SIGTERM, signal_handler_reboot); 451 | signal(SIGPIPE, signal_handler_reboot); 452 | 453 | init_epoll_connect(); 454 | // g_net_init_mysql(); // connect to the database 455 | #if CONNECT_TO_SQL_SUCCESS 456 | if (0 != sql_pool_create(THREAD_POLL_SIZE)) 457 | { 458 | LOG_INFO(LOG_LEVEL_FATAL, "mysql error.\n"); 459 | log_close(); 460 | return -1; 461 | } 462 | #endif 463 | epoll_fd = epoll_create(MAX_FDS); // 1024 464 | if (0 >= epoll_fd) 465 | { 466 | LOG_INFO(LOG_LEVEL_FATAL, "epoll_create error.\n"); 467 | log_close(); 468 | return -1; 469 | } 470 | 471 | // crate thread pool 472 | thpool = thpool_init(THREAD_POLL_SIZE); 473 | if (NULL == thpool) 474 | { 475 | LOG_INFO(LOG_LEVEL_FATAL, "create thread pool error.\n"); 476 | log_close(); 477 | return -1; 478 | } 479 | LOG_INFO(LOG_LEVEL_INDISPENSABLE, "thpool_init success.\n"); 480 | 481 | // accept the socket connect 482 | create_accept_task(); 483 | 484 | time(&prevTime); 485 | eventTime = prevTime; 486 | while (!exit_flag) 487 | { 488 | time(&now); 489 | if (abs(now - eventTime) >= SERVER_TIMEOUT) //SERVER_TIMEOUT second detect one time delete the time out event 490 | { 491 | eventTime = now; 492 | for (index = 0; index < MAX_EVENTS; index++) 493 | { 494 | connect_socket_fd_temp = get_fd_by_event_index(index); 495 | if (connect_socket_fd_temp != -1) 496 | { 497 | if ((now - get_event_connect_time_by_index(index)) > SERVER_TIMEOUT) 498 | { 499 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "Epoll event[%d] timeout closed and fd= %d.\n", index, connect_socket_fd_temp); 500 | LOG_INFO(LOG_LEVEL_INDISPENSABLE, log_str_buf); 501 | free_event_by_index(index); 502 | if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, connect_socket_fd_temp, &ev) == -1) 503 | { 504 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "EPOLL_CTL_DEL %d,%s.\n", errno, strerror(errno)); 505 | LOG_INFO(LOG_LEVEL_ERROR, log_str_buf); 506 | } 507 | connect_total_count_opration(FALSE, 1); 508 | closesocket(connect_socket_fd_temp); 509 | connect_socket_fd_temp = -1; 510 | } 511 | } 512 | } 513 | // delete the pool job time out job 514 | delete_pool_job_number = delete_timeout_job(thpool, SERVER_TIMEOUT); 515 | connect_total_count_opration(FALSE, delete_pool_job_number); 516 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "pool queque delete job number = %d.\n", delete_pool_job_number); 517 | LOG_INFO(LOG_LEVEL_INDISPENSABLE, log_str_buf); 518 | } 519 | epoll_events_number = epoll_wait(epoll_fd, events, MAX_EVENTS, 2000); //2seconds 520 | for (index = 0; index < epoll_events_number; ++index) // deal with the event 521 | { 522 | connect_socket_fd_temp = events[index].data.fd; // get the socket fd 523 | // delete epoll event 524 | if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[index].data.fd, &ev) == -1) 525 | { 526 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "EPOLL_CTL_DEL %d,%s.\n", errno, strerror(errno)); 527 | LOG_INFO(LOG_LEVEL_ERROR, log_str_buf); 528 | events[index].data.fd = -1; 529 | } 530 | if (events[index].events & EPOLLIN) //have read event 531 | { 532 | int event_index = -1; 533 | int recv_length = 0; 534 | unsigned char recv_buffer[BUFFER_SIZE]; 535 | 536 | if (connect_socket_fd_temp < 0) 537 | { 538 | connect_total_count_opration(FALSE, 1); 539 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "Event[%d] read invalid handle.\n", index); 540 | LOG_INFO(LOG_LEVEL_ERROR, log_str_buf); 541 | continue; 542 | } 543 | event_index = get_matched_event_index_by_fd(connect_socket_fd_temp); 544 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "Epoll get Event[%d] fd = %d.\n", event_index, connect_socket_fd_temp); 545 | LOG_INFO(LOG_LEVEL_INDISPENSABLE, log_str_buf); 546 | // no the event 547 | if (event_index < 0) 548 | { 549 | connect_total_count_opration(FALSE, 1); 550 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "not find matched fd = %d.\n", connect_socket_fd_temp); 551 | LOG_INFO(LOG_LEVEL_ERROR, log_str_buf); 552 | free_event_by_index(event_index); 553 | if (connect_socket_fd_temp != -1) 554 | { 555 | closesocket(connect_socket_fd_temp); 556 | connect_socket_fd_temp = -1; 557 | } 558 | continue; 559 | } 560 | // receive the buffer from the socket fd 561 | if (0 == recv_buffer_from_fd(connect_socket_fd_temp, recv_buffer, &recv_length)) 562 | { 563 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "recv_length = %d, current fd = %d, current job queue job number = %d.\n",recv_length, connect_socket_fd_temp, get_jobqueue_number(thpool)); 564 | LOG_INFO(LOG_LEVEL_INDISPENSABLE, log_str_buf); 565 | dumpInfo((unsigned char *)recv_buffer, recv_length); 566 | // receive buffer success then add the thread pool 567 | thpool_add_work(thpool, (void*)respons_stb_info, connect_socket_fd_temp, recv_buffer); 568 | } 569 | else 570 | { 571 | // receive buffer error 572 | connect_total_count_opration(FALSE, 1); 573 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "Epoll event[%d] not read data, and the socket fd = %d.\n", event_index, connect_socket_fd_temp); 574 | LOG_INFO(LOG_LEVEL_INDISPENSABLE, log_str_buf); 575 | free_event_by_index(event_index); 576 | if (connect_socket_fd_temp != -1) 577 | { 578 | closesocket(connect_socket_fd_temp); 579 | connect_socket_fd_temp = -1; 580 | } 581 | } 582 | } 583 | // else if (events[index].events & EPOLLOUT) //have read event. Will not reach here 584 | // { 585 | // //; 586 | // } 587 | else 588 | { 589 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "Unknown error! event.data.fd = %d.\n", events[index].data.fd); 590 | LOG_INFO(LOG_LEVEL_ERROR, log_str_buf); 591 | connect_total_count_opration(FALSE, 1); 592 | if (connect_socket_fd_temp < 0) 593 | { 594 | LOG_INFO(LOG_LEVEL_ERROR, "EPOLLOUT.\n"); 595 | continue; 596 | } 597 | //close the socket 598 | free_event_by_index(get_matched_event_index_by_fd(connect_socket_fd_temp)); 599 | if (connect_socket_fd_temp != -1) 600 | { 601 | closesocket(connect_socket_fd_temp); 602 | connect_socket_fd_temp = -1; 603 | } 604 | } 605 | } 606 | } 607 | log_close(); 608 | if (listen_fd != -1) 609 | { 610 | closesocket(listen_fd); 611 | listen_fd = -1; 612 | } 613 | 614 | #if CONNECT_TO_SQL_SUCCESS 615 | sql_pool_destroy(); 616 | #endif 617 | exit_accept_flag = 1; 618 | thpool_destroy(thpool); 619 | printf("[%s %s %d]Done...\n", __FILE__, __FUNCTION__, __LINE__); 620 | return 1; 621 | } 622 | 623 | 624 | -------------------------------------------------------------------------------- /server/g_net_update.h: -------------------------------------------------------------------------------- 1 | /* 2 | * g_net_update.h 3 | * 4 | * Created on: 5 | * Author: leo 6 | */ 7 | 8 | #ifndef G_NET_UPDATE_H_ 9 | #define G_NET_UPDATE_H_ 10 | #include "g_net_global.h" 11 | 12 | CONFIG_INFO *get_config_info(void); 13 | #endif /* G_NET_UPDATE_H_ */ 14 | -------------------------------------------------------------------------------- /server/ini.ini: -------------------------------------------------------------------------------- 1 | ; 2 | ; G-Net Update inifile 3 | ; 4 | 5 | [GENERAL] 6 | Version = 1.0; 7 | LogLevel = 1; 8 | 9 | [DATABASE] 10 | MySqlBranchServerAddr = 127.0.0.1 11 | MySqlServerPort = 3306 12 | MySqlDbName = leoweb 13 | MySqlUserName = root 14 | MySqlPassword = aigewei 15 | -------------------------------------------------------------------------------- /server/log.c: -------------------------------------------------------------------------------- 1 | /* 2 | * log.c 3 | * 4 | * Created on: 2013-5-7 5 | * Author: Fred 6 | */ 7 | 8 | #include "g_net_global.h" 9 | #include "log.h" 10 | 11 | #define MAX_LOG_LINE_NUM 500000 12 | #define TIME_STAMP_BUF_LEN 128 13 | 14 | static FILE *log_file_handle = NULL; 15 | static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER; 16 | static int log_level = LOG_LEVEL_INDISPENSABLE; 17 | static char last_log_str[LOG_STR_BUF_LEN]; 18 | static char cur_ts_str[TIME_STAMP_BUF_LEN]; 19 | 20 | static char log_file_name[128] = {0}; 21 | 22 | void set_log_file_name(char *file_name) 23 | { 24 | sprintf(log_file_name, "%s", file_name); 25 | } 26 | 27 | static int log_create_current_time_stamp(void) 28 | { 29 | struct tm *time_stamp; 30 | time_t cur_time; 31 | 32 | cur_time = time(NULL); 33 | time_stamp = localtime(&cur_time); 34 | 35 | snprintf(cur_ts_str, TIME_STAMP_BUF_LEN, "%02d/%02d/%02d %02d:%02d:%02d", time_stamp->tm_mday, 36 | time_stamp->tm_mon + 1, time_stamp->tm_year % 100, time_stamp->tm_hour, time_stamp->tm_min, time_stamp->tm_sec); 37 | return 0; 38 | } 39 | 40 | int log_init() 41 | { 42 | log_file_handle = fopen(log_file_name, "w"); 43 | if (log_file_handle == NULL) 44 | { 45 | printf("[%s %s %d] Can't create log file.\n", __FILE__, __FUNCTION__, __LINE__); 46 | return -1; 47 | } 48 | 49 | memset(last_log_str, 0, LOG_STR_BUF_LEN); 50 | 51 | log_string(LOG_LEVEL_INDISPENSABLE, "LOG START\n"); 52 | return 0; 53 | } 54 | 55 | void log_set_level(int level) 56 | { 57 | log_level = level; 58 | } 59 | 60 | int log_string(int level, const char *str) 61 | { 62 | char log_str[LOG_STR_BUF_LEN]; 63 | static int count = 0; 64 | int need_log_str = 0; 65 | 66 | pthread_mutex_lock(&log_mutex); 67 | log_create_current_time_stamp(); 68 | 69 | if (++count >= MAX_LOG_LINE_NUM) 70 | { 71 | count = 0; 72 | fclose(log_file_handle); 73 | log_file_handle = fopen(log_file_name, "w"); 74 | } 75 | 76 | // only log the string in case it is different then the last one 77 | if (strcmp(str, last_log_str)) 78 | { 79 | switch (level) 80 | { 81 | case LOG_LEVEL_INFO: 82 | if (log_level <= LOG_LEVEL_INFO) 83 | { 84 | need_log_str = 1; 85 | snprintf(log_str, LOG_STR_BUF_LEN, "[INFO: %s] %s", cur_ts_str, str); 86 | } 87 | break; 88 | case LOG_LEVEL_WARNING: 89 | if (log_level <= LOG_LEVEL_WARNING) 90 | { 91 | need_log_str = 1; 92 | snprintf(log_str, LOG_STR_BUF_LEN, "[WARNING: %s] %s", cur_ts_str, str); 93 | } 94 | break; 95 | case LOG_LEVEL_ERROR: 96 | if (log_level <= LOG_LEVEL_ERROR) 97 | { 98 | need_log_str = 1; 99 | snprintf(log_str, LOG_STR_BUF_LEN, "[ERROR: %s] %s", cur_ts_str, str); 100 | } 101 | break; 102 | case LOG_LEVEL_FATAL: 103 | if (log_level <= LOG_LEVEL_FATAL) 104 | { 105 | need_log_str = 1; 106 | snprintf(log_str, LOG_STR_BUF_LEN, "[FATAL: %s] %s", cur_ts_str, str); 107 | } 108 | break; 109 | case LOG_LEVEL_INDISPENSABLE: 110 | need_log_str = 1; 111 | snprintf(log_str, LOG_STR_BUF_LEN, "[%s] %s", cur_ts_str, str); 112 | break; 113 | } 114 | 115 | if (need_log_str) 116 | { 117 | fprintf(log_file_handle, "%s", log_str); 118 | memset(last_log_str, 0, LOG_STR_BUF_LEN); 119 | strcpy(last_log_str, str); 120 | } 121 | } 122 | fflush(log_file_handle); 123 | pthread_mutex_unlock(&log_mutex); 124 | return 0; 125 | } 126 | 127 | int log_close(void) 128 | { 129 | if (log_file_handle != NULL) 130 | { 131 | log_string(LOG_LEVEL_INDISPENSABLE, "LOG END\n"); 132 | fclose(log_file_handle); 133 | } 134 | return 0; 135 | } 136 | 137 | -------------------------------------------------------------------------------- /server/log.h: -------------------------------------------------------------------------------- 1 | #ifndef LOG_H_ 2 | #define LOG_H_ 3 | 4 | #define LOG_LEVEL_INFO (0x00) 5 | #define LOG_LEVEL_WARNING (0x01) 6 | #define LOG_LEVEL_ERROR (0x02) 7 | #define LOG_LEVEL_FATAL (0x03) 8 | #define LOG_LEVEL_INDISPENSABLE (0x04) //To display several indispensable information. 9 | 10 | #define LOG_STR_BUF_LEN 256 11 | 12 | 13 | #define LOG_INFO(a, b) \ 14 | {\ 15 | char log_str[LOG_STR_BUF_LEN];\ 16 | snprintf(log_str, LOG_STR_BUF_LEN, "[%s %s %d] %s", __FILE__, __FUNCTION__, __LINE__, b);\ 17 | log_string(a, log_str);\ 18 | } 19 | 20 | void set_log_file_name(char *file_name); 21 | int log_init(); 22 | void log_set_level(int level); 23 | int log_string(int level, const char *str); 24 | int log_close(void); 25 | 26 | #endif /* LOG_H_ */ 27 | 28 | -------------------------------------------------------------------------------- /server/makefile.txt: -------------------------------------------------------------------------------- 1 | # ======================================================================================== 2 | # Makefile for G-Net Update Server 3 | # ======================================================================================== 4 | 5 | 6 | # ======================================================================================== 7 | # Set include directories. 8 | INCLUDEDIR = /usr/local/include 9 | 10 | # ======================================================================================== 11 | # Compile flags 12 | CPPFLAGS = 13 | CC=gcc 14 | 15 | # ======================================================================================== 16 | # TARGET/Source definitions 17 | SRCDIR = . 18 | TARGET = epoll_server 19 | OBJS = $(TARGET).o 20 | SRC = $(wildcard $(SRCDIR)/*.c) 21 | 22 | # ======================================================================================== 23 | # Make all option. 24 | LDLIBS = 25 | LIBS = -l pthread -lm -L /usr/lib/mysql -lmysqlclient -lz 26 | 27 | all: $(TARGET) 28 | $(TARGET): $(SRC:.cpp=.o) 29 | $(CC) $(CPPFLAGS) $(LDFLAGS) $^ -o $@ $(LDLIBS) $(LIBS) 30 | 31 | # ======================================================================================== 32 | # Clean all option 33 | 34 | clean: 35 | rm -f $(SRCDIR)*.o $(SRCDIR)*~ $(SRCDIR)fcs $(SRCDIR).depend 36 | rm -f *.o *~ $(TARGET) .depend $(TARGET) 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /server/sql_pool.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sql_pool.c 3 | * 4 | * Created on: 201611 5 | * Author: leo 6 | */ 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "g_net_global.h" 14 | #include "config_info.h" 15 | #include "log.h" 16 | #include "g_net_update.h" 17 | #include "thread_pool.h" 18 | #include "sql_pool.h" 19 | 20 | 21 | static POOL_SQL_SOCK sql_sock_pool; 22 | 23 | // return 0: connect success, 1 connect error, -1: init error 24 | static int create_connect(POOL_SQL_SOCK *pool_sql_sock, SQL_SOCK_NODE *node) 25 | { 26 | int ret = 0; 27 | int opt = 1; 28 | char log_str_buf[LOG_STR_BUF_LEN] = {0}; 29 | 30 | do 31 | { 32 | if (NULL == mysql_init(&node->fd)) 33 | { 34 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "mysql_init error!.\n"); 35 | LOG_INFO(LOG_LEVEL_ERROR, log_str_buf); 36 | ret = -1; 37 | } 38 | else 39 | { 40 | if(pthread_mutex_init(&node->sql_lock, NULL)) 41 | { 42 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "Couldn't pthread_mutex_init to engine!.\n"); 43 | LOG_INFO(LOG_LEVEL_ERROR, log_str_buf); 44 | } 45 | 46 | if(!(node->mysql_sock = mysql_real_connect(&node->fd, pool_sql_sock->ip, pool_sql_sock->user, pool_sql_sock->passwd, pool_sql_sock->dbname, 47 | pool_sql_sock->port, NULL, 0))) 48 | { 49 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "Couldn't connect to engine! %s.\n", mysql_error(&node->fd)); 50 | LOG_INFO(LOG_LEVEL_ERROR, log_str_buf); 51 | node->sql_state = DB_DISCONN; 52 | ret = 1; 53 | printf("connect error\n"); 54 | } 55 | else 56 | { 57 | node->used = 0; 58 | node->sql_state = DB_CONN; 59 | mysql_options(&node->fd, MYSQL_OPT_RECONNECT, &opt); 60 | opt = 3; //3S 61 | mysql_options(&node->fd, MYSQL_OPT_CONNECT_TIMEOUT, &opt); 62 | ret = 0; 63 | } 64 | } 65 | 66 | }while(0); 67 | 68 | return ret; 69 | } 70 | 71 | int sql_pool_create(int connect_pool_number) 72 | { 73 | int index = 0; 74 | BOOL re_connect = TRUE; 75 | MYSQL mysql; 76 | MYSQL fd_temp; 77 | char log_str_buf[LOG_STR_BUF_LEN] = {0}; 78 | CONFIG_INFO *config = (CONFIG_INFO *)get_config_info(); 79 | 80 | // init 81 | memset((POOL_SQL_SOCK *)&sql_sock_pool, 0, sizeof(POOL_SQL_SOCK)); 82 | 83 | // set db info 84 | sprintf(sql_sock_pool.ip, "%s", config->mysql_branch_server_addr); 85 | sql_sock_pool.port = config->mysql_server_port; 86 | sprintf(sql_sock_pool.dbname, "%s", config->mysql_db_name); 87 | sprintf(sql_sock_pool.user, "%s", config->mysql_user_name); 88 | sprintf(sql_sock_pool.passwd, "%s", config->mysql_password); 89 | 90 | mysql_init(&fd_temp); 91 | 92 | // create connect 93 | for(index = 0; index < connect_pool_number; index ++) 94 | { 95 | if(-1 == create_connect(&sql_sock_pool, &(sql_sock_pool.sql_pool[index]))) 96 | { 97 | goto POOL_CREATE_FAILED; 98 | } 99 | printf("create db pool success\n"); 100 | sql_sock_pool.sql_pool[index].index = index; 101 | sql_sock_pool.pool_number++; 102 | } 103 | return 0; 104 | POOL_CREATE_FAILED: 105 | sql_pool_destroy(); 106 | return -1; 107 | } 108 | 109 | void sql_pool_destroy() 110 | { 111 | int index; 112 | for (index = 0; index < sql_sock_pool.pool_number; index ++) 113 | { 114 | if (NULL != sql_sock_pool.sql_pool[index].mysql_sock) // close the mysql 115 | { 116 | mysql_close(sql_sock_pool.sql_pool[index].mysql_sock); // close 117 | sql_sock_pool.sql_pool[index].mysql_sock = NULL; 118 | } 119 | sql_sock_pool.sql_pool[index].sql_state = DB_DISCONN; 120 | } 121 | } 122 | 123 | 124 | SQL_SOCK_NODE *get_db_connect_from_pool() 125 | { 126 | char log_str_buf[LOG_STR_BUF_LEN] = {0}; 127 | int start_index = 0, loop_index = 0, index = 0, ping_ret = 0; 128 | 129 | srand((int) time(0)); 130 | start_index = rand() % sql_sock_pool.pool_number; 131 | 132 | for (loop_index = 0; loop_index < sql_sock_pool.pool_number; loop_index++) 133 | { 134 | index = (start_index + loop_index) % sql_sock_pool.pool_number; 135 | if (0 == pthread_mutex_trylock(&(sql_sock_pool.sql_pool[index].sql_lock))) 136 | { 137 | if (DB_DISCONN == sql_sock_pool.sql_pool[index].sql_state) 138 | { 139 | // try reconnect 140 | if (0 != create_connect(&sql_sock_pool, &(sql_sock_pool.sql_pool[index]))) 141 | { 142 | // also can not connect to the database 143 | release_sock_to_sql_pool(&(sql_sock_pool.sql_pool[index])); 144 | continue; 145 | } 146 | } 147 | ping_ret = mysql_ping(sql_sock_pool.sql_pool[index].mysql_sock); 148 | if (0 != ping_ret) 149 | { 150 | snprintf(log_str_buf, LOG_STR_BUF_LEN, "mysql_ping error!.\n"); 151 | LOG_INFO(LOG_LEVEL_ERROR, log_str_buf); 152 | // error 153 | sql_sock_pool.sql_pool[index].sql_state = DB_DISCONN; // ping error then next time reconnect 154 | release_sock_to_sql_pool(&(sql_sock_pool.sql_pool[index])); 155 | } 156 | else 157 | { 158 | sql_sock_pool.sql_pool[index].used = 1; 159 | break; 160 | } 161 | } 162 | 163 | } 164 | if (loop_index == sql_sock_pool.pool_number) 165 | { 166 | return NULL; 167 | } 168 | else 169 | { 170 | return &(sql_sock_pool.sql_pool[index]); 171 | } 172 | 173 | } 174 | 175 | // put to pool 176 | void release_sock_to_sql_pool(SQL_SOCK_NODE * n) 177 | { 178 | n->used = 0; 179 | pthread_mutex_unlock(&n->sql_lock); 180 | } 181 | 182 | // error 183 | void check_sql_sock_normal(SQL_SOCK_NODE * n) 184 | { 185 | n->sql_state = DB_DISCONN; 186 | } 187 | -------------------------------------------------------------------------------- /server/sql_pool.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sql_pool.h 3 | * 4 | * Created on: 201611 5 | * Author: leo 6 | */ 7 | 8 | #ifndef SQL_POOL_H_ 9 | #define SQL_POOL_H_ 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "g_net_global.h" 16 | 17 | #define DB_LEN_IP 15 18 | #define DB_LEN_PORT 8 19 | #define DB_LEN_DBNAME 64 20 | #define DB_LEN_DBUSER 64 21 | #define DB_LEN_PASSWD 64 22 | 23 | #define POOL_NUMBER 20 24 | 25 | typedef struct _SQL_SOCK_NODE{ 26 | MYSQL fd; 27 | MYSQL *mysql_sock; 28 | pthread_mutex_t sql_lock; 29 | char used; 30 | int index; // for test 31 | enum {DB_DISCONN, DB_CONN} sql_state; 32 | } SQL_SOCK_NODE; 33 | 34 | typedef struct _POOL_SQL_SOCK{ 35 | SQL_SOCK_NODE sql_pool[POOL_NUMBER]; 36 | 37 | char ip[DB_LEN_IP + 1]; 38 | int port; 39 | char dbname[DB_LEN_DBNAME + 1]; 40 | char user[DB_LEN_DBUSER + 1]; 41 | char passwd[DB_LEN_PASSWD + 1]; 42 | 43 | int pool_number; 44 | } POOL_SQL_SOCK; 45 | 46 | void sql_pool_destroy(); 47 | SQL_SOCK_NODE *get_db_connect_from_pool(); 48 | void release_sock_to_sql_pool(SQL_SOCK_NODE *n); 49 | void check_sql_sock_normal(SQL_SOCK_NODE *n); 50 | int sql_pool_create(int connect_pool_number); 51 | 52 | 53 | 54 | #endif /* SQL_POOL_H_ */ 55 | -------------------------------------------------------------------------------- /server/thread_pool.c: -------------------------------------------------------------------------------- 1 | /* 2 | * thread_pool.c 3 | * 4 | * Created on: 201610 5 | * Author: leo 6 | */ 7 | #include "thread_pool_global.h" 8 | #include "thread_pool.h" 9 | 10 | 11 | static void thpool_thread_do(thpool_thread_parameter* tp_p); 12 | static int thpool_jobqueue_init(thpool_t* tp_p); 13 | static int thpool_jobqueue_removelast(thpool_t* tp_p); 14 | static void thpool_jobqueue_add(thpool_t *tp_p, thpool_job_t *newjob_p); 15 | static thpool_job_t* thpool_jobqueue_peek(thpool_t* tp_p); 16 | static void thpool_jobqueue_empty(thpool_t* tp_p); 17 | 18 | static int thpool_keepalive = 1; 19 | /* create a mute and initialized */ 20 | pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; /* used to serialize queue access */ 21 | 22 | /** 23 | * thread pool initialize 24 | * thread_pool_numbers: the thread pool number(the number of concurrent threads) 25 | */ 26 | thpool_t *thpool_init(int thread_pool_numbers) 27 | { 28 | int index = 0; 29 | thpool_t *thpool = NULL; 30 | 31 | if(!thread_pool_numbers || thread_pool_numbers < 1) 32 | { 33 | thread_pool_numbers = 1; 34 | } 35 | 36 | //allocate memory for thread pool 37 | thpool = (thpool_t*) malloc(sizeof(thpool_t)); 38 | if(thpool == NULL) 39 | { 40 | printf("malloc thpool_t error"); 41 | return NULL; 42 | } 43 | 44 | //distribution the thread number 45 | thpool->threadsN = thread_pool_numbers; 46 | thpool->threads = (pthread_t*) malloc(thread_pool_numbers * sizeof(pthread_t)); 47 | if(thpool->threads == NULL) 48 | { 49 | printf("malloc thpool->threads error"); 50 | return NULL; 51 | } 52 | 53 | // initialize job queue 54 | if(thpool_jobqueue_init(thpool)) 55 | { 56 | return NULL; 57 | } 58 | 59 | thpool->jobqueue->queueSem = (sem_t*)malloc(sizeof(sem_t)); 60 | sem_init(thpool->jobqueue->queueSem, 0, 0); // value start 0 61 | for(index = 0; index < thread_pool_numbers; index++) 62 | { 63 | thpool_thread_parameter *thead_paramter = (thpool_thread_parameter*) malloc(sizeof(thpool_thread_parameter));; 64 | thead_paramter->thpool = thpool; 65 | thead_paramter->thread_index = index; 66 | pthread_create(&(thpool->threads[index]), NULL, (void *)thpool_thread_do, (void*)thead_paramter); 67 | } 68 | return thpool; 69 | } 70 | 71 | void thpool_destroy(thpool_t* tp_p) 72 | { 73 | int i ; 74 | thpool_keepalive = 0; 75 | if (NULL == tp_p) 76 | { 77 | return; 78 | } 79 | for(i = 0; i < (tp_p->threadsN); i++) 80 | { 81 | if(sem_post(tp_p->jobqueue->queueSem)) 82 | { 83 | fprintf(stderr, "thpool_destroy(): Could not bypass sem_wait()\n"); 84 | } 85 | } 86 | if(sem_post(tp_p->jobqueue->queueSem) != 0) 87 | { 88 | fprintf(stderr, "thpool_destroy(): Could not destroy semaphore\n"); 89 | } 90 | for(i = 0;i < (tp_p->threadsN); i++) 91 | { 92 | pthread_join(tp_p->threads[i], NULL); 93 | } 94 | thpool_jobqueue_empty(tp_p); 95 | 96 | free(tp_p->threads); 97 | free(tp_p->jobqueue->queueSem); 98 | free(tp_p->jobqueue); 99 | free (tp_p); 100 | } 101 | 102 | /* Initialize queue */ 103 | static int thpool_jobqueue_init(thpool_t* tp_p) 104 | { 105 | tp_p->jobqueue = (thpool_jobqueue*)malloc(sizeof(thpool_jobqueue)); /* MALLOC job queue */ 106 | if (tp_p->jobqueue == NULL) 107 | { 108 | return -1; 109 | } 110 | tp_p->jobqueue->tail = NULL; 111 | tp_p->jobqueue->head = NULL; 112 | tp_p->jobqueue->jobN = 0; 113 | return 0; 114 | } 115 | 116 | static void thpool_thread_do(thpool_thread_parameter *thread_paramter) 117 | { 118 | thpool_t *tp_p = thread_paramter->thpool; 119 | int index = thread_paramter->thread_index; 120 | printf("index = %d\n", index); 121 | while(thpool_keepalive ==1) 122 | { 123 | if(sem_wait(tp_p->jobqueue->queueSem)) //thread block, until have data come 124 | { 125 | perror("thpool_thread_do(): Waiting for semaphore"); 126 | exit(1); 127 | } 128 | if(thpool_keepalive) 129 | { 130 | FUNC function; 131 | // void *arg_buff; 132 | thpool_job_t *job_p; 133 | pthread_mutex_lock(&mutex); 134 | job_p = thpool_jobqueue_peek(tp_p); 135 | function = job_p->function; 136 | // arg_buff = job_p->arg; 137 | if(thpool_jobqueue_removelast(tp_p)) 138 | { 139 | return ; 140 | } 141 | pthread_mutex_unlock(&mutex); 142 | function((void *)&job_p->arg, index); // our function 143 | free(job_p); // free the 144 | } 145 | else 146 | { 147 | free(thread_paramter); 148 | return ; 149 | } 150 | } 151 | free(thread_paramter); 152 | } 153 | 154 | //get the queue tail 155 | static thpool_job_t* thpool_jobqueue_peek(thpool_t* tp_p) 156 | { 157 | return tp_p->jobqueue->tail; 158 | } 159 | 160 | /////ɾ����е����һ���ڵ� 161 | static int thpool_jobqueue_removelast(thpool_t* tp_p) 162 | { 163 | int reval = 0; 164 | thpool_job_t *theLastJob = NULL; 165 | if (tp_p == NULL) 166 | { 167 | return -1; 168 | } 169 | theLastJob = tp_p->jobqueue->tail; 170 | switch (tp_p->jobqueue->jobN) 171 | { 172 | case 0: 173 | return -1; 174 | case 1: 175 | tp_p->jobqueue->head = NULL; 176 | tp_p->jobqueue->tail = NULL; 177 | break; 178 | default: 179 | theLastJob->prev->next = NULL; 180 | tp_p->jobqueue->tail = theLastJob->prev; 181 | 182 | } 183 | (tp_p->jobqueue->jobN)--; 184 | sem_getvalue(tp_p->jobqueue->queueSem, &reval); 185 | return 0; 186 | } 187 | 188 | static void thpool_jobqueue_add(thpool_t *tp_p, thpool_job_t *newjob_p) 189 | { 190 | int reval = 0; 191 | thpool_job_t *oldFirstJob = tp_p->jobqueue->head; 192 | 193 | newjob_p->next = NULL; 194 | newjob_p->prev = NULL; 195 | switch(tp_p->jobqueue->jobN) 196 | { 197 | case 0: 198 | tp_p->jobqueue->head = newjob_p; 199 | tp_p->jobqueue->tail = newjob_p; 200 | break; 201 | default: 202 | oldFirstJob->prev = newjob_p; 203 | newjob_p->next = oldFirstJob; 204 | tp_p->jobqueue->head = newjob_p; 205 | 206 | } 207 | (tp_p->jobqueue->jobN)++; 208 | sem_post(tp_p->jobqueue->queueSem); 209 | sem_getvalue(tp_p->jobqueue->queueSem, &reval); 210 | 211 | return; 212 | } 213 | 214 | // add to thread pool 215 | int thpool_add_work(thpool_t* tp_p, void *(*function_p)(void* arg, int index), /*void *arg_p*/int socket_fd, char *recev_buffer) 216 | { 217 | thpool_job_t *newjob = (thpool_job_t*) malloc(sizeof(thpool_job_t)); 218 | time_t now; 219 | 220 | time(&now); 221 | if(newjob == NULL) 222 | { 223 | fprintf(stderr, "thpool_add_work(): Could not allocate memory for new job\n"); 224 | return -1; 225 | } 226 | newjob ->function = function_p; 227 | newjob->job_add_time = now; 228 | // newjob ->arg = arg_p; 229 | memcpy(newjob->arg.recv_buffer, recev_buffer, BUFFER_SIZE); 230 | newjob->arg.fd = socket_fd; 231 | pthread_mutex_lock(&mutex); 232 | thpool_jobqueue_add(tp_p, newjob); 233 | pthread_mutex_unlock(&mutex); 234 | 235 | return 0; 236 | } 237 | 238 | // clean queue 239 | static void thpool_jobqueue_empty(thpool_t* tp_p) 240 | { 241 | thpool_job_t *curjob = tp_p->jobqueue->tail; 242 | 243 | while (tp_p->jobqueue->jobN) 244 | { 245 | tp_p->jobqueue->tail = curjob->prev; 246 | free (curjob); 247 | curjob = tp_p->jobqueue->tail; 248 | (tp_p->jobqueue->jobN)--; 249 | } 250 | tp_p->jobqueue->head = NULL; 251 | tp_p->jobqueue->tail = NULL; 252 | } 253 | 254 | int get_jobqueue_number(thpool_t* tp_p) 255 | { 256 | if (NULL != tp_p && NULL != tp_p->jobqueue) 257 | { 258 | return tp_p->jobqueue->jobN; 259 | } 260 | else 261 | { 262 | return 0; 263 | } 264 | } 265 | 266 | int delete_timeout_job(thpool_t* tp_p, int time_out) 267 | { 268 | int delete_number = 0; 269 | time_t now; 270 | thpool_job_t *curjob = tp_p->jobqueue->tail; 271 | 272 | time(&now); 273 | if (NULL != tp_p && NULL != tp_p->jobqueue) 274 | { 275 | pthread_mutex_lock(&mutex); 276 | while (tp_p->jobqueue->jobN) 277 | { 278 | if (NULL == curjob) 279 | { 280 | break; 281 | } 282 | if (now - curjob->job_add_time > time_out) 283 | { 284 | tp_p->jobqueue->tail = curjob->prev; 285 | free (curjob); 286 | curjob = tp_p->jobqueue->tail; 287 | (tp_p->jobqueue->jobN)--; 288 | delete_number++; 289 | } 290 | else 291 | { 292 | break; 293 | } 294 | } 295 | pthread_mutex_unlock(&mutex); 296 | } 297 | 298 | return delete_number; 299 | } 300 | -------------------------------------------------------------------------------- /server/thread_pool.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leoge0113/epoll-threadpool/bc2cd737f22b3acf73e4a77bd71f49841b6dda12/server/thread_pool.h -------------------------------------------------------------------------------- /server/thread_pool_global.h: -------------------------------------------------------------------------------- 1 | /* 2 | * thread_pool_global.h 3 | * 4 | * Created on: 5 | * Author: leo 6 | */ 7 | 8 | /********************************** 9 | * @author wallwind@yeah.net 10 | * @date 2012/06/13 11 | * Last update: 2012/06/13 12 | * License: LGPL 13 | * 14 | **********************************/ 15 | 16 | #ifndef _THREAD_POOL_GLOBAL_H_ 17 | #define _THREAD_POOL_GLOBAL_H_ 18 | 19 | #include 20 | #include 21 | #include /* */ 22 | #include 23 | #include /* offsetof() */ 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include /* statfs() */ 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include 45 | #include 46 | #include /* TCP_NODELAY, TCP_CORK */ 47 | #include 48 | #include 49 | #include 50 | 51 | #include /* tzset() */ 52 | #include /* memalign() */ 53 | #include /* IOV_MAX */ 54 | #include 55 | #include 56 | #include 57 | #include /* uname() */ 58 | #include 59 | 60 | #include 61 | #include 62 | #include 63 | #include 64 | #endif 65 | 66 | 67 | 68 | 69 | --------------------------------------------------------------------------------