18.3.1 SHTTPD命令行解析的实现
SHTTPD可以根据用户的命令行输入进行服务器的配置。在解析用户输入的参数后,对默认参数进行修改来启动服务器。
1.配置文件的结构
服务器SHTTPD的结构为conf_opts,主要包含CGI根路径、网络资源根路径、配置文件名、默认文件名、服务器侦听端口、最大客户端、超时时间及初始化线程数量。原型如下:
struct conf_opts{
char CGIRoot[128]; /*CGI跟路径*/
char DefaultFile[128]; /*默认文件名称*/
char DocumentRoot[128]; /*根文件路径*/
char ConfigFile[128]; /*配置文件路径和名称*/
int ListenPort; /*侦听端口*/
int MaxClient; /*最大客户端数量*/
int TimeOut; /*超时时间*/
int InitClient; /*初始化线程数量*/
};
2.命令行解析结构
配置文件的优先级为配置文集>命令行配置>默认配置,在初始化时,服务器的默认配置为CGI根路径为“/usr/local/var/www/cgi-bin/”,默认文件名为index.html,根文件路径为“/usr/local/var/www/”,配置文件名为“/etc/SHTTPD.conf”,最大客户端数量为4,侦听端口为8080,超时时间为3秒,初始化线程数量为2,代码如下:
struct conf_opts conf_para={
/*CGIRoot*/ "/usr/local/var/www/cgi-bin/",
/*DefaultFile*/ "index.html",
/*DocumentRoot*/ "/usr/local/var/www/",
/*ConfigFile*/ "/etc/SHTTPD.conf",
/*ListenPort*/ 8080,
/*MaxClient*/ 4,
/*TimeOut*/ 3,
/*InitClient*/ 2
};
q 短选项的配置为c:d:f:ho:l:m:t::
static char *shortopts = "c:d:f:ho:l:m:t:";
q 长选项的配置如下:
static struct option longopts[] = {
{"CGIRoot", required_argument, NULL, 'c'},
{"ConfigFile", required_argument, NULL, 'f'},
{"DefaultFile", required_argument, NULL, 'd'},
{"DocumentRoot", required_argument, NULL, 'o'},
{"ListenPort", required_argument, NULL, 'l'},
{"MaxClient", required_argument, NULL, 'm'},
{"TimeOut", required_argument, NULL, 't'},
{"Help", no_argument, NULL, 'h'},
{0, 0, 0, 0},
};
3.命令行解析代码
命令行解析函数利用getopt_long()函数,查找用户输入的长选项和短选项配置,获取其配置参数。对于成功匹配的选项,如果有输入参数,则输入参数为optarg,可以通过这个指针对输入参数进行处理,进一步获得最终的值。对于输入参数为字符串的,直接将字符串复制;对于输入参数为整型的需要使用字符串到整型的转换函数,获得最终值。
static char *l_opt_arg;
static int Para_CmdParse(int argc, char *argv[])
{
int c;
int len;
int value;
/*遍历输入参数,设置配置参数*/
while ((c = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1)
{
switch (c)
{
case 'c': /*CGI根路径*/
l_opt_arg = optarg;
if(l_opt_arg && l_opt_arg[0]!=':'){
len = strlen(l_opt_arg);
memcpy(conf_para.CGIRoot, l_opt_arg, len +1);
/*更新CGI根路径*/
}
break;
case 'd': /*默认文件名称*/
l_opt_arg = optarg;
if(l_opt_arg && l_opt_arg[0]!=':'){
len = strlen(l_opt_arg);
memcpy(conf_para.DefaultFile, l_opt_arg, len +1);
/*更新默认文件名称*/
}
break;
case 'f': /*配置文件名称和路径*/
l_opt_arg = optarg;
if(l_opt_arg && l_opt_arg[0]!=':'){
len = strlen(l_opt_arg);
memcpy(conf_para.ConfigFile, l_opt_arg, len +1);
/*更新配置文件名称和路径*/
}
break;
case 'o': /*根文件路径*/
l_opt_arg = optarg;
if(l_opt_arg && l_opt_arg[0]!=':'){
len = strlen(l_opt_arg);
memcpy(conf_para.DocumentRoot, l_opt_arg, len +1);
/*更新根文件路径*/
}
break;
case 'l': /*侦听端口*/
l_opt_arg = optarg;
if(l_opt_arg && l_opt_arg[0]!=':'){
len = strlen(l_opt_arg);
value = strtol(l_opt_arg, NULL, 10);/*转化字符串为整型*/
if(value != LONG_MAX && value != LONG_MIN)
conf_para.ListenPort = value; /*更新侦听端口*/
}
break;
case 'm': /*最大客户端数量*/
l_opt_arg = optarg;
if(l_opt_arg && l_opt_arg[0]!=':'){
len = strlen(l_opt_arg);
value = strtol(l_opt_arg, NULL, 10); /*转化字符串为整型*/
if(value != LONG_MAX && value != LONG_MIN)
conf_para.MaxClient= value; /*更新最大客户端数量*/
}
break;
case 't': /*超时时间*/
l_opt_arg = optarg;
if(l_opt_arg && l_opt_arg[0]!=':'){
printf("TIMEOUT/n");
len = strlen(l_opt_arg);
value = strtol(l_opt_arg, NULL, 10);/*转化字符串为整型*/
if(value != LONG_MAX && value != LONG_MIN)
conf_para.TimeOut = value; /*更新超时时间*/
}
break;
case '?': /*错误参数*/
printf("Invalid para/n");
case 'h': /*帮助*/
display_usage();
break;
}
}
return 0;
}