`
zsxxsz
  • 浏览: 444066 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

使用 acl 库开发一个 HTTP 下载客户端

阅读更多

  在 acl 的协议库(lib_protocol) 中有专门针对 HTTP 协议和 ICMP 协议的,本文主要介绍如何使用 lib_protocol 协议库来开发一个简单的 http 客户端。下面首先介绍一下几个本文用到的函数接口。

/**
 * 创建一个 HTTP_UTIL 请求对象
 * @param url {const char*} 完整的请求 url
 * @param method {const char*} 请求方法,有效的请求方法有:GET, POST, HEAD, CONNECT
 * @return {HTTP_UTIL*}
 */
HTTP_API HTTP_UTIL *http_util_req_new(const char *url, const char *method);

/**
 * 设置 HTTP 代理服务器地址
 * @param http_util {HTTP_UTIL*}
 * @param proxy {const char*} 代理服务器地址,有效格式为: IP:PORT, DOMAIN:PORT,
 *  如: 192.168.0.1:80, 192.168.0.2:8088, www.g.cn:80
 */
HTTP_API void http_util_set_req_proxy(HTTP_UTIL *http_util, const char *proxy);

/**
 * 设置 HTTP 响应体的转储文件,设置后 HTTP 响应体数据便会转储于该文件
 * @param http_util {HTTP_UTIL*}
 * @param filename {const char*} 转储文件名
 * @return {int} 如果返回值 < 0 则表示无法打开该文件, 否则表示打开文件成功
 */
HTTP_API int http_util_set_dump_file(HTTP_UTIL *http_util, const char *filename);

/**
 * 打开远程 HTTP 服务器或代理服务器连接,同时构建 HTTP 请求头数据并且将该数据
 * 发给新建立的网络连接
 * @param http_util {HTTP_UTIL*}
 * @return {int} 0: 成功; -1: 无法打开连接或发送请求头数据失败
 */
HTTP_API int http_util_req_open(HTTP_UTIL *http_util);

/**
 * 发送完请求数据后调用此函数从 HTTP 服务器读取完整的 HTTP 响应头
 * @param http_util {HTTP_UTIL*}
 * @return {int} 0: 成功; -1: 失败
 */
HTTP_API int http_util_get_res_hdr(HTTP_UTIL *http_util);

/**
 * 读完 HTTP 响应头后调用此函数从 HTTP 服务器读取 HTTP 数据体数据,需要连续调用
 * 此函数,直至返回值 <= 0, 如果之前设置了转储文件或转储则在读取数据过程中同时会
 * 拷贝一份数据给转储文件或转储流
 * @param http_util {HTTP_UTIL*}
 * @param buf {char *} 存储 HTTP 响应体的缓冲区
 * @param size {size_t} buf 的空间大小
 * @return {int} <= 0: 表示读结束; > 0: 表示本次读到的数据长度
 */
HTTP_API int http_util_get_res_body(HTTP_UTIL *http_util, char *buf, size_t size);

 

  以上仅是 lib_http_util.h 函数接口中的一部分,下面就写一个简单的例子:

#include "lib_acl.h"
#include "lib_protocol.h"

static void get_url(const char *method, const char *url,
	const char *proxy, const char *dump, int out)
{
	/* 创建 HTTP_UTIL 请求对象 */
	HTTP_UTIL *http = http_util_req_new(url, method);
	int   ret;

	/* 如果设定代理服务器,则连接代理服务器地址,
	 * 否则使用 HTTP 请求头里指定的地址
	 */

	if (proxy && *proxy)
		http_util_set_req_proxy(http, proxy);

	/* 设置转储文件 */
	if (dump && *dump)
		http_util_set_dump_file(http, dump);

	/* 输出 HTTP 请求头内容 */

	http_hdr_print(&http->hdr_req->hdr, "---request hdr---");

	/* 连接远程 http 服务器 */

	if (http_util_req_open(http) < 0) {
		printf("open connection(%s) error\n", http->server_addr);
		http_util_free(http);
		return;
	}

	/* 读取 HTTP 服务器响应头*/

	ret = http_util_get_res_hdr(http);
	if (ret < 0) {
		printf("get reply http header error\n");
		http_util_free(http);
		return;
	}

	/* 输出 HTTP 响应头 */

	http_hdr_print(&http->hdr_res->hdr, "--- reply http header ---");

	/* 如果有数据体则开始读取 HTTP 响应数据体部分 */
	while (1) {
		char  buf[4096];
		
		ret = http_util_get_res_body(http, buf, sizeof(buf) - 1);
		if (ret <= 0)
			break;
		buf[ret] = 0;
		if (out)
			printf("%s", buf);
	}
	http_util_free(http);
}

static void usage(const char *procname)
{
	printf("usage: %s -h[help] -t method -r url -f dump_file -o[output] -X proxy_addr\n"
		"example: %s -t GET -r http://www.sina.com.cn/ -f url_dump.txt\n",
		procname, procname);
}

int main(int argc, char *argv[])
{
	int   ch, out = 0;
	char  url[256], dump[256], proxy[256], method[32];

	acl_init();  /* 初始化 acl 库 */

	ACL_SAFE_STRNCPY(method, "GET", sizeof(method));
	url[0] = 0;
	dump[0] = 0;
	proxy[0] = 0;
	while ((ch = getopt(argc, argv, "hor:t:f:X:")) > 0) {
		switch (ch) {
		case 'h':
			usage(argv[0]);
			return (0);
		case 'o':
			out = 1;
			break;
		case 'r':
			ACL_SAFE_STRNCPY(url, optarg, sizeof(url));
			break;
		case 't':
			ACL_SAFE_STRNCPY(method, optarg, sizeof(method));
			break;
		case 'f':
			ACL_SAFE_STRNCPY(dump, optarg, sizeof(dump));
			break;
		case 'X':
			ACL_SAFE_STRNCPY(proxy, optarg, sizeof(proxy));
			break;
		default:
			break;
		}
	}

	if (url[0] == 0) {
		usage(argv[0]);
		return (0);
	}

	get_url(method, url, proxy, dump, out);
	return (0);
}

  编译成功后,运行 ./url_get -h 会给出如下提示:

usage: ./url_get -h[help] -t method -r url -f dump_file -o[output] -X proxy_addr
example: ./url_get -t GET -r http://www.sina.com.cn/ -f url_dump.txt

  输入: ./url_get -t GET -r http://www.sina.com -o, 该命令是获取 www.sina.com 页面并输出至标准输出,得到的结果为:

HTTP/1.0 301 Moved Permanently
Date: Tue, 12 Jan 2010 01:54:39 GMT
Server: Apache
Location: http://www.sina.com.cn/
Cache-Control: max-age=3600
Expires: Tue, 12 Jan 2010 02:54:39 GMT
Vary: Accept-Encoding
Content-Length: 231
Content-Type: text/html; charset=iso-8859-1
Age: 265
X-Cache: HIT from tj175-135.sina.com.cn
Connection: close
--------------- end -----------------
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>301 Moved Permanently</title>
</head><body>
<h1>Moved Permanently</h1>
<p>The document has moved <a href="http://www.sina.com.cn/">here</a>.</p>
</body></html>

   如果想把页面转存至文件中,可以输入:./url_get -t GET -r http://www.sina.com -f dump.txt, 这样就会把新浪的首页下载并存储于 dump.txt 文件中。

  这个例子非常简单,其实如果查看 http_util.c 源码,会看到这个文件是对 lib_http.h 里一些更为底层 API 的封装。

  如果仅是下载一个页面至某个文件中,其实还有更为简单的方法,只需要调用接口:

/**
 * 将某个 url 的响应体数据转储至某个文件中
 * @param url {const char*} 完整请求 url, 如: http://www.g.cn
 * @param dump {const char*} 转储文件名
 * @param {int} 读到的响应体数据长度, >=0: 表示成功, -1: 表示失败
 */
HTTP_API int http_util_dump_url(const char *url, const char *dump);

   只这一个函数便可以达到与上一个例子相同的效果。

  可以从 acl.sourceforge.net 上下载最新的 acl_project 库,查看 samples/http/ 下的三个例子,看一下下载WEB文件的不同方式。

 

个人微博:http://weibo.com/zsxxsz

 

2
0
分享到:
评论

相关推荐

    acl 工程是一个跨平台的网络通信库及服务器编程框架,同时提供更多的实用功能库

    acl 工程是一个跨平台(支持LINUX,WIN32,Solaris,MacOS,FreeBSD)的网络通信库及服务器编程框架,同时提供更多的实用功能库。通过该库,用户可以非常容易地编写支持多种模式(多线程、多进程、非阻塞、触发器、...

    acl 框架库-其他

    acl 框架库是一个 C 库,主要包含:服务器开发框架、同步/异步网络通讯、常用数据结构、进程池/线程池、流式 xml/json 解析器、http/ping 应用协议等内容。 acl 包括以下丰富的常用函数库: 1、常见网络应用库:SMTP...

    storage-acl-setter-python:使用批处理JSON补丁请求将GCS存储桶的默认对象ACL应用于所有包含的对象

    存储-acl-setter-python 使用通过Google API Python客户端库发出的批量JSON补丁请求,将GCS存储桶的默认对象ACL应用于所有包含的对象。 api:存储关键字:cmdline,分页,oauth2用于验证用户身份的设置。 自2013年2...

    ASP.net入门教程

    ASP.NET 是一个统一的 Web 开发模型,它包括您使用尽可能少的代码生成企业级 Web 应用程序所必需的各种服务。ASP.NET 作为 .NET Framework 的一部分提供。当您编写 ASP.NET 应用程序的代码时,可以访问 .NET ...

    fourinone-3.04.25

    跟Hadoop, Zookeeper, Memcache, ActiveMq等开源产品代码上没有任何相似性,不需要任何依赖,引用一个jar包就可以嵌入式使用,良好支持window环境,可以在一台机器上模拟分布式环境,更方便开发。 开发包里自带了一...

    Fourinone分布式计算框架

    跟Hadoop, Zookeeper, Memcache, ActiveMq等开源产品代码上没有任何相似性,不需要任何依赖,引用一个jar包就可以嵌入式使用,良好支持window环境,可以在一台机器上模拟分布式环境,更方便开发。 开发包里自带了一...

    docker-tarreceive:提供一个服务器端点,在该端点中将通过管道传输的数据流提取到指定的卷中

    概括 该存储库基于 ,后者创建了一个系统用户,该用户通过SSH运行单个命令,并管理SSH密钥(authorized_keys)的ACL。 这使我们能够提供一个服务器端点,在其中将管道输入的tar数据流提取到环境变量指定的卷中。参考...

    JavaAPI1.6中文chm文档 part1

    由于比较大分为两个部分,这是第一...org.ietf.jgss 此包提供一个框架,该框架允许应用程序开发人员通过利用统一的 API 使用一些来自各种基础安全机制(如 Kerberos)的安全服务,如验证、数据完整性和和数据机密性。 ...

    IIS6.0 IIS,互联网信息服务

    除了匿名访问用户(Anonymous)外,IIS中的FTP将使用Windows 2000自带的用户库(可在“开始→程序→管理工具→计算机管理”中找到“用户”一项来进行用户库的管理)。 最后,关键一步还有就是将你的电脑变为网络中的...

    JAVA_API1.6文档(中文)

    javax.management.remote.rmi RMI 连接器是供 JMX Remote API 使用的一种连接器,后者使用 RMI 将客户端请求传输到远程 MBean 服务器。 javax.management.timer 提供对 Timer MBean(计时器 MBean)的定义。 javax...

    Fourinone分布式并行计算四合一框架

    跟Hadoop, Zookeeper, Memcache, ActiveMq等开源产品代码上没有任何相似性,不需要任何依赖,引用一个jar包就可以嵌入式使用,良好支持window环境,可以在一台机器上模拟分布式环境,更方便开发。  开发包里自带了...

    精通WindowsAPI 函数 接口 编程实例

    1.1 第一个实例程序 1 1.1.1 start.exe 1 1.1.2 Windows API 2 1.1.3 程序入口函数 2 1.1.4 start.c代码分析 2 1.2 编译代码 3 1.2.1 安装Visual Studio 3 1.2.2 安装Microsoft Platform SDK 4 ...

    ngx-admin-dotnet-starter

    Ngx-admin是一个基于Nebular库的2万颗星的仪表板。它包括扩展的授权和用户数据编辑模块。 此捆绑包使您可以加快Web应用程序的开发速度,并节省多达300个开发小时(甚至更多!)。您可以从IDE中运行.Net Bundle,...

    dokieli:dokieli是用于分散式文章发布,注释和社交互动的客户端编辑器

    它可以用作: 单页应用程序-打开任何dokieli嵌入式文章浏览器扩展-在您的Web浏览器中导入此存储库,或从或安装Web Extension执照代码: 内容:文献资料对于勇敢的开发人员和作者:规范解释了dokieli的原理,体系...

    精通Windows.API-函数、接口、编程实例.pdf

    1.1 第一个实例程序 1 1.1.1 start.exe 1 1.1.2 Windows API 2 1.1.3 程序入口函数 2 1.1.4 start.c代码分析 2 1.2 编译代码 3 1.2.1 安装Visual Studio 3 1.2.2 安装Microsoft Platform SDK 4 ...

Global site tag (gtag.js) - Google Analytics