Transcript Document

Linux开发基础
Development Foundation on Linux OS
方贤进, Ph.D & Associate Prof.
安徽理工大学 计算机科学与工程学院
Outline
 Shell programming on Linux OS
 GNU C/C++ programming
 CGI programming in C/C++ language
 Perl programming
 CGI programming in Perl language
2
Section 2
GNU C/C++ programming
3
What is GNU?
 The GNU operating system is a
complete free software
system, upward-compatible
with Unix. GNU stands for
“GNU's Not Unix”. Richard
Stallman made the Initial
Announcement of the GNU
Project in September 1983.
Source:
http://www.gnu.org/gnu/initialannouncement.html
4
What is Free Software?
 “Free software” is a matter of liberty, not price. To understand the
concept, you should think of “free” as in “free speech”, not as in
“free beer”.
 Free software is a matter of the users' freedom to run, copy,
distribute, study, change and improve the software. More precisely,
it refers to four kinds of freedom, for the users of the software:
 The freedom to run the program, for any purpose (freedom 0).
 The freedom to study how the program works, and adapt it to your
needs (freedom 1). Access to the source code is a precondition for
this.
 The freedom to redistribute copies so you can help your neighbor
(freedom 2).
 The freedom to improve the program, and release your
improvements to the public, so that the whole community benefits
(freedom 3). Access to the source code is a precondition for this.
5
What is gcc?
 GCC, the GNU Compiler Collection.
 The GNU Compiler Collection includes front
ends for C, C++, Objective-C, Fortran, Java,
and Ada, as well as libraries for these
languages (libstdc++, libgcj,...). GCC was
originally written as the compiler for the GNU
operating system. The GNU system was
developed to be 100% free software, free in
the sense that it respects the user's freedom.
Source: http://gcc.gnu.org
6
2.1 GNU C/C++编译器的使用
gcc通过扩展名来判断文件的类型,从而确定用何种方式处理该文件
后缀名
.c
.C/.cc/.cxx
说明
C语言源代码文件
C++源代码文件
.h
程序所包含的头文件
.i
已经预处理过的C语言源代码文件
.ii
已经预处理过的C++源代码文件
.m
Objective-C语言源代码文件
.s
汇编语言源代码文件
.S
经过预编译的汇编语言源代码文件
.a/.so
.o
编译后的库代码
编译后的目标文件
7
2.1 GNU C/C++编译器的使用
gcc 编译器选项和参数
参数
含义
-o <file>
Place the output into <file>
-c
Compile and assemble, but do not link
-ggdb
Produce debugging information for use by GDB.
-O
the compiler tries to reduce code size and execution time,
without performing any optimizations that take a great deal of
com-pilation time.
-g
Produce debugging information in the operating system's native
format. GDB can work with this debugging information.
-I <dir>
Add the directory dir to the list of directories to be searched
for header files. Directories named by -I are searched before
the
-L <dir>
Search the library named library when linking
8
2.1 GNU C/C++编译器的使用
1、直接通过编译生成目标代码可执行文件:
$gcc hello.c –o hello
2、如果一个程序包含有多个源文件,则也可直接生成目标代码:
void f1()
{
printf(“%s\n”, "function 1");
}
void f2()
{
printf("%s\n", "function 2");
}
main()
{
f1();
f2();
}
$gcc f1.c f2.c main.c –o main
9
 Linux上广泛使用的C语言编译器是GNU C编译器,GNU C建
立在自由软件基金会的编程许可证的基础上,可以自由发
布。在Linux下,一个完整的C语言开发环境到少包括以下
三个组成部分:
 函数库glibc
(在/usr/lib和/lib目录中)
 编译器gcc
 系统头文件glibc_header (*.h)
 glibc是构成一个完整的C语言开发环境所必不可少的组成
部分,也是Linux下C语言的主要函数库。
 glibc_header中包含了系统编译源代码所需要的声明文件,
如果缺少系统头文件,很多用到系统功能的C程序将无法
编译。(包含在/usr/include/及其子目录中)
10
2.2 GNU C/C++函数库
 定义:是一些预先编译好的函数的集合,那些函数都是按照可再使用
的原则编写的。它们通常是一组相互关联的用来完成某项常见工作的
函数构成(比如c库里面的标准输入输出函数、时间函数和数学函数
等)。
 函数库中的函数可以通过连接程序与应用程序进行连接,而不必在每
