1
0
mirror of https://github.com/fumiama/simple-kanban.git synced 2026-06-30 16:10:26 +08:00

优化代码结构

This commit is contained in:
源文雨
2022-05-15 14:26:09 +08:00
parent 1ae1138496
commit 352a8dc285
4 changed files with 140 additions and 134 deletions

View File

@@ -10,16 +10,16 @@ endif()
add_definitions(-DLISTEN_ON_IPV6) add_definitions(-DLISTEN_ON_IPV6)
# include_directories("/usr/local/include") include_directories("/usr/local/include")
# link_directories("/usr/local/lib") link_directories("/usr/local/lib")
add_executable(simple-kanban server.c) add_executable(simple-kanban server.c)
add_executable(simple-kanban-client client.c) add_executable(simple-kanban-client client.c)
add_executable(cfgwriter cfgwriter.c) add_executable(cfgwriter cfgwriter.c)
target_link_libraries(simple-kanban spb pthread) target_link_libraries(simple-kanban libspb.a pthread)
target_link_libraries(simple-kanban-client pthread) target_link_libraries(simple-kanban-client pthread)
target_link_libraries(cfgwriter spb) target_link_libraries(cfgwriter libspb.a)
INSTALL(TARGETS simple-kanban RUNTIME DESTINATION bin) INSTALL(TARGETS simple-kanban RUNTIME DESTINATION bin)
INSTALL(TARGETS simple-kanban-client RUNTIME DESTINATION bin) INSTALL(TARGETS simple-kanban-client RUNTIME DESTINATION bin)

View File

