GCGI 是一款开放源代码的、使用C语言实现的、面向对象的 CGI 库,它基于 GObject。
功能
发送 Status
发送 Content-Type
发送 Location
获取环境变量
设置环境变量
GET请求字段解析
POST请求字段解析
支持文件上传、下载
后期功能
Cookies 支持
Session 支持
代码仓库
git clone http://git.heiher.info/gcgi.git |
Over!
C/C++ 语言
GCGI 是一款开放源代码的、使用C语言实现的、面向对象的 CGI 库,它基于 GObject。
功能
发送 Status
发送 Content-Type
发送 Location
获取环境变量
设置环境变量
GET请求字段解析
POST请求字段解析
支持文件上传、下载
后期功能
Cookies 支持
Session 支持
代码仓库
git clone http://git.heiher.info/gcgi.git |
Over!
用 C 语言写的简单的 CGI 访问计数器程序,用文件保存的计数,我觉得比数据库高效一点吧,呵呵。
/* counter.c * Heihaier <admin@heiher.info> */ #include <stdio.h> #include <stdlib.h> int main(int argc, char * argv[]) { unsigned long long int counter = 0; FILE * f = NULL; char file[256]; printf("Content-type: text/html;\n\n"); char * query = getenv("QUERY_STRING"); if(NULL == query) goto error; snprintf(file, 256, "./data/%s", query); f = fopen(file, "rw+"); if(NULL == f) goto error; fread(&counter, sizeof(unsigned long long int), 1, f); printf("document.write(\"<b>%llu</b>\");", ++counter); fseek(f, 0, SEEK_SET); fwrite(&counter, sizeof(unsigned long long int), 1, f); fclose(f); return 0; error: return -1; } |
gcc counter.c -o /var/web/cgi-bin/counter.cgi mkdir /var/web/cgi-bin/data touch /var/web/cgi-bin/data/www.heiher.info chmod 666 /var/web/cgi-bin/data/www.heiher.info |
Over!
从数据库中取回数据
在这个实例中我们从表中取回数据。
步骤:
#include <my_global.h> #include <mysql.h> int main(int argc, char * argv[]) { MYSQL * conn; MYSQL_RES * result; MYSQL_ROW row; int num_fields; int i; conn = mysql_init(NULL); mysql_real_connect(conn, "localhost", "username", "password", "testdb", 0, NULL, 0); mysql_query(conn, "SELECT * FROM writers"); result = mysql_store_result(conn); num_fields = mysql_num_fields(result); while ((row = mysql_fetch_row(result))) { for (i=0; i<num_fields; i++) printf("%s ", row[i] ? row[i] : "NULL"); printf("\n"); } mysql_free_result(result); mysql_close(conn); } |
实例程序打印 writers 表中所有的记录(姓名)。
./select |
Leo Tolstoy Jack London Honore de Balzac Lion Feuchtwanger Emile Zola |
mysql_query(conn, "SELECT * FROM writers"); |
执行查询将取回表 writers 中所有的记录。
result = mysql_store_result(conn); |
取得结果集。
num_fields = mysql_num_fields(result); |
获得表中的字段数量。
while ((row = mysql_fetch_row(result))) { for (i=0; i<num_fields; i++) printf("%s ", row[i] ? row[i] : "NULL"); printf("\n"); } |
获取记录并打印到屏幕。
mysql_free_result(result); |
释放资源。
字段名称
这个实例里将要打印数据并显示字段名称。
为此我们创建一个新的表 friends。
mysql> CREATE TABLE friends (id int not null primary key auto_increment, name varchar(20), age int); |
mysql> insert into friends(name, age) values('Tom', 25); mysql> insert into friends(name, age) values('Elisabeth', 32); mysql> insert into friends(name, age) values('Jane', 22); mysql> insert into friends(name, age) values('Luke', 28); |
插入一些数据到表中。
#include <my_global.h> #include <mysql.h> int main(int argc, char * argv[]) { MYSQL * conn; MYSQL_RES * result; MYSQL_ROW row; MYSQL_FIELD * field; int num_fields; int i; conn = mysql_init(NULL); mysql_real_connect(conn, "localhost", "username", "password", "testdb", 0, NULL, 0); mysql_query(conn, "SELECT * FROM friends"); result = mysql_store_result(conn); num_fields = mysql_num_fields(result); while ((row = mysql_fetch_row(result))) { for(i=0; i<num_fields; i++) { if (i == 0) { while(field = mysql_fetch_field(result)) { printf("%s ", field->name); } printf("\n"); } printf("%s ", row[i] ? row[i] : "NULL"); } } printf("\n"); mysql_free_result(result); mysql_close(conn); return 0; } |
这个实例和之前有一点差别,仅仅增加了字段名称。
while(field = mysql_fetch_field(result)) { printf("%s ", field->name); } |
mysql_fetch_field() 返回一个 MYSQL_FIELD 结构。我们从这个结构中得到名称(name)。
./header |
id name age 1 Tom 25 2 Elisabeth 32 3 Jane 22 4 Luke 28 |
这是程序输出结果。
插件图片到 MySQL 数据库
一些用户喜欢将图片存入数据库,还有一些用户喜欢将图片存入本地文件系统。图片是二进制数据,MySQL 有专用的数据类型 BLOB(Binary Large Object) 以存储二进制数据。
mysql> describe images; +-------+------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | | | | data | mediumblob | YES | | NULL | | +-------+------------+------+-----+---------+-------+ 2 rows in set (0.00 sec) |
这个表将在我们的实例中使用,通过下面的 SQL 语句可以创建它。
CREATE TABLE images(id int not null primary key, data mediumblob); |
#include <my_global.h> #include <mysql.h> int main(int argc, char * argv[]) { MYSQL * conn; int len, size; char data[1000*1024]; char chunk[2*1000*1024+1]; char query[1024*5000]; FILE * fp; conn = mysql_init(NULL); mysql_real_connect(conn, "localhost", "username", "password", "testdb", 0, NULL, 0); fp = fopen("image.png", "rb"); size = fread(data, 1, 1024*1000, fp); mysql_real_escape_string(conn, chunk, data, size); char *stat = "INSERT INTO images(id, data) VALUES('1', '%s')"; len = snprintf(query, sizeof(stat)+sizeof(chunk), stat, chunk); mysql_real_query(conn, query, len); fclose(fp); mysql_close(conn); return 0; } |
在这个实例中,我们插入一张图片到表 images 中,图片最大可以是 1MB。
fp = fopen("images.png", "rb"); size = fread(data, 1, 1024*1000, fp); |
这里打开图片并读入数据集。
mysql_real_escape_string(conn, chunk, data, size); |
二进制数据可以包含特殊字符,为了在 SQL 语句中不造成麻烦。我们必需避开它们。 mysql_real_escape_string() 函数将编码后的数据放入集合 chunk。这样,它们就可以是合法的语句了。这个函数还会在结尾增加一个 NULL 字符,这也是为什么集合 chunk 是集合 data两倍多一个字节。
char * stat = "INSERT INTO images(id, data) VALUES('1', '%s')"; len = snpritnf(query, sizeof(stat)+sizeof(chunk), stat, chunk); |
这两行代码准备查询语句。
mysql_real_query(conn, query, len); |
最后,我们执行语句。
从 MySQL 数据库中有选择的取出图片
在上一个实例中,我们在数据库中插入了图片。在本实例中,我们将有选择的取出这些插入的图片。
#include <my_global.h> #include <mysql.h> int main(int argc, char * argv[]) { MYSQL * conn; MYSQL_RES * result; MYSQL_ROW row; unsigned long * lengths; FILE * fp; conn = msyql_init(NULL); mysql_real_connect(conn, "localhost", "username", "password", "testdb", 0, NULL, 0); fp = fopen("image.png", "wb"); mysql_query(conn, "SELECT data FROM images WHERE id=1"); result = mysql_store_result(conn); row = mysql_fetch_row(result); lengths = mysql_fetch_lengths(result); fwrite(row[0], lengths[0], 1, fp); mysql_free_result(result); fclose(fp); mysql_close(conn); return 0; } |
这个实例中我们将数据库中 ID 为 1 的图片创建为文件 image.png
fp = fopen("image.png", "wb"); |
以可写的方式打开一个文件。
mysql_query(conn, "SELECT data FROM images WHERE id=1"); |
选择 ID 为 1 的图片。
row = mysql_fetch_row(result); |
row 包含了原始数据。
lengths = mysql_fetch_lengths(result); |
获取图片长度。
fwrite(row[0], lengths[0], 1, fp); |
使用标准函数 fwrite() 将数据写入文件。
Over!
关于教程
这是一篇 MySQL 数据库的 C 语言开发教程。它讲述了用 C 语言开发 MySQL 应用程序的基本过程。
关于 MySQL 数据库
MySQL 是一个重要的开放源代码的、多用户的、多线程的数据库管理系统。MySQL 在 Web 应用中很流行。它是非常流行的 LAMP(Linux, Apache, MySQL, PHP) 架构的一部分。MySQL 被瑞典一家名为 MySQL AB 并对开源事业有杰出贡献的公司所有。MySQL 数据库可以运行在很多的操作系统上,如 BSD, Unix, Linux Windows 和 Mac。维基百科和 Youtube 都在使用 MySQL。这些站点一天有数百万将的查询。MySQL 有两个版本,分别是 MySQL 服务器系统和 MySQL 嵌入式系统。
第一个实例
我们第一个实例将要测试调用一个 MySQL 函数。
#include <my_global.h> #include <mysql.h> int main(int argc, char * argv[]) { printf("MySQL client version: %s\n", mysql_get_client_info()); return 0; } |
函数 mysql_get_client_info()返回 MySQL 客户端版本信息。
gcc version.c -o version `mysql_config --cflags --libs` ./version |
这是是如何编译和运行这个实例。
MySQL client version: 5.0.38 |
#include <my_global.h> #include <mysql.h> |
我们包含两个需要的头文件: mysql.h MySQL 函数调用的最重要的头文件。my_global.h 包含了一些全局的声明和标准输入/输出头文件。
printf("MySQL client version: %s\n", mysql_get_client_info()); |
这行代码输入了 MySQL 客户端的版本信息。我们调用了 mysql_get_client_info()函数。
创建一个数据库
在第二个实例中创建一个数据库。
#include <my_global.h> #include <mysql.h> int main(int argc, char * argv[]) { MYSQL * conn; conn = mysql_init(NULL); if (conn == NULL) { printf("Error %u: %s\n", mysql_errno(conn), mysql_error(conn)); exit(1); } if (mysql_real_connect(conn, "localhost", "username", "password", NULL, 0, NULL, 0) == NULL) { printf("Error %u: %s\n", mysql_errno(conn), mysql_error(conn)); exit(1); } if (mysql_query(conn, "CREATE DATABASE testdb")) { printf("Error %u: %s\n", mysql_errno(conn), mysql_error(conn)); exit(1); } mysql_close(conn); return 0; } |
这段代码连接了 MySQL 数据库系统并创建了一个名为 testdb 的数据库。
mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | testdb | +--------------------+ 3 rows in set (0.00 sec) |
检验的确创建了一个新的库。
在这段实例中我们包含了错误检测,检查可能出现的错误是非常重要的。在数据库开发领域里,很多地方都可能出错。为了有清晰的代码之后的实例中将不包含错误检查,我们假设所有人清楚错误检测是开发人员的责任。
实例分为如下的部分:
MYSQL * conn; |
我们声明一个 MYSQL 结构指针,这个结构是连接对象。
conn = mysql_init(NULL); |
mysql_init() 函数返回一个连接对象。
if (conn == NULL) { printf("Error %u: %s\n", mysql_errno(conn), mysql_error(conn)); exit(1); } |
我们检查返回值,如果 mysql_init() 调用失败打印错误消息并中止应用程序。
if (mysql_real_connect(conn, "localhost", "username", "password", NULL, 0, NULL, 0) == NULL) { printf("Error %u: %s\n", mysql_errno(conn), mysql_error(conn)); exit(1); } |
mysql_real_connect() 函数建立了一个到数据库的连接。我们提供连接对象、主机名、用户名和密码参数。其它四个参数分别是数据库名、端口、Unix 套接字和客户端标记。
if (mysql_query(conn, "CREATE DATABASE testdb")) { printf("Error %u: %s\n", mysql_errno(conn), mysql_error(conn)); exit(1); } |
mysql_query() 执行一个 SQL 语句。这里创建一个新的库。
mysql_close(conn); |
最后,我们关闭数据库连接。
创建和操作表
第三个实例将要创建一个表并插入一些数据。
#include <my_global.h> #include <mysql.h> int main(int argc, char * argv[]) { MYSQL * conn; conn = mysql_init(NULL); mysql_real_connect(conn, "localhsot", "username", "password", "testdb", 0, NULL, 0); mysql_query(conn, "CREATE TABLE writers(name VARCHAR(25))"); mysql_query(conn, "INSERT INTO writers VALUES('Leo Tolstoy')"); mysql_query(conn, "INSERT INTO writers VALUES('Jack London')"); mysql_query(conn, "INSERT INTO writers VALUES('Honore de Balzac')"); mysql_query(conn, "INSERT INTO writers VALUES('Lion Feuchtwanger')"); mysql_query(conn, "INSERT INTO writers VALUES('Emile Zole')"); mysql_close(conn); return 0; } |
我们不使用任何新的 MySQL 函数。使用 mysql_query() 函数去创建表和插入数据。
mysql_real_connect(conn, "localhost", "username", "password", "testdb", 0, NULL, 0); |
我们连接数据库 testdb,用户名 username 密码 password。
mysql_query(conn, "CREATE TABLE writers(name VARCHAR(25))"); |
这里我们创建一个名为 writers 的表,它有一个 varchar 类型的字段。
mysql_query(conn, "INSERT INTO writers VALUES('Leo Tolstoy')"); |
我们在 writers 表里插入一个记录。
mysql> show tables; +------------------+ | Tables_in_testdb | +------------------+ | writers | +------------------+ 1 row in set (0.00 sec) |
显示数据库里的表。
mysql> select * from writers; +-------------------+ | name | +-------------------+ | Leo Tolstoy | | Jack London | | Honore de Balzac | | Lion Feuchtwanger | | Emile Zola | +-------------------+ 5 rows in set (0.00 sec) |
枚举表中的记录。
Over!