间隔了一周时间没写了,由于今年的股势行情貌似不错的样子,对于对股市完全不懂的我也在蠢蠢欲动,所以最近一周业余时间在“不务正业”-----学习炒股。发现学习它其实挺费神的,满脑子都是走势图,而且是神经有点受刺激的感觉,发现这个坚决不能在上班时间去想这事,不然会非常影响情绪,毕境对于普通老百姓来讲经济来源还主要是来源于工作,专职炒股也不适合像我这样笨拙的人,不过可以业余有时间学习学习,入市那还是得非常非常谨慎,所以放下它,接着来学习技术这才是王道,言归正传。

上一次对字符串工具模块进行了封装,这次主要是对"参数配置模块"的封装,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 = ;
int tunable_port_enable = ;
unsigned int tunable_listen_port = ;
unsigned int tunable_max_clients = ;
unsigned int tunable_max_per_ip = ;
unsigned int tunable_accept_timeout = ;
unsigned int tunable_connect_timeout = ;
unsigned int tunable_idle_session_timeout = ;
unsigned int tunable_data_connection_timeout = ;
unsigned int tunable_local_umask = ;
unsigned int tunable_upload_max_rate = ;
unsigned int tunable_download_max_rate = ;
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函数读取的一行字符包含'\n',所以需要将其去掉,可以用我们之前封装的现成方法:

接下来实现命令行的解析函数,在正式解析之前,需要将配置文件中的配置项与配置项变量对应关系表用代码定义出来,如下:

#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[] = {};
while (fgets(setting_line, sizeof(setting_line), fp) != NULL)
{
if (strlen(setting_line) ==
|| setting_line[] == '#'
|| str_all_space(setting_line))
continue; str_trim_crlf(setting_line);
parseconf_load_setting(setting_line);
memset(setting_line, , 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客户端连接:

可见这样代码就变成可配置的了,另外配置文件的文件名可以做成宏:

加载时直接用该宏:

好了,经过几周的耽搁先完成到这,之后会慢慢恢复学习。

Linux网络编程综合运用之MiniFtp实现(六)的更多相关文章

  1. Linux网络编程综合运用之MiniFtp实现(一)

    春节过后,万物复苏,在这元宵佳节的前一天,决定继续开启新年的学习计划,生命在于运动,提高源于学习,在经过漫长的Linux网络编程学习后,接下来会以一个综合的小项目来将所学的知识点综合运用,首先是对项目 ...

  2. Linux网络编程综合运用之MiniFtp实现(四)

    从今天开始,正式进入MiniFtp的代码编写阶段了,好兴奋,接下来很长一段时间会将整个实现过程从无到有一点点实现出来,达到综合应用的效果,话不多说正入正题: 这节主要是将基础代码框架搭建好,基于上节介 ...

  3. Linux网络编程综合运用之MiniFtp实现(九)

    上次中实现了FTP命令的映射来避免很多if....else的判断,这次主要是开始实现目录列表的传输,先看一下目前实现的: 数据连接创建好之后则开始进行目录列表的传输了,而要传输目录列表,首先要将目录列 ...

  4. Linux网络编程综合运用之MiniFtp实现(五)

    转眼兴奋的五一小长假就要到来了,在放假前夕还是需要保持一颗淡定的心,上次中已经对miniFTP有基础框架进行了搭建,这次继续进行往上加代码,这次主要还是将经历投射到handle_child()服务进程 ...

  5. Linux网络编程综合运用之MiniFtp实现(八)

    上节中实现了"USER"和"PASS"命令,如下: 事实上FTP是有很多命令组成的,如果就采用上面的这种方法来实现的话,就会有很多if...else if语句, ...

  6. Linux网络编程综合运用之MiniFtp实现(七)

    上节中实现了配置文件的解析,这节来实现用户登录的验证,首先用客户端来登录vsftpd来演示登录的过程: 接着再连接miniftpd,来看下目前的效果: 接下来实现它,与协议相关的模块都是在ftppro ...

  7. Linux网络编程综合运用之MiniFtp实现(三)

    前面已经对FTP相关的一些概念有了基本的认识,接下来就要进入代码编写阶段了,也是非常兴奋的阶段,在开启这个它之前先对项目需求进行一个梳理,对其我们要实现的FTP服务器是一个什么样子. ftp命令列表 ...

  8. 【深入浅出Linux网络编程】 "开篇 -- 知其然,知其所以然"

    [深入浅出Linux网络编程]是一个连载博客,内容源于本人的工作经验,旨在给读者提供靠谱高效的学习途径,不必在零散的互联网资源中浪费精力,快速的掌握Linux网络编程. 连载包含4篇,会陆续编写发出, ...

  9. 【linux草鞋应用编程系列】_5_ Linux网络编程

    一.网络通信简介   第一部分内容,暂时没法描述,内容实在太多,待后续专门的系列文章.   二.linux网络通信     在linux中继承了Unix下“一切皆文件”的思想, 在linux中要实现网 ...

随机推荐

  1. 玩转CONSUL(2)–分布式锁

    1. 前言 分布式锁的场景,大家应该都有遇到过.比如对可靠性有较高要求的系统中,我们需要做主备切换.这时我们可以利用分布式锁,来做选主动作,抢到锁作为主,执行对应的任务,剩余的实例作为备份 redis ...

  2. CF1277D Let's Play the Words?

    思路: 字符串其实只有0...0, 0...1, 1...0, 1...1四种. 实现: #include <bits/stdc++.h> using namespace std; ]; ...

  3. 【CUDA开发】CUDA开发琐碎知识

    ## 一维矩阵的加 //实现一个一维1*16的小矩阵的加法. //矩阵大小:1*16  //分配一个block,共有16个线程并发.  #include <stdio.h> #includ ...

  4. 配置MySQL,使其与PyCharm相关联

    在配置MySQL和PyCharm时,经常出现这样的错误提示: Connection to base@localhost failed. [08001] Could not create connect ...

  5. 使用Jedis出现Connection refused的解决方案

    1.修改redis.conf配置文件中的   bind 127.0.0.1  为本机外网IP: 2. cluster-enabled yes  设置是否集群操作,如果是的话开启 yes,否的话 设置n ...

  6. Error:(18, 51) java: -source 1.5 中不支持 diamond 运算符 (请使用 -source 7 或更高版本以启用 diamond 运算符)

    问题:主要是因为jdk版本不一样 解决: 方法一:List<String> list=new ArrayList<Stirng>(); 方法二:重新安装jdk8的版本(安装和配 ...

  7. Django时区导致的datetime时间比较报错

    我们使用python 的datetime模块比较Django数据库Datetime字段的时候,可能会出现报错: TypeError: can't compare offset-naive and of ...

  8. RedHat Linux下普通用户无法使用sudo命令的解决方法

    Ref:http://blog.sina.com.cn/s/blog_4aa35ca101012qb6.html 装完linux系统,发现普通用户无法使用sudo 命令, 提示:User1(普通用户) ...

  9. 消息中间件——RabbitMQ(十)RabbitMQ整合SpringBoot实战!(全)

    前言 1. SpringBoot整合配置详解 publisher-confirms,实现一个监听器用于监听Broker端给我们返回的确认请求:RabbitTemplate.ConfirmCallbac ...

  10. C++枚举类型教案

    一.枚举类型的应用场景 只需要将需要的变量值一一列举出来,便构成一个枚举类型. 二.枚举类型的定义 ·定义方式: enum 枚举类型名字{枚举常量表}: ·关键字enum:说明接下来定义的是一个枚举类 ...