次开发程序时都对这些通用的函数进行编译。
 不同类型的应用程序将会使用不同的函数库。如数学应用将使用数学
库libm(/usr/lib/libm.a, /usr/lib/libm.so),标准的C库
libc(/usr/lib/libc.a,/usr/lib/libc.so)。
注意:*.h只是对函数的声明(declaration),函数的定义是在具体的
函数库中
11
 所有的程序都将使用标准的C函数库libc,该库中包含了内存管理或
输入输出操作的基本函数,这些库都存放在/usr/lib或/lib这些系统
公用的目录中,系统中的任何用户都可以利用这些库。
注:用户可以自己定义自己的函数库!
 库可以有三种使用的形式:
 静态库(*.a):代码在编译时就已连接到开发人员开发的应用程序
中。静态库在程序编译时会被连接到目标代码中,程序运行时将
不再需要该静态库
 共享库(shared object,以*.so作为后缀):只是在程序开始运行
时才载入,在编译时,只是简单地指定需要使用的库函数。
 动态库:是共享库的另一种变化形式,也是在程序运行时载入,
使用的库函数不是在程序运行开始,而是在程序中的语句需要使
用该函数时才载入。类似于windows OS中的DLL文件。
12
共享库的生成方法
 动态库可以在程序运行期间释放动态库所占用的内存,腾
出空间供其他程序使用。
 由于共享库和动态库并没有在程序中包括库函数的内容,
只是包含了对库函数的引用,因此代码的规模比较小。
生成用户共享库的方法:
 gcc test1.c test2.c test3.c -fPIC -shared -o
libtest.so
使用自定义的库进行编译、连接
 gcc test.c -L. libtest.so -o test
13
静态库的生成方法
 静态库的生成方法:
Step1: 编译而不连接
 $ gcc test1.c -c -o test1.o
 $ gcc test2.c -c -o test2.o
 $ gcc test3.c -c -o test3.o
Step2: 生成ar命令生成静态库
$ar rcs libtest.a test1.o test2.o test3.o
Step3: 使用静态库编译和连接,生成可执行文件
 gcc test.c -L. libtest.a -o test
14
 系统中可用的库都存放在/usr/lib和/lib目录中。库文件名
由前缀lib和库名以及后缀组成。根据库的类型不同,后
缀名也不一样。
 共享库名的格式:库的名称.so.主版本号.次版本号
 静态库名的格式:库的名称.a
例如:
libm.so.5
libm.a
libc.a
数学共享库的标识字符为m,版本号为5
静态数字库
为标准C库
15
函数库存放的标准目录:
 /lib
系统必备共享库
 /usr/lib 标准共享库和静态库
 /usr/i486-linux-libc5/lib
libc5兼容性函数库
 /usr/X11R6/libX11R6的函数库
 /usr/local/lib 本地函数库
16
头文件存放的目录:
 /usr/include 系统头文件
 /usr/local/include 本地头文件
共享库及相关配置文件在/etc目录中,其中:
ld.so.conf 包含共享库的搜索位置
ldconfig
共享库管理工具,一般在更新了共享库之后要
运行该命令
ldd 可查看可执行文件所使用的共享库
e.g. #ldd test, 查看test文件的共享库依赖
17
2.4 gcc的基本用法和选项
 gcc的一般用法为:
gcc [options] <filenames>
 其常用格式为:
gcc [-c][-S][-E][-s][-g]
[-static][-shared][-rdynamic]
[-Idir …][-Ldir …][-lmylib] [-Olevel]
[-x Language] [-Dmacro[=defn] …]
[-Umacro][-mmachine-option …]
[-o out_file] infile …
18
 -c:编译后仅输出*.o型的目标文件,而不连接生成可执
行程序
 -S:编译后仅生成汇编语言文件*.s,但不生成目标文件
和可执行代码
 -s:生成可执行文件时,删除符号表和重定位信息。生成
成品软件时使用
 -E:在预处理过程后结束,不进行编译和连接,也不生成
可执行代码
 -g:在可执行文件中加入调试信息,便于程序的调试
19
 -o outfile:指定输出文件名。若不指定则生成a.out
 -Idir:将目录dir添加到头文件搜索范围
 -lmylib:连接时搜索库libmylib.a
