在Windows下实现HTTP下载,其实很容易,微软已经帮我们封装好了简便易用的wininet库,利用它提供的API,很容易就能开发出具备HTTP下载功能的程序,不过我在这里并不准备对wininet进行讨论,有兴趣的朋友可以自行查阅MSDN或者相关资料。
我在这里要说的,是直接使用socket编程,来实现HTTP的下载。这种看似底层和原始的方法,虽然实现起来比较麻烦(仅仅是麻烦而已,其实很简单),但对我们了解HTTP的工作原理和应对非Windows平台的编程,都有一定的帮助,所以我将这几天自己学习的心得体会,记录于此。本文主要涉及socket编程实现直接HTTP下载和通过代理服务器进行HTTP下载。
HTTP消息头
说是socket编程,但核心其实是对HTTP消息头的处理,包括格式化发送,以及接受解析。一个典型的用于下载的HTTP请求头大概是这样的:
GET /test/test.zip HTTP/1.1 | -- "GET"是命令,后接要下载的文件,HTTP表示版本 |
Host: www.gl.gx.cn | -- 主机域名 |
Accept: */* | -- 接受任何类型的文件 |
User-Agent: MyApp | -- 浏览器的类型 |
Connection: Keep-Alive | -- 保持连接 |
-- 空行,表示请求头结束 |
"--"后面的是我加的注释,请求头不包括这些东西。
这里注意还有一个内容没有列出来,但是对于HTTP下载来说是比较重要的,就是"Range"项,像这样"Range: bytes=起始位置 - 终止位置",要实现多线程下载和断点续传就都靠他了。我并不打算详细解说每一项内容,有兴趣的可以查阅相关资料。
一个典型的服务器返回的响应头如下:
HTTP/1.1 200 OK | -- 响应代码及指示文本 |
Content-Length: 1679134430 | -- 数据块长度 |
Content-Type: application/x-zip-compressed | -- 数据块文件类型 |
Last-Modified: Wed, 15 Mar 2006 13:40:59 GMT | -- 修改时间 |
Server: Microsoft-IIS/6.0 | -- 服务器信息 |
Date: Fri, 26 Sep 2008 08:42:01 GMT | -- 时间 |
-- 空行,表示响应头结束 | |
XX XX XX XX XX ... | -- 数据块字节数据 |
格式化的信息清晰明了,要注意的是,请求的数据将会紧跟在表示响应头结束的空行后面,所以这里要自己进行拆分处理等等工作。
Socket实现HTTP下载
1 - 和服务器建立连接
2 - 格式化请求头
3 - 发送请求头
4 - 接收服务器返回的数据
5 - 拆分、分析响应头
6 - 接收数据
以上就是简要的步骤,实际编程的时候,还有些细节需要动动脑筋来实现,比如拆分响应头和返回的数据,这里提供一种思路,接收的时候一个字节一个字节的接收,然后利用换行符和最后的空行来判断响应头和数据块的分界点,达到拆分数据的目的。
Socket通过代理服务器实现HTTP下载
以上的方法在实际测试时,不能成功,在第一步就失败了,无法和服务器建立连接(用wininet不会有这个问题),判断是由于公司采用代理服务器上网造成的,无法直连外网。那如何在使用代理服务器的情况下进行下载呢?
答案其实也很简单,上面的几个步骤稍微修改即可,如下:
1 - 和代理服务器建立连接
2 - 向代理服务器发送对目标服务器的连接请求
3 - 格式化请求头
4 - 发送请求头
5 - 接收服务器返回的数据
6 - 拆分、分析响应头
7 - 接收数据
第一步首先和代理服务器进行连接,而不是和目标服务器,这样就可以向代理服务器发送HTTP请求,只不过这次首先发送的是一个连接请求,如下:
CONNECT www.gl.gx.com:80 HTTP/1.1 | -- 连接目标服务器 |
Connection: Keep-Alive | -- 保持连接 |
-- 空行结束 |
成功以后,就和目标服务器连接上了,然后就和原来直连一样了,像它发送请求就可以了。
上述通过代理进行下载的方法有一个前提,就是你必须获得代理服务器的地址,才能和它进行连接。当然可以手动指定或者从配置文件中读取,但更多的朋友应该是希望能够取得并使用IE的代理信息,有两个方法可以实现,一个是读取注册表,这个我也没什么研究。。。另一个就是使用wininet提供的InternetQueryOption函数,具体可以参阅MSDN,如果用到了wininet,那么还不如连下载也使用它来的方便。。。
本文只是简单介绍了一下HTTP直接下载和代理下载的原理,都是我这几天的心得和体会,没有提供任何源代码,因为我也没写出完整的示例代码,因为我最终决定偷懒,直接使用wininet来实现http下载的功能... ╮(╯_╰)╭
联系客服