@@ -3,17 +3,17 @@
#include <simple_protobuf.h> #include <simple_protobuf.h>
#include "config.h" #include "config.h"
CONFIG cfg; config_t cfg;
int main() { int main() {
printf("Enter a password: "); printf("Enter a password: ");
scanf("%s", cfg.pwd); scanf("%s", cfg.pwd);
printf("Enter a set password: "); printf("Enter a set password: ");
scanf("%s", cfg.sps); scanf("%s", cfg.sps);
uint32_t* types_len = align_struct(sizeof(CONFIG), 2, &cfg.pwd, &cfg.sps); uint32_t* types_len = align_struct(sizeof(config_t), 2, &cfg.pwd, &cfg.sps);
FILE* fp = fopen("cfg.sp", "wb"); FILE* fp = fopen("cfg.sp", "wb");
if(fp) { if(fp) {
set_pb(fp, types_len, sizeof(CONFIG), &cfg); set_pb(fp, types_len, sizeof(config_t), &cfg);
fclose(fp); fclose(fp);
puts("Config is saved to cfg.sp."); puts("Config is saved to cfg.sp.");
fp = NULL; fp = NULL;
@@ -21,8 +21,8 @@ int main() {
fp = fopen("cfg.sp", "rb"); fp = fopen("cfg.sp", "rb");
if(fp) { if(fp) {
SIMPLE_PB* spb = get_pb(fp); SIMPLE_PB* spb = get_pb(fp);
memset(&cfg, 0, sizeof(CONFIG)); memset(&cfg, 0, sizeof(config_t));
memcpy(&cfg, spb->target, sizeof(CONFIG)); memcpy(&cfg, spb->target, sizeof(config_t));
printf("set pwd: %s, sps: %s\n", cfg.pwd, cfg.sps); printf("set pwd: %s, sps: %s\n", cfg.pwd, cfg.sps);
} else perror("[SPB]"); } else perror("[SPB]");
} else perror("[SPB]"); } else perror("[SPB]");

View File

@@ -1,10 +1,10 @@
#ifndef _CONFIG_H_ #ifndef _CONFIG_H_
#define _CONFIG_H_ #define _CONFIG_H_
struct CONFIG { struct config_t {
char pwd[64]; //password char pwd[64]; //password
char sps[64]; //set password char sps[64]; //set password
}; };
typedef struct CONFIG CONFIG; typedef struct config_t config_t;
#endif #endif

252
server.c
View File

@@ -4,6 +4,7 @@
#include <pthread.h> #include <pthread.h>
#include <signal.h> #include <signal.h>
#include <simple_protobuf.h> #include <simple_protobuf.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -23,7 +24,7 @@
#include <machine/endian.h> #include <machine/endian.h>
#endif #endif
static CONFIG* cfg; // 存储 pwd 和 sps static config_t* cfg; // 存储 pwd 和 sps
static int fd; // server socket fd static int fd; // server socket fd
@@ -49,7 +50,7 @@ static pthread_attr_t attr;
// accept_timer 使用的结构体 // accept_timer 使用的结构体
// 包含了本次 accept 的全部信息 // 包含了本次 accept 的全部信息
// 以方便退出后清理空间 // 以方便退出后清理空间
struct THREADTIMER { struct threadtimer_t {
int index; // 指向 accept_threads 某个槽位的下标 int index; // 指向 accept_threads 某个槽位的下标
time_t touch; // 最后访问时间,与当前时间差超过 MAXWAITSEC 将由 timer 强行回收线程 time_t touch; // 最后访问时间,与当前时间差超过 MAXWAITSEC 将由 timer 强行回收线程
int accept_fd; // 本次 accept 的 fd会自行关闭或出错时由 timer 负责回收 int accept_fd; // 本次 accept 的 fd会自行关闭或出错时由 timer 负责回收
@@ -59,30 +60,29 @@ struct THREADTIMER {
FILE *fp; // 本会话打开的文件,会自行关闭或出错时由 timer 负责回收 FILE *fp; // 本会话打开的文件,会自行关闭或出错时由 timer 负责回收
char data[TIMERDATSZ]; char data[TIMERDATSZ];
}; };
typedef struct THREADTIMER THREADTIMER; typedef struct threadtimer_t threadtimer_t;
#define showUsage(program) printf("Usage: %s [-d] listen_port try_times kanban_file data_file config_file\n\t-d: As daemon\n", program) #define show_usage(program) printf("Usage: %s [-d] listen_port kanban_file data_file config_file\n\t-d: As daemon\n", program)
static void accept_client(); static void accept_client();
static void accept_timer(void *p); static void accept_timer(void *p);
static int bind_server(uint16_t port, int try_times); static int bind_server(uint16_t port);
static int check_buffer(THREADTIMER *timer); static int check_buffer(threadtimer_t *timer);
static void clean_timer(THREADTIMER* timer); static void clean_timer(threadtimer_t* timer);
static void close_file(FILE *fp); static void close_file(FILE *fp);
static int close_file_and_send(THREADTIMER *timer, char *data, size_t numbytes); static int close_file_and_send(threadtimer_t *timer, char *data, size_t numbytes);
static void exit_thread(int signo);
static void handle_accept(void *accept_fd_p); static void handle_accept(void *accept_fd_p);
static void handle_pipe(int signo); static int listen_socket();
static void handle_quit(int signo);
static int listen_socket(int try_times);
static FILE *open_file(char* file_path, int lock_type, char* mode); static FILE *open_file(char* file_path, int lock_type, char* mode);
static int send_all(char* file_path, THREADTIMER *timer); static int send_all(char* file_path, threadtimer_t *timer);
static int send_data(int accept_fd, char *data, size_t length); static int send_data(int accept_fd, char *data, size_t length);
static off_t size_of_file(const char* fname); static off_t size_of_file(const char* fname);
static int sm1_pwd(THREADTIMER *timer); static int sm1_pwd(threadtimer_t *timer);
static int s0_init(THREADTIMER *timer); static int s0_init(threadtimer_t *timer);
static int s1_get(THREADTIMER *timer); static int s1_get(threadtimer_t *timer);
static int s2_set(THREADTIMER *timer); static int s2_set(threadtimer_t *timer);
static int s3_set_data(THREADTIMER *timer); static int s3_set_data(threadtimer_t *timer);
static pid_t pid; static pid_t pid;
/*************************************** /***************************************
@@ -102,13 +102,11 @@ static void accept_client() {
puts("Server subprocess exited. Restart..."); puts("Server subprocess exited. Restart...");
pid = fork(); pid = fork();
} }
signal(SIGQUIT, handle_quit);
signal(SIGPIPE, handle_pipe);
pthread_attr_init(&attr); pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if(pid < 0) puts("Error when forking a subprocess."); if(pid < 0) puts("Error when forking a subprocess.");
else while(1) { else while(1) {
puts("Ready for accept, waitting..."); puts("\nReady for accept, waitting...");
int p = 0; int p = 0;
while(p < THREADCNT && accept_threads[p] && !pthread_kill(accept_threads[p], 0)) p++; while(p < THREADCNT && accept_threads[p] && !pthread_kill(accept_threads[p], 0)) p++;
if(p >= THREADCNT) { if(p >= THREADCNT) {
@@ -117,7 +115,7 @@ static void accept_client() {
continue; continue;
} }
printf("Next thread is No.%d\n", p); printf("Next thread is No.%d\n", p);
THREADTIMER *timer = malloc(sizeof(THREADTIMER)); threadtimer_t *timer = malloc(sizeof(threadtimer_t));
if(!timer) { if(!timer) {
puts("Allocate timer error"); puts("Allocate timer error");
continue; continue;
@@ -149,7 +147,7 @@ static void accept_client() {
} }
} }
#define timer_ptr(x) ((THREADTIMER*)(x)) #define timer_ptr(x) ((threadtimer_t*)(x))
#define my_thread(timer) accept_threads[timer->index] #define my_thread(timer) accept_threads[timer->index]
/*************************************** /***************************************
* accept_timer 是与 handle_accept 伴生的 * accept_timer 是与 handle_accept 伴生的
@@ -163,11 +161,10 @@ static void accept_timer(void *p) {
if(waitsec > MAXWAITSEC) break; if(waitsec > MAXWAITSEC) break;
} }
clean_timer(timer_ptr(p)); clean_timer(timer_ptr(p));
free(p); // 唯一 free 点
puts("Timer has been freed"); puts("Timer has been freed");
} }
static int bind_server(uint16_t port, int try_times) { static int bind_server(uint16_t port) {
int fail_count = 0; int fail_count = 0;
int result = -1; int result = -1;
#ifdef LISTEN_ON_IPV6 #ifdef LISTEN_ON_IPV6
@@ -182,21 +179,15 @@ static int bind_server(uint16_t port, int try_times) {
bzero(&(server_addr.sin_zero), 8); bzero(&(server_addr.sin_zero), 8);
fd = socket(AF_INET, SOCK_STREAM, 0); fd = socket(AF_INET, SOCK_STREAM, 0);
#endif #endif
while(!~(result = bind(fd, (struct sockaddr *)&server_addr, struct_len)) && fail_count++ < try_times) sleep(1); if(!~bind(fd, (struct sockaddr *)&server_addr, struct_len)) return 1;
if(!~result && fail_count >= try_times) { return 0;
puts("Bind server failure!");
return 0;
} else{
puts("Bind server success!");
return 1;
}
} }
/*************************************** /***************************************
* check_buffer 检查接收到的数据,结合 * check_buffer 检查接收到的数据,结合
* 当前会话所处状态决定接下来的处理流程 * 当前会话所处状态决定接下来的处理流程
***************************************/ ***************************************/
static int check_buffer(THREADTIMER *timer) { static int check_buffer(threadtimer_t *timer) {
printf("Status: %d\n", (int)timer->status); printf("Status: %d\n", (int)timer->status);
switch(timer->status) { switch(timer->status) {
case -1: return sm1_pwd(timer); break; case -1: return sm1_pwd(timer); break;
@@ -209,7 +200,7 @@ static int check_buffer(THREADTIMER *timer) {
} }
// clean_timer 清理 timer // clean_timer 清理 timer
static void clean_timer(THREADTIMER* timer) { static void clean_timer(threadtimer_t* timer) {
puts("Start cleaning."); puts("Start cleaning.");
if(my_thread(timer)) { if(my_thread(timer)) {
pthread_kill(my_thread(timer), SIGQUIT); pthread_kill(my_thread(timer), SIGQUIT);
@@ -226,6 +217,7 @@ static void clean_timer(THREADTIMER* timer) {
timer->accept_fd = 0; timer->accept_fd = 0;
puts("Close accept."); puts("Close accept.");
} }
free(timer);
puts("Finish cleaning."); puts("Finish cleaning.");
} }
@@ -237,7 +229,7 @@ static void close_file(FILE *fp) {
} }
} }
static int close_file_and_send(THREADTIMER *timer, char *data, size_t numbytes) { static int close_file_and_send(threadtimer_t *timer, char *data, size_t numbytes) {
close_file(timer->fp); close_file(timer->fp);
timer->is_open = 0; timer->is_open = 0;
return send_data(timer->accept_fd, data, numbytes); return send_data(timer->accept_fd, data, numbytes);
@@ -262,58 +254,52 @@ static int close_file_and_send(THREADTIMER *timer, char *data, size_t numbytes)
#define my_dat(x) (timer_ptr(x)->data) #define my_dat(x) (timer_ptr(x)->data)
// handle_accept 初步解析指令,处理部分粘连 // handle_accept 初步解析指令,处理部分粘连
static void handle_accept(void *p) { static void handle_accept(void *p) {
if(my_fd(p) > 0) { puts("Connected to the client.");
puts("Connected to the client."); signal(SIGQUIT, exit_thread);
signal(SIGQUIT, handle_quit); signal(SIGPIPE, exit_thread);
signal(SIGPIPE, handle_pipe); pthread_t thread;
pthread_t thread; if (pthread_create(&thread, &attr, (void *)&accept_timer, p)) {
if (pthread_create(&thread, &attr, (void *)&accept_timer, p)) puts("Error creating timer thread"); puts("Error creating timer thread");
else puts("Creating timer thread succeeded"); close(my_fd(p));
send_data(my_fd(p), "Welcome to simple kanban server.", 33); free(p);
timer_ptr(p)->status = -1; return;
while(my_thread(timer_ptr(p)) && (timer_ptr(p)->numbytes = recv(my_fd(p), my_dat(p), TIMERDATSZ, 0)) > 0) { }
touch_timer(p); puts("Creating timer thread succeeded");
my_dat(p)[timer_ptr(p)->numbytes] = 0; pthread_cleanup_push((void*)clean_timer, p);
printf("Get %d bytes: %s\n", (int)timer_ptr(p)->numbytes, my_dat(p)); send_data(my_fd(p), "Welcome to simple kanban server.", 33);
puts("Check buffer"); timer_ptr(p)->status = -1;
//处理部分粘连 while(my_thread(timer_ptr(p)) && (timer_ptr(p)->numbytes = recv(my_fd(p), my_dat(p), TIMERDATSZ, 0)) > 0) {
take_word(p, cfg->pwd, my_dat(p)); touch_timer(p);
take_word(p, "get", my_dat(p)); my_dat(p)[timer_ptr(p)->numbytes] = 0;
take_word(p, "set", my_dat(p)); printf("Get %d bytes: %s\n", (int)timer_ptr(p)->numbytes, my_dat(p));
take_word(p, "cat", my_dat(p)); puts("Check buffer");
take_word(p, "quit", my_dat(p)); //处理部分粘连
take_word(p, cfg->sps, my_dat(p)); take_word(p, cfg->pwd, my_dat(p));
take_word(p, "ver", my_dat(p)); take_word(p, "get", my_dat(p));
take_word(p, "dat", my_dat(p)); take_word(p, "set", my_dat(p));
if(timer_ptr(p)->numbytes > 0) chkbuf(p); take_word(p, "cat", my_dat(p));
} take_word(p, "quit", my_dat(p));
printf("Break: recv %d bytes\n", (int)timer_ptr(p)->numbytes); take_word(p, cfg->sps, my_dat(p));
my_thread(timer_ptr(p)) = 0; take_word(p, "ver", my_dat(p));
clean_timer(timer_ptr(p)); take_word(p, "dat", my_dat(p));
} else puts("Error accepting client"); if(timer_ptr(p)->numbytes > 0) chkbuf(p);
}
printf("Break: recv %d bytes\n", (int)timer_ptr(p)->numbytes);
my_thread(timer_ptr(p)) = 0;
pthread_cleanup_pop(1);
} }
static void handle_quit(int signo) { static void exit_thread(int signo) {
perror("signal quit"); printf("Signal %d", signo);
perror("");
pthread_exit(NULL); pthread_exit(NULL);
} }
static void handle_pipe(int signo) { static int listen_socket() {
perror("signal pipe");
pthread_exit(NULL);
}
static int listen_socket(int try_times) {
int fail_count = 0; int fail_count = 0;
int result = -1; int result = -1;
while(!~(result = listen(fd, 10)) && fail_count++ < try_times) sleep(1); if(!~listen(fd, 10)) return 1;
if(!~result && fail_count >= try_times) { return 0;
puts("Listen failed!");
return 0;
} else{
puts("Listening....");
return 1;
}
} }
static FILE *open_file(char* file_path, int lock_type, char* mode) { static FILE *open_file(char* file_path, int lock_type, char* mode) {
@@ -329,7 +315,7 @@ static FILE *open_file(char* file_path, int lock_type, char* mode) {
return fp; return fp;
} }
static int send_all(char* file_path, THREADTIMER *timer) { static int send_all(char* file_path, threadtimer_t *timer) {
int re = 1; int re = 1;
FILE *fp = open_file(file_path, LOCK_SH, "rb"); FILE *fp = open_file(file_path, LOCK_SH, "rb");
if(fp) { if(fp) {
@@ -391,12 +377,12 @@ static off_t size_of_file(const char* fname) {
else return -1; else return -1;
} }
static int sm1_pwd(THREADTIMER *timer) { static int sm1_pwd(threadtimer_t *timer) {
if(!strcmp(cfg->pwd, timer->data)) timer->status = 0; if(!strcmp(cfg->pwd, timer->data)) timer->status = 0;
return !timer->status; return !timer->status;
} }
static int s0_init(THREADTIMER *timer) { static int s0_init(threadtimer_t *timer) {
if(!strcmp("get", timer->data)) timer->status = 1; if(!strcmp("get", timer->data)) timer->status = 1;
else if(!strcmp(cfg->sps, timer->data)) timer->status = 2; else if(!strcmp(cfg->sps, timer->data)) timer->status = 2;
else if(!strcmp("cat", timer->data)) return send_all(data_path, timer); else if(!strcmp("cat", timer->data)) return send_all(data_path, timer);
@@ -404,7 +390,7 @@ static int s0_init(THREADTIMER *timer) {
return send_data(timer->accept_fd, timer->data, timer->numbytes); return send_data(timer->accept_fd, timer->data, timer->numbytes);
} }
static int s1_get(THREADTIMER *timer) { //get kanban static int s1_get(threadtimer_t *timer) { //get kanban
FILE *fp = open_file(kanban_path, LOCK_SH, "rb"); FILE *fp = open_file(kanban_path, LOCK_SH, "rb");
timer->status = 0; timer->status = 0;
if(fp) { if(fp) {
@@ -429,7 +415,7 @@ static int s1_get(THREADTIMER *timer) { //get kanban
return close_file_and_send(timer, "null", 4); return close_file_and_send(timer, "null", 4);
} }
static int s2_set(THREADTIMER *timer) { static int s2_set(threadtimer_t *timer) {
FILE *fp = NULL; FILE *fp = NULL;
if(!strcmp(timer->data, "ver")) { if(!strcmp(timer->data, "ver")) {
fp = open_file(kanban_path, LOCK_EX, "wb"); fp = open_file(kanban_path, LOCK_EX, "wb");
@@ -447,7 +433,7 @@ static int s2_set(THREADTIMER *timer) {
} }
} }
static int s3_set_data(THREADTIMER *timer) { static int s3_set_data(threadtimer_t *timer) {
timer->status = 0; timer->status = 0;
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
uint32_t file_size = __builtin_bswap32(*(uint32_t*)(timer->data)); uint32_t file_size = __builtin_bswap32(*(uint32_t*)(timer->data));
@@ -494,42 +480,62 @@ static int s3_set_data(THREADTIMER *timer) {
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
if(argc != 6 && argc != 7) showUsage(argv[0]); if(argc != 5 && argc != 6) {
else { show_usage(argv[0]);
int port = 0; return 0;
int as_daemon = !strcmp("-d", argv[1]);
sscanf(argv[as_daemon?2:1], "%d", &port);
if(port > 0 && port < 65536) {
int times = 0;
sscanf(argv[as_daemon?3:2], "%d", &times);
if(times > 0) {
if(!as_daemon || (as_daemon && (daemon(1, 1) >= 0))) {
FILE *fp = NULL;
fp = fopen(argv[as_daemon?4:3], "rb+");
if(!fp) fp = fopen(argv[as_daemon?4:3], "wb+");
if(fp) {
kanban_path = argv[as_daemon?4:3];
fclose(fp);
fp = NULL;
fp = fopen(argv[as_daemon?5:4], "rb+");
if(!fp) fp = fopen(argv[as_daemon?5:4], "wb+");
if(fp) {
data_path = argv[as_daemon?5:4];
fclose(fp);
fp = NULL;
fp = fopen(argv[as_daemon?6:5], "rb");
if(fp) {
SIMPLE_PB* spb = get_pb(fp);
cfg = (CONFIG*)spb->target;
fclose(fp);
if(bind_server(port, times)) if(listen_socket(times)) accept_client();
} else printf("Error opening config file: %s\n", argv[as_daemon?6:5]);
} else printf("Error opening data file: %s\n", argv[as_daemon?5:4]);
} else printf("Error opening kanban file: %s\n", argv[as_daemon?4:3]);
} else puts("Start daemon error");
} else printf("Error times: %d\n", times);
} else printf("Error port: %d\n", port);
} }
close(fd); int port = 0;
exit(EXIT_FAILURE); int as_daemon = !strcmp("-d", argv[1]);
sscanf(argv[as_daemon?2:1], "%d", &port);
if(port <= 0 || port >= 65536) {
printf("Error port: %d\n", port);
return 1;
}
if(as_daemon && daemon(1, 1) < 0) {
perror("Start daemon error");
return 2;
}
FILE *fp = NULL;
fp = fopen(argv[as_daemon?3:2], "rb+");
if(!fp) fp = fopen(argv[as_daemon?3:2], "wb+");
if(!fp) {
printf("Error opening kanban file: ");
perror(argv[as_daemon?3:2]);
return 3;
}
kanban_path = argv[as_daemon?3:2];
fclose(fp);
fp = NULL;
fp = fopen(argv[as_daemon?4:3], "rb+");
if(!fp) fp = fopen(argv[as_daemon?4:3], "wb+");
if(!fp) {
printf("Error opening data file: ");
perror(argv[as_daemon?4:3]);
return 4;
}
data_path = argv[as_daemon?4:3];
fclose(fp);
fp = NULL;
fp = fopen(argv[as_daemon?5:4], "rb");
if(!fp) {
printf("Error opening config file: ");
perror(argv[as_daemon?5:4]);
return 5;
}
SIMPLE_PB* spb = get_pb(fp);
cfg = (config_t*)spb->target;
fclose(fp);
if(bind_server(port)) {
perror("Bind server failed");
return 6;
}
puts("Bind server success!");
if(listen_socket()) {
perror("Listen failed");
return 7;
}
pthread_cleanup_push((void*)close, (void*)(uintptr_t)fd);
accept_client();
pthread_cleanup_pop(1);
return 99;
} }