e.g. $gcc test.c –ltest –o test4
则搜索libtest.a库进行连接
 -Ldir:将目录dir添加到库文件搜索范围
 -O[L]:编译时进行优化。L为优化级别,分别0~3和s。
生成最终产品时使用
 -static:禁止使用共享库(动态连接库)
 -shared:生成共享库
 -rdynamic:连接时使用共享库
20
程序示例
1. C程序
设有一个文件名为hello.c的程序,其内容为:
#include <stdio.h>
main()
{
printf(“Hello World!\n”);
}
21
编译和执行步骤
 编译
 gcc hello.c
#生成可执行程序a.out,或
 gcc –o hello hello.c #生成可执行程序hello
 运行
 ./a.out
或
 ./hello
 输出结果
Hello World!
22
 GCC 可同时用来编译 C 程序和 C++ 程序。一般来说,C
编译器通过源文件的后缀名来判断是 C 程序还是 C+ + 程
序。
 在 Linux 中,C 源文件的后缀名为 .c,而 C++ 源文件的
后缀名为 .C 或 .cc。 但是,gcc 命令只能编译 C++ 源文
件,而不能自动和 C++ 程序使用的库连接。因此,通常
使用 g++ 命令来完成 C++ 程序的编译和连接,该程序会
自动调用 gcc 实现编译。
 假设我们有一个如下的 C++ 源文件(hello.C):
23
 2 一个c++版的Hello World程序,其文件名为hello.C,
内容为:
#include <iostream.h>
main (void)
{
cout << "Hello, World!" << endl;
}
24
编译方法
 使用c++或g++来编译:
 g++ hello.C
#生成可执行程序a.out
 c++ –o hello hell.C #生成可执行程序hello
 g++ –s -o Hello hello.C
#生成删除符号表的可执
行程序Hello 发布的时候用
 或使用gcc并指定库文件来编译c++程序:
 gcc –c hello.C
#生成目标文件hello.o
 gcc –o h hello.C –lstdc++ #指定标准c++库,生成可
执行程序h
25
例:假设有 两个源文件 main.c 和 factorial.c ,现在要编译
生成一个计算阶乘的程序。
/*程序清单main.c*/
#include <stdio.h>
#include <stdlib.h>
int factorial (int n);
int main (int argc, char **argv)
{
int n;
if (argc < 2)
{
printf ("Usage: %s n\n", argv [0]);
return -1;
}
else
{
n = atoi (argv[1]);
printf ("Factorial of %d is %d.\n", n, factorial (n));
}
return 0;
}
26
/*程序清单factorial.c*/
#include <stdio.h>
#include <stdlib.h>
int factorial (int n)
{
if (n <= 1)
return 1;
else
return factorial (n - 1) * n;
}
27
 编译
 $ gcc –o factorial main.c factorial.c
 运行
 $ ./factorial 5
 结果
 Factorial of 5 is 120
28
关于头文件
 在标准C中有两种形式的头文件使用方式:
 #include
<headfile.h>
 #include
“headfile.h”
 区别:
 #include <headfile.h>型头文件搜索范围为默认位置
/usr/include,
 #include“headfile.h”型头文件的搜索位置为当前目录,
在Linux的GNU C中,若当前目标不存在headerfile.h,
则也会到默认位置去搜索。
29
2.5 make与Makefile
2.5.1
2.5.2
2.5.3
2.5.4
make的用法简介
Makefile文件
make的用法简介
Makefile示例
30
2.5.1 make的用法简介
make命令会根据Makefile的内容对项目进
行管理。make能自动确定哪一个模块被修
改了,然后再进行统一、无遗漏的编译。
最后实现项目或软件包的管理工作。
make的用法为:
 make [-f filename] [options] [targets]
31
make的常用参数
 -C dir:在读Makefile或做任何操作前切换目录,一般用
于对目录的递归搜索
 -d:显示调试信息
 -f file:指定file文件作为Makefile,而非使用默认的
makefile或Makefile
 -I dir:指定Makefile搜索目录
 -k:默认情况下make在遇到错误将终止执行,-k可以让
在出现错误时工作的尽量长一些,以便观察分析
 -n:让make在不真正编译的情况下列出将执行的步骤
