间隔了一周时间没写了,由于今年的股势行情貌似不错的样子,对于对股市完全不懂的我也在蠢蠢欲动,所以最近一周业余时间在“不务正业”-----学习炒股。发现学习它其实挺费神的,满脑子都是走势图,而且是神经有点受刺激的感觉,发现这个坚决不能在上班时间去想这事,不然会非常影响情绪,毕境对于普通老百姓来讲经济来源还主要是来源于工作,专职炒股也不适合像我这样笨拙的人,不过可以业余有时间学习学习,入市那还是得非常非常谨慎,所以放下它,接着来学习技术这才是王道,言归正传。
上一次对字符串工具模块进行了封装,这次主要是对"参数配置模块"的封装,FTP中有很多配置相关的选项,不可能硬编码到代码中,而应该将它们配置到配置文件当中,像vsftpd的配置文件如下:
而对于miniftpd所有的参数配置项如下:
对于上面这些变量应该是与对应的配置项进行一一对应的,所以需要定义三张表格来进行一一对应:
配置文件中的配置项与配置项变量对应关系表 |
static struct parseconf_bool_setting { const char *p_setting_name; int *p_variable; } parseconf_bool_array[] = { { "pasv_enable", &tunable_pasv_enable }, { "port_enable", &tunable_port_enable }, { NULL, NULL } }; |
static struct parseconf_uint_setting { const char *p_setting_name; unsigned int *p_variable; } parseconf_uint_array[] = { { "listen_port", &tunable_listen_port }, { "max_clients", &tunable_max_clients }, { "max_per_ip", &tunable_max_per_ip }, { "accept_timeout", &tunable_accept_timeout }, { "connect_timeout", &tunable_connect_timeout }, { "idle_session_timeout", &tunable_idle_session_timeout }, { "data_connection_timeout", &tunable_data_connection_timeout }, { "local_umask", &tunable_local_umask }, { "upload_max_rate", &tunable_upload_max_rate }, { "download_max_rate", &tunable_download_max_rate }, { NULL, NULL } }; |
static struct parseconf_str_setting { const char *p_setting_name; const char **p_variable; } parseconf_str_array[] = { { "listen_address", &tunable_listen_address }, { NULL, NULL }//最后这个NULL是为了遍历用的 }; |
下面定义两个操作配置文件的函数:
函数 |
说明 |
void parseconf_load_file(const char *path); |
加载配置文件 |
void parseconf_load_setting(const char *setting); |
将配置项加载到相应的变量 |
下面则开始进行编码,首先先新建配置文件模块文:
tunable.h:对其变量进行声明:
#ifndef _TUNABLE_H_ #define _TUNABLE_H_ extern int tunable_pasv_enable; extern int tunable_port_enable; extern unsigned int tunable_listen_port; extern unsigned int tunable_max_clients; extern unsigned int tunable_max_per_ip; extern unsigned int tunable_accept_timeout; extern unsigned int tunable_connect_timeout; extern unsigned int tunable_idle_session_timeout; extern unsigned int tunable_data_connection_timeout; extern unsigned int tunable_local_umask; extern unsigned int tunable_upload_max_rate; extern unsigned int tunable_download_max_rate; extern const char *tunable_listen_address; #endif /* _TUNABLE_H_ */
tunable.h:
#include "tunable.h" int tunable_pasv_enable = 1; int tunable_port_enable = 1; unsigned int tunable_listen_port = 21; unsigned int tunable_max_clients = 2000; unsigned int tunable_max_per_ip = 50; unsigned int tunable_accept_timeout = 60; unsigned int tunable_connect_timeout = 60; unsigned int tunable_idle_session_timeout = 300; unsigned int tunable_data_connection_timeout = 300; unsigned int tunable_local_umask = 077; unsigned int tunable_upload_max_rate = 0; unsigned int tunable_download_max_rate = 0; const char *tunable_listen_address;
另外新建一个配置文件:
接下来还要暴露两个接口出来,对文件和配置项的解析:
函数 |
说明 |
void parseconf_load_file(const char *path); |
加载配置文件 |
void parseconf_load_setting(const char *setting); |
将配置项加载到相应的变量 |
新建一个解析模块来做上面的解析工作:
parseconf.h:
#ifndef _PARSE_CONF_H_ #define _PARSE_CONF_H_ void parseconf_load_file(const char *path); void parseconf_load_setting(const char *setting); #endif /* _PARSE_CONF_H_ */
parseconf.c:
#include "parseconf.h" #include "common.h" #include "tunable.h" void parseconf_load_file(const char *path){ } void parseconf_load_setting(const char *setting){ }
下面来实现这两个函数:
另外,由于fgets函数读取的一行字符包含' ',所以需要将其去掉,可以用我们之前封装的现成方法:
接下来实现命令行的解析函数,在正式解析之前,需要将配置文件中的配置项与配置项变量对应关系表用代码定义出来,如下:
#include "parseconf.h" #include "common.h" #include "tunable.h" static struct parseconf_bool_setting { const char *p_setting_name; int *p_variable; } parseconf_bool_array[] = { { "pasv_enable", &tunable_pasv_enable }, { "port_enable", &tunable_port_enable }, { NULL, NULL } }; static struct parseconf_uint_setting { const char *p_setting_name; unsigned int *p_variable; } parseconf_uint_array[] = { { "listen_port", &tunable_listen_port }, { "max_clients", &tunable_max_clients }, { "max_per_ip", &tunable_max_per_ip }, { "accept_timeout", &tunable_accept_timeout }, { "connect_timeout", &tunable_connect_timeout }, { "idle_session_timeout", &tunable_idle_session_timeout }, { "data_connection_timeout", &tunable_data_connection_timeout }, { "local_umask", &tunable_local_umask }, { "upload_max_rate", &tunable_upload_max_rate }, { "download_max_rate", &tunable_download_max_rate }, { NULL, NULL } }; static struct parseconf_str_setting { const char *p_setting_name; const char **p_variable; } parseconf_str_array[] = { { "listen_address", &tunable_listen_address }, { NULL, NULL } }; void parseconf_load_file(const char *path){ FILE *fp = fopen(path, "r"); if (fp == NULL) ERR_EXIT("fopen"); char setting_line[1024] = {0}; while (fgets(setting_line, sizeof(setting_line), fp) != NULL) { if (strlen(setting_line) == 0 || setting_line[0] == '#' || str_all_space(setting_line)) continue; str_trim_crlf(setting_line); parseconf_load_setting(setting_line); memset(setting_line, 0, sizeof(setting_line)); } fclose(fp); } void parseconf_load_setting(const char *setting){ }
其中各个变量是来自于全局变量tunable.c中。
可见有三种类型的参数,下面一个个来进行解析,对于"pasv_enable=YES"一个配置,可能会写成“ pasv_enable=YES”,所以先去掉左控格:
然后需要将key=pasv_enable;value=YES分隔开,这里可以用之前封装的现成的命令:
但也有可能用户没有配置value,如“pasv_enable=”,所以这是不合法的,也应该做下判断:
接下来,就需要拿这个key在上面的配置表格变量中进行搜索,如果找到了,则将其值赋值给该配置变量,如下:
如果说没有找到话,也就说明当前的配置项不是字符串类型的,这时,还得继续去其它类型的配置项中进行搜寻,如下:
而对于布尔类型,可以有以下几种形式:
AA=YES
AA=yes
AA=TRUE
AA=1
所以,首先将value统一成大写:
当遍历boolean类型配置项中也没有找到时,则需要在无符号整形中进行查找,其中无符号整形有两种形式:一种八进制,以0开头,比如"local_umask=077";另一种是十进制,如:"listen_port=21",所以需要做下判断,代码基本类似:
下面则来编译运行一下,在编译运行之前,需要把新加的模块加入到Makefile中:
上面看已经正常通过了,那还是看不出这些配置信息是否正常读取了,所以下面需要写一个测试程序来检验一下:
编译运行:
再次编译运行:
接下来可以应用某些配置项了:
编译运行:
用FTP客户端连接:
可见这样代码就变成可配置的了,另外配置文件的文件名可以做成宏:
加载时直接用该宏:
好了,经过几周的耽搁先完成到这,之后会慢慢恢复学习。