现在我们就可以通过这个编译好的程序来创建一个名为TESTINST的服务器实例并打印其属性信息:
CALL PGM(ILEDEMO/CRTINST) PARM(TESTINST)
程序打印信息如下(可以看到其线程数如我们设置的一样,为32):
我们也可以在IBM Web Administration for i中找到该实例。
但此时该实例仍然无法启动,因为相关的文件路径和配置文件还未创建。我们至少还需要创建/www/testinst/htdocs/index.html/www/testinst/conf/httpd.conf两个文件才能启动该服务器实例。而要使其能够真正工作,还需要下一节介绍的配置文件API的帮助。
* 在某些应用场景中,我们需要将一台机器上的某个HTTP服务器实例迁移到另一台机器上。此时便可以使用这些API在新机器的注册表中添加该实例的信息,然后再将实例的相关文件拷贝到新机器的相应目录下即可。
(二)配置文件API
配置文件API涵盖对配置文件的常用操作,包括打开和关闭配置文件,查找、删除、新增、修改某条指令。一般来说,配置文件API的使用流程如下:
1) 打开配置文件,获得文件句柄供后续API调用。
2) 查找或添加相关指令,获得指令句柄供后续API调用。
3) 根据2)获得的指令句柄修改或删除指令。
4) 根据1)获得的文件句柄关闭配置文件。
*如果程序涉及到改写配置文件的操作,需要在1)中以独占写锁的方式打开配置文件以免与其他程序发生写入冲突。
接下来我将用一个例子介绍这些基本操作的编程实现。假设我们已有一个HTTP实例XMTEST,其配置文件/www/xmtest/conf/httpd.conf包含以下内容:
我们将通过一个程序,将它的监听端口号从11082修改为8196。并且添加一条新指令HotBackup off然后将其删除掉。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "qzhbconf.h"
#include <qusec.h>
#define MAXLEN 100
int main(int args, char* argv[]) {
unsigned char name[MAXLEN];
unsigned int name_len = 0;
unsigned int writelock = 1; //以独占式写锁方式打开配置文件
unsigned int cfg = 0; //配置文件句柄
unsigned int fdata_size = 0;
unsigned char *format = "CFGF0110";
int objHandle = 0; //指令句柄
unsigned char val[MAXLEN] = { 0 };
unsigned int valsize = MAXLEN;
unsigned int valactlen = 0;
char *key = "HotBackup"; //新加指令名
unsigned int keylen = 0;
char *addval = "Off"; //新加指令值
unsigned int addvallen = 0;
char *newval = "*:8196"; //修改指令值
unsigned int newvallen = 0;
unsigned int objtype = 0; //0=directive, 1=scope
int where = 0; //查找指令时,从头开始查找
Qzui_Search_Data_T fdata = { 0 };
Qus_EC_t error_code = { 0 };
if (strlen(argv[1]) >= MAXLEN) {
printf("usage: call lib/prog 'configfilepath'\n");
return 1;
}
strncpy((char *) name, " ", MAXLEN);
strncpy((char *) name, argv[1], strlen(argv[1]));
keylen = sizeof(key);
newvallen = sizeof(newval);
addvallen = sizeof(addval);
name_len = sizeof(name);
fdata_size = sizeof(fdata);
strcpy(fdata.keyword, "Listen"); //修改指令名
error_code.Bytes_Provided=sizeof(error_code);
//打开配置文件
QzuiOpenConfig(name, &name_len, &writelock, &cfg,
(unsigned char*) &error_code);
//查找"Listen"指令,打印它的值
QzuiFindConfigObject(&cfg, &fdata, &fdata_size, format, &objHandle, val,
&valsize, &valactlen, (unsigned char*) &error_code);
printf("Value is %.20s\n", val);
//修改"Listen"指令的值为8196
QzuiChangeConfigObject(&cfg, &objHandle, newval, &newvallen,
(unsigned char*) &error_code);
if (error_code.Bytes_Available == 0)
printf("Change object successfully!\n");
else
printf("Change object failed!\n");
objHandle = 0;
//新加"HotBackup off"指令
QzuiAddConfigObject(&cfg, &objtype, key, &keylen, addval, &addvallen,
&objtype, &where, &objHandle, (unsigned char*) &error_code);
if (error_code.Bytes_Available == 0)
printf("Add object successfully!\n");
else
printf("Add object failed!\n");
//删除"HotBackup off"指令
QzuiRemoveConfigObject(&cfg, &objHandle, (unsigned char*) &error_code);
if (error_code.Bytes_Available == 0)
printf("Delete object successfully!\n");
else
printf("Delete object failed!\n");
//关闭配置文件,释放独占锁
QzuiCloseConfig(&cfg, &writelock, 0, 0, (unsigned char*) &error_code);
if (error_code.Bytes_Available == 0)
printf("Close instance data %s successfully!\n", name);
else
printf("Closing instance data %s failed!\n", name);
return 0;
}
将上述代码上传到步骤(一)所创建的路径/ileexample下(确保qzhbconf.h仍然存在与该目录下),取名为iconf.c。然后用下面的两条命令编译该程序。
CRTCMOD MODULE(ILEDEMO/ICONF) SRCSTMF('/ileexample/iconf.c') TGTCCSID(*JOB)
CRTPGM PGM(ILEDEMO/ICONF) MODULE(ILEDEMO/ICONF) BNDSRVPGM(QHTTPSVR/QZHBCONF)
编译成功后,使用下面的命令执行程序,对目标配置文件进行修改。
CALL PGM(ILEDEMO/ICONF) PARM('/www/xmtest/conf/httpd.conf')
屏幕显示如下:
执行完毕后通过IBM Web Administration for i查看该实例的配置文件,可以看到其端口号已经被成功修改为8196了。
在配置文件API中,目标指令的分为两类,一类是上面例子中的Listen指令这些单行指令,称为directive。另外一类是类似与<Directory />……</Directory>这种有起止范围的指令,称为scope。如果要对第二类指令进行操作,需要对结构体Qzui_Search_Data_T中的int objectType字段进行设置,其中0(默认值)表示directive,1表示scope。
通过上述两类API的使用,我们便可以通过程序来创建、修改、删除HTTP服务器实例并配置其具体的属性。从而达到程序化管理HTTP server的目的。
作者:Xu Meng