32
2.5.2 Makefile文件
 Makefile文件的内容是描述项目或软件(包)中的模块
之间的相互依赖关系以及目标文件、可执行程序产生时要
执行的命令等。
 Makefile文件可认为是一个工程规划文件。
 传统Unix使用的是Makefile,现在也可使用makefile
33
Makefile文件包含的5类内容
 显式规则:显式告诉make如何编译或构造一个目标
 隐式规则:隐式的通过变量或规则告诉make如何编译或构
造一个目标
 变量定义:在Makefile中可以像shell编程一样定义和使
用变量
 命令:定义完成某任务所使用的shell命令
 注释:#开始的部分。意义同shell编程
34
规则的定义
 规则中的项目定义必须从最左边开始,一个规则中的第二
行以后的行必须以tab健开始。
 规则的格式如下:
 targets :prerequisites
commands
或
 targets :prerequisites;commands
commands
35
Makefile文件中的常用符号
 $@:目标名
 $*:删除了后缀的目标名
 $%:当目标是库文件时,目标内的成员名。
 例如目标x.a(y.o)的目标名为x.a,成员名为y.o
 $^:由空格分隔的目标中所有成员
 $?:目标中的变化成员
 $<:当前目标的第一个相关成员名
36
Makefile文件中的符号“%”
 %可以理解为统配符。可使用它定义或重定义模式规则。
 例如:
%.o:%.c
gcc –c $<
 定义了一个规则:
 所有目标文件*.o依赖C语言源程序*.c;
 且生成方法为gcc -c $< 。
37
Makefile文件中的符号“=”或“:=”
 符号“=”或“:=”用于修改已经定义的变量或在已定义变
量的基础上定义新变量。
 例如
已知:var1 = a.c b.c c.c
则
var2 = $(var1:.c=.o)
定义
var2 =a.o b.o c.o
而
var1 += d.c
重定义var1,其值为var1 = a.c b.c c.c d.c
38
“:=”与“=”的区别
 “:=”与“=”是有区别的。
 当使用“=”时,变量将做递归或扩展
 “:=”只作简单替换。
39
2.5.3 make的用法简介
 Makefile文件内容可包含多个目标,可以通过make obj
的方式指定处理的目标,若不指定则默认为第一个。
 为了方便的使用Makefile文件对整个项目进行编译,可在
Makefile文件内设一个代表整个项目的目标,一般为all。
40
Makefile中的常用目标
 有时为了对项目进行管理还要设置有clean、install和
uninstall目标:
• clean:用于对项目环境进行准备,清除已经
生成的目标文件等以便重新编译;
• install:用于对整个项目的成品进行安装;
• uninstall:则是用于对安装的项目进行卸载。
41
Makefile示例1
//文件f1.c的内容
f1(int arg)
{
printf(”F1: you passed: %d\n”,arg);
}
//文件f2.c的内容:
f2(char *arg)
{
printf(”F2: you passed: %s\n”,arg);
}
//文件f3.c的内容
#include <stdio.h>
main()
{
fprintf(stderr,”Begine:\
n”);
f1(15);
f2(”Hello World!”);
fprintf(stderr,”:End\n”);
exit(0);
}
42
Makefile示例2
 它们之间的关系如下图
43
项目编译过程分析
 按照gcc的工作过程,对模块的编译和链接过程可分为:
 (1)生成目标代码

gcc -c f1.c

gcc -c f2.c

gcc -c f3.c
(2) 生成可执行程序
 gcc -o f f1.o f2.o f3.o
44
Makefile内容
f: f1.o f2.o f3.o
gcc -o f f1.o f2.o f3.o
f1.o: f1.c
gcc –c f1.c
f2.o: f2.c
gcc –c f2.c
f3.o: f3.c
gcc –c f3.c
45
Makefile的使用
 有了Makefile文件,可以使用make命令对此项目进行编
译。编译方法为:
 make
 或 make f
 若要编译单个项目,比方说f1.o,可以使用以下方法:
 make f1.o
