Technical Blog Post
Abstract
通过API管理IBM HTTP server for i
Body
在管理HTTP server时,相对于基于图形界面的IBM Web Administration for i工具,开发人员有时候也需要在自己的程序中控制和维护HTTP server的运行。而IBM也提供了这样一些API方便开发人员根据自己的需求进行调用。本文将通过几个简单的示例,展示使用这些API进行程序开发的大致流程。
* 所有本文涉及到的API均可在IBM i信息中心找到更详尽的介绍,具体目录为:
IBM i信息中心 > 联网 > HTTP Server > Programming > API
或直接访问下面的链接:
(一)服务器实例APIs
这一类API专注于服务器实例的管理。包括创建和删除服务器实例、列出所有服务器实例、获取和设置服务器实例的基本属性等等。
在这些程序中,大多涉及到结构体Qzui_Inst_Data_T的使用。该结构体对应于单个服务器实例的一些基础属性,例如自动启动、线程数、CCSID、配置文件路径等等。通过设置和修改该结构体,便可以达到配置服务器基本属性的目的。
下面是通过API创建一个新的HTTP server实例的范例代码:
#include <stdio.h>
#include <string.h>
#include "qzhbconf.h"
#include <qusec.h>
void print_INSD0110(Qzui_Inst_Data_T* data) {
printf("Autostart: %10.10s\n", data->autostart);
printf("Threads: %d\n", data->maxthreads);
printf("CCSID: %d\n", data->ccsid);
printf("Outgoing table name: %10.10s\n", data->outgoing_e2a_table);
printf("Outgoing table library: %10.10s\n", data->outgoing_e2a_lib);
printf("Incoming table name: %10.10s\n", data->incoming_a2e_table);
printf("Incoming table library: %10.10s\n", data->incoming_a2e_lib);
printf("Config file (full path): %30.30s\n", data->configfile);
printf("Server root path: %20.20s\n", data->serverroot);
}
int main(int args, char* argv[])
{
char *name = argv[1];
Qzui_Inst_Data_T data;
unsigned int data_len;
unsigned char *format = "INSD0110";
unsigned int buf_actlen;
unsigned int running;
Qus_EC_t error_code;
strcpy(data.autostart, "*NO ");
data.maxthreads = 32; //设置线程数为32
data.ccsid = 0;
strcpy(data.outgoing_e2a_table, "*GLOBAL ");
strcpy(data.outgoing_e2a_lib, " ");
strcpy(data.incoming_a2e_table, "*GLOBAL ");
strcpy(data.incoming_a2e_lib, " ");
strcpy(data.configfile, "conf/httpd.conf");
strcpy(data.serverroot, strcat("/www/", argv[1]));
data_len = sizeof(data);
//创建HTTP实例
QzuiCreateInstance(name, &data, &data_len, format, (unsigned char*) &error_code);
if (error_code.Bytes_Available == 0)
printf("Creation of %s succeed!\n", name);
else
printf("Creation of %s failed!\n", name);
//获取该HTTP实例的基本属性
QzuiGetInstanceData(name, &inst_data, &data_len, formatINSD,
&buf_actlen, &running, (unsigned char*) &error_code);
print_INSD0110(&inst_data);
if (error_code.Bytes_Available == 0)
printf("Instance data %s has been retrieved!\n", name);
else
printf("Failed to get instance %s data!\n", name);
return 0;
}
将上述代码保存后上传到IBM i机器上的某个路径下,例如/ileexample/crtinst.c
为了使下面的编译能够成功,我们还需要在当前目录下为其创建一个符号链接使编译器能够正确找到所需的头文件。
通过QSH命令进入到QShell环境,然后进入保存源文件的目录并建立符号链接:
cd /ileexample
ln -s /QSYS.LIB/QHTTPSVR.LIB/H.FILE/QZHBCONF.MBR ./qzhbconf.h
然后我们可以通过ls -l命令检查链接是否成功
我们看到qzhbconf.h -> /QSYS.LIB/QHTTPSVR.LIB/H.FILE/QZHBCONF.MBR这样的信息,证明链接已经生效。
现在我们便可以使用下面两条命令将crtinst.c编译为可执行文件。
CRTCMOD MODULE(ILEDEMO/CRTINST) SRCSTMF('/ileexample/crtinst.c') TGTCCSID(*JOB)
CRTPGM PGM(ILEDEMO/CRTINST) MODULE(ILEDEMO/CRTINST) BNDSRVPGM(QHTTPSVR/QZHBCONF)
现在我们就可以通过这个编译好的程序来创建一个名为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的目的。
UID
ibm11145248