To return expected results, you can:
Reduce the number of search terms.
Each term you use focuses the search further.
Check your spelling.
A single misspelled or incorrectly typed term can change your result.
Try substituting synonyms for your original terms.
For example, instead of searching for "java classes", try "java training"
Did you search for an IBM acquired or sold product ?
If so, follow the appropriate link below to find the content you need.
在管理
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
的目的。
作者:Xu Meng