46
增加all、clean和install目标的Makefile
all : f
#make all to build f
f : f1.o f2.o f3.o
gcc -o f f1.o f2.o f3.o
f1.o: f1.c
gcc –c f1.c
f2.o: f2.c
gcc –c f2.c
f3.o: f3.c
gcc –c f3.c
clean:
rm –f f?.o
#make all and install f to /usr/bin with permission 755
install: all
install –m 755 /usr/local/bin
47
GDB调试工具
 GDB 是一个强大的命令行调试工具。大家知道命令行的
强大就是在于,其可以形成执行序列,形成脚本。UNIX
下的软件全是命令行的,这给程序开发提供了极大的便利,
命令行软件的优势在于,他们可以非常容易的集成在一起,
使用几个简单的已有工具的命令,就可以做出一个非常强
大的功能。
48
GDB概述
 GDB 是 GNU 开源组织发布的一个强大的 UNIX 下调试
程序工具。或许各位比较喜欢那种图形界面方式的,像
VC,BCB 等 IDE 的调试,但如果你是在 UNIX 平台下作
软件,你会发现 GDB 这个调试工具有比 VC,BCB 的图
形化调试器更强大的功能。所谓“寸有所长,尺有所短”
就是这个道理。
49
GDB功能
 一般来说,GDB 主要帮助你完成下面四个方面的功能:
 1、启动你的程序,可以按照你自定义的要求随心所欲的
运行程序。
 2、可以让调试程序在你所指定的位置的断点处停止。
 3、当程序停止时,可以检查此时你的程序中所发生的事
情。
 4、动态的改变你程序的执行环境。
 从上面看来,GDB 和一般的调试工具没有什么两样,基
本上也是完成这些功能,不过在细节上,你会发现 GDB
这个调试工具的强大,大家可能习惯图形化的调试工具,
但有时候,命令行的调试工具却有着图形化工具所不能完
成的功能。
50
 gdb不仅允许用户在运行程序时显示源代码,而且在调试
过程中允许在预设的断点处暂停程序的运行,显示变量的
内容。
 在可以使用 gdb 调试程序之前,必须使用 -g 选项编译源
文件。可在 makefile 中如下定义 CFLAGS 变量:
CFLAGS = -g
 运行 gdb 调试程序时通常使用如下的命令:
#gdb progname
51
 在gdb 提示符处键入help,将列出命令的分类,主要的
分类有:
 aliases:命令别名
 breakpoints:断点定义
 data:数据查看
 files:指定并查看文件
 internals:维护命令
52
 running:程序执行
 stack:调用栈查看
 statu:状态查看
 tracepoints:跟踪程序执行
键入 help 后跟命令的分类名,可获得该类命令的详细清单。
53
gdb 的常用命令
break NUM
bt
clear
在指定的行上设置断点。
显示所有的调用栈帧。该命令可用来显示函数的调用顺序
删除设置在特定源文件、特定行上的断点。其用法为:clear
FILENAME:NUM
continue
继续执行正在调试的程序。该命令用在程序由于处理信号或断点而
导致停止运行时
display EXPR 每次程序停止后显示表达式的值。表达式由程序定义的变量组成
file FILE
装载指定的可执行文件进行调试
help NAME
显示指定命令的帮助信息
quit
退出gdb。也可以输入'C-d'来退出gdb
run
执行载入后的要调试的程序。可以输入参数
set
修改变量值。格式如下:set varible=value
step
单步执行,进入遇到的函数
next
单步执行,不进入函数调用,即视函数调用为普通语句
54
info break 显示当前断点清单,包括到达断点处的次数等
info files 显示被调试文件的详细信息
info func 显示所有的函数名称
info local 显示当函数中的局部变量信息
info prog 显示被调试程序的执行状态
info var
显示所有的全局和静态变量名称
kill
终止正被调试的程序
list
显示源代码段
make
next
在不退出 gdb 的情况下运行 make 工具
在不单步执行进入其他函数的情况下,向前执行一行源代码
print EXPR 显示表达式 EXPR 的值
注意:在使用gdb调试程序前,必须使用gcc –g对源程序进行编
译。
55
GDB调试示例
 源程序:test.c











1 #include <stdio.h>
2
3 int func(int n)
4{
5
int sum=0,i;
6
for(i=0; i<n; i++)
7
{
8
sum+=i;
9
}
10
return sum;
11 }
56












14 main()
15 {
16
int i;
17
long result = 0;
18
for(i=1; i<=100; i++)
19
{
20
result += i;
21
}
22
23
printf("result[1-100] = %d \n", result );
24
printf("result[1-250] = %d \n", func(250) );
25 }
57
编译
 gcc -g test.c -o test
58
使用 GDB 调试:








gdb test ——————启动 GDB
GNU gdb ****
Copyright **** Free Software Foundation, Inc.
GDB is free software, covered by the GNU General
Public License, and you are
welcome to change it and/or distribute copies of it
under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show
warranty" for details.
This GDB was configured as "i386-suse-linux"...
59











(gdb) list ——————从第一行列出源码
1
#include <stdio.h>
2
3
int func(int n)
4
{
5
int sum=0,i;
6
for(i=0; i<n; i++)
7
{
8
sum+=i;
9
}
10
return sum;
60










(gdb) ——————直接回车表示,重复上一次命令
11 }
12
13
14 main()
15 {
16
int i;
17
long result = 0;
18
for(i=1; i<=100; i++)
19
 20
{
result += i;
61












(gdb) break 16 ——————设置断点,在源程序第 16 行处。
Breakpoint 1 at 0x8048496: file tst.c, line 16.
(gdb) break func ——————设置断点,在函数 func()入口处。
Breakpoint 2 at 0x8048456: file tst.c, line 5.
(gdb) info break ——————查看断点信息。
Num Type
Disp Enb Address What
1 breakpoint keep y 0x08048496 in main at tst.c:16
2 breakpoint keep y 0x08048456 in func at tst.c:5
(gdb) run
——————运行程序
Starting program: /home/hchen/test/tst
Breakpoint 1, main () at tst.c:17 ——————在断点处停住。
17
long result = 0;
62













(gdb) next
——————单条语句执行。
18
for(i=1; i<=100; i++)
(gdb) n
20
result += i;
(gdb) n
18
for(i=1; i<=100; i++)
(gdb) n
20
result += i;
(gdb) continue ——————继续运行程序
Continuing.
result[1-100] = 5050 ——————程序输出。
Breakpoint 2, func (n=250) at tst.c:5
5
int sum=0,i;
63








(gdb) n
6
for(i=1; i<=n; i++)
(gdb) print i ——————打印变量 i 的值。
$1 = 134513808
(gdb) n
8
sum+=i;
(gdb) n
6
for(i=1; i<=n; i++)
64










(gdb) p sum
$2 = 1
(gdb) n
8
sum+=i;
(gdb) p i
$3 = 2
(gdb) n
6
for(i=1; i<=n; i++)
(gdb) p sum ——————p 是 print 的缩写
$4 = 3
65









(gdb) bt ——————查看函数堆栈
#0 func (n=250) at tst.c:5
#1 0x080484e4 in main () at tst.c:24
#2 0x400409ed in __libc_start_main () from
/lib/libc.so.6
(gdb) finish ——————推出函数
Run till exit from #0 func (n=250) at tst.c:5
0x080484e4 in main () at tst.c:24
24
printf("result[1-250] = %d \n", func(250) );
Value returned is $6 = 31375
66




(gdb) continue
Continuing.
result[1-250] = 31375 ——————程序输出。
Program exited with code 027.——————程序退出,
调试结束。
 (gdb) quit
——————退出 gdb
67
Section 3
CGI programming in GNU C/C++ language
68
What is CGI?
简单的说来,CGI(Common Gateway Interface)是
用来沟通HTML表单和服务器端程序的接口
(interface)。说它是接口,也就是说CGI并不是
一种语言,而是可以被其他语言所应用的一个规范集。
理论上讲,你可以用任何的程序语言来编写CGI程序,
只要在编程的时候符合CGI规范所定义的一些东西就
可以了。
69
Why c/c++ language is used for CGI
programming?
本部分的目的就是初步了解一下CGI编程的概念。事实上,现
在的一些主流的服务器端脚本编程语言如ASP,PHP,JSP等,
都基本上具备了CGI编程的大部分的功能,但他们在使用上的,
确实是比无论用什么语言进行CGI编程都要容易的多。所以在
进行服务器端编程的时候,一般都会首先考虑使用这些脚本编
程语言。只有当他们也解决不了,比如要进行一些更为底层的
编程的时候,才会用到CGI。
另外,由于C语言在平台无关性上表现不错(几乎在任何的系
统平台下都有其相应编译器),而且对大多数程序员而言都算
得上很熟悉(不像Perl),因此,C是CGI编程的首选语言之
一。
70
CGI表单处理程序的原理
对于使用了属性“method=get”的表单(或者没有method属
性,这时候get是其缺省值),CGI定义为:当表单被发送到
服务器断后,表单中的数据被保存在服务器上一个叫做
QUERY_STRING的环境变量中。这种表单的处理相对简单,
只要读取环境变量就可以了。这一点对不同的语言有不同的做
法。在C语言中,你可以用库函数getenv(定义在标准库函数
stdlib中)来把环境变量的值作为一个字符串来存取。你可以
在取得了字符串中的数据后,运用一些小技巧进行类型的转换,
这都是比较简单的了。在CGI程序中的标准输出(output)
(比如在C中的stdout文件流)也是经过重定义了的。它并没
有在服务器上产生任何的输出内容,而是被重定向到客户浏览
器。这样,如果编写一个C的CGI程序的时候,把一个HTML
文档输出到它的stdout上,这个HTML文档会被在客户端的浏
览器中显示出来。这也是CGI程序的一个基本原理。
71
CGI表单处理程序的原理
对使用了属性“method=get”的表单(或者没有method)的
CGI程序处理实例:
通过CGI程序实现简单的乘法运算:
http://infosec.aust.edu.cn/~xjfang/c3.html
72
CGI表单处理程序的原理
下面我们来考虑另外一种表单传送方法:POST。假设我们要
实现的任务是这样的:把表单中客户输入的一段文本内容添加
到服务器上的一个文本文件的后面。这可以看作是一个留言版
程序的雏形。显然,这个工作是无法用JavaScript这种客户端
脚本来实现,也算得上真正意义上的CGI程序了。
GET对于表单的长度是有限制的,而POST则不然,这也是在
这个任务中选用POST方法的主要原因。但相对的,对GET的
处理速度就要比POST快一些。
73
CGI表单处理程序的原理
在CGI的定义中,对于POST类型的表单,其内容被送到CGI程
序的标准输入(在C语言中是stdin),而被传送的长度被放在
环境变量CONTENT_LENGTH中。因而我们要做的就是,在
标准输入中读入CONTENT_LENGTH长度的字符串。从标准
输出读入数据听起来似乎要比从环境变量中读数据来的要容易
一些,其实则不然,有一些细节地方要注意,这在下面的程序中
可以看到。特别要注意的一点就是:CGI程序和一般的程序有
所不同,一般的程序在读完了一个文件流的内容之后,会得到
一个EOF的标志。但在CGI程序的表单处理过程中,EOF是永
远不会出现的,所以千万不要读多于CONTENT_LENGTH长
度的字符,否这会有什么后果,谁也不知道(CGI规范中没有
定义,一般根据服务器不同而有不同得处理方法)。
74
CGI表单处理程序的原理
例子:简单留言本
http://infosec.aust.edu.cn/~xjfang/note
<html>
<body>
<FORM ACTION="/cgi-bin/collect.cgi" METHOD="POST">
<P>请输入您的留言(最多80个字符):<BR>
<textarea NAME="data" cols="40" rows="4"></textarea><BR>
<INPUT TYPE="SUBMIT" VALUE="确定">
</FORM>
</body>
</html>
75
CGI表单处理程序的原理
例子:采用post方法的CGI程序collect.c的内容可参见
http://infosec.aust.edu.cn/~xjfang/note/collect.c
生成CGI程序:
$gcc collect.c –o /www/cgi-bin/collect.cgi
查看留言本内容的CGI程序viewdata.c可参见:
http://infosec.aust.edu.cn/~xjfang/note/viewdata.c
生成CGI程序:
$gcc viewdata.c –o /www/cgi-bin/viewdata.cgi
76
Section 3大作业:
用GNU C/C++开发一个基于web的Linux系统管理用户:
1。使用该系统必须要通过身份认证;
2。能进行系统用户列表浏览;
3。能进行passwd修改;
4。能删除用户;
5。能增加新用户;
6。能进行用户查询;
7。能禁用(disable)/启用(enable)某个用户
功能参见:
http://infosec.aust.edu.cn/cgi-bin/admuser.cgi
77