在这一系列的前一篇文章学了C语言,如何为下载狂人写一个磁盘剩余容量监控程序?中,我们为下载狂人写了一个程序来监视磁盘的剩余容量,防止下载的东西撑爆了硬盘。可是,这两天,他又抱怨他的下载程序不好用,让我们帮他写一个下载程序。

虽然我们学了C语言,虽说学了C语言,走遍天下都不怕,但是要想用C语言写一个全新的下载程序,对我们来说,就好比另外一个二万五千里长征。虽然技术上可行,但是在实际操作中却是行不通的。谁也不会傻到去用C语言写一个全新的下载程序。那么,到底怎么办呢?

如果我们看了《C程序设计伴侣》的7.A 站在巨人的肩膀上——如何使用已有的函数库这个节,要想解决这个问题,那简直就是“洒洒水啦”。在这个小节中,我们介绍了如何借助一些已有的函数库来帮助我们高质量高效率地完成一些常见任务。而其中介绍的CURL,正好是一个可以用于网络下载的开源函数库。

实际上,CURL有两种工作方式,其一,它是一个用URL语法在命令行方式下工作的文件传输工具。我们可以使用curl.exe直接在命令行下下载文件。其二,它也是一个开源的函数库,它提供了libcurl这个函数库,其中提供了多个可以用于处理网络事务(诸如下载,登陆,POST等)的API,利用这些API,我们就可以轻松地完成一个下载程序,这就好像坐上了飞机,片刻之间,就从江西瑞金到了陕北延安,一步完成二万五千里长征。

CURL的使用非常简单,跟其他类似的开源的函数库一样,其使用分为编译函数库和使用函数库两个步骤。

编译CURL函数库

在这里,我们以在Windows环境下,利用Visual C++ 2012编译为例。如果是其他环境,可以参考其文档,也很详尽。

    1. 从CURL的官方网站上下载CURL的源代码包,并解压得到所有源代码
    2. 接下来的工作就是源代码编译成相应的函数库文件(lib和dll)了。这里有两种方法:
    3. 我们可以采用《C程序设计伴侣》中介绍的方法,用Visual Studio打开根目录下的vc6curl文件,经过项目转换后,使用Visual C++ 2012的IDE编译其中的libcurl项目。
    4. 更简便的,我们还可以在“VS2012开发人员命令行提示”中,使用nmake来编译整个源代码。
    5. 首先是启动位于开始->所有程序->Microsoft Visual Studio 2012->Visual Studio Tools中的命令提示,然后用cd命令进入源代码所在根目录下的winbuild目录,比如:     C:\Program Files\Microsoft Visual Studio 11.0>f:

F:\>cd code\curl-7.28.1d\winbuild

F:\code\curl-7.28.1d\winbuild>

  1. 然后,就是使用nmake编译整个代码了:     nmake /f Makefile.vc mode=dll vc=10      其中,mode=dll表示编译成动态链接库,而vc=10选择的是Visual C++的版本,本来Visual C++ 2012是vc11,但是CURL不支持,只好用2010的10代替了,编译也没有什么问题。
  2. 起来倒杯水的时间,整个编译就完成了,编译结果保存在     F:\code\curl-7.28.1d\builds\libcurl-vc10-x86-release-dll-ipv6-sspi-spnego-winssl/      目录下,其中bin保存了可以用于命令行的curl.exe应用程序和它用到的libcurl.dll,include目录是开发需要用到的头文件,lib目录下是需要用到的库文件。
  3. 最后的工作,就是安装libcurl函数库。     将/builds/lib/目录下的文件复制到编译器的库文件目录,例如,E:\MinGW\lib\      将/builds/include/目录下的文件复制到编译器的头文件目录,例如,E:\MinGW\include\      将/builds/bin/目录下的libcurl.dll文件复制到操作系统的动态库搜索目录,例如,C:\Windows\System32\      或者可执行文件所在的目录      当然,我们可以通过配置开发工具来达到同样的目的,这里就不赘述了。
  4. 如果你嫌自己编译麻烦,CURL也提供已经编译好的二进制文件可以直接下载,不过我还是建议你自己动手编译,毕竟,这是我们每个程序员都需要掌握的基本功。

至此,整个编译安装过程就算完成了,这样我们就可以在我们自己的程序中调用CURL所提供的API来完成文件下载的功能。这就像飞机已经加满了油,正停在跑道上等待起飞!

塔台塔台,CL2013次航班准备完毕,请求起飞。

现在,我们就可以利用其中提供的API来简便地实现一个系在程序。

/*
* get.c
* 简易下载程序
* Created on: 2013年11月1日11:13:10
* Author: Bruce
*/ #include <curl/curl.h>
#include <string.h>
//用#pragam comment预编译命令,表示这个程序将使用libcurld_imp.lib这个文件
#pragma comment(lib,"libcurl.lib") //复制将数据写入文件的回调函数,关于回调函数,可以参考C程序设计伴侣8.5.4小节介绍
size_t write_data(void * ptr,size_t size,size_t nmemb,FILE * stream)
{
int written = fwrite(ptr,size,nmemb,stream);
return written;
} //使用函数库所提供函数实现文件下载函数
CURLcode download(char * url,char * out) //char * url待下载文件的URL,char * out 下载后的文件名
{
CURL * curl = NULL;
FILE * fp = NULL;
CURLcode res;
//调用函数库中的curl_easy_init()函数完成初始化
curl = curl_easy_init();
if(curl) //判断初始化是否成功
{
//以二进制可写方式打开文件,保存下载得到的数据
fp = fopen(out,"wb");
//根据libcurl的使用方法,设定下载的URL,写入函数以及写入的文件
curl_easy_setopt(curl,CURLOPT_URL,url);
curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,write_data);
curl_easy_setopt(curl,CURLOPT_WRITEDATA,fp);
//调用curl_easy_perform()函数执行下载操作
res = curl_easy_perform(curl);
//下载完成,进行最后的清理工作
curl_easy_cleanup(curl);
//关闭文件
fclose(fp);
return res;
}
else
{
//如果初始化失败,返回相应的错误代码
return CURL_FAILED_INIT;
}
} //辅助函数,用于从URL中获得文件名
void getfilename(char * url,char * name)
{
//找到URL中的最后一个‘/’字符
char* pos = strrchr(url,'/');
if(NULL != pos)
{
//将URL中文件名(从pos+1开始知道字符串结束)复制到name字符串中
strcpy(name,pos+);
}
} //带有参数的主函数,可以让用户在执行时,直接输入待下载文件的URL
// 例如,如果我们想要下载libcurl的源代码包,则可以直接输入:
// get http://curl.haxx.se/download/curl-7.24.0.zip
// 关于带参数的主函数,可以参考8.7.3小节
int main(int argc,char* argv[])
{
//获取用户输入的URL,判断使用方法是否正确
if( != argc)
{
// 提示正确的使用方法
puts("usage: get http://curl.haxx.se/download/curl-7.24.0.zip");
return -;
}
//获取URL中的文件名
char* url = argv[];
char name[] = "";
getfilename(url,name);
// 调用函数库所提供函数实现的download()函数, 完成文件的下载
CURLcode res = download(url,name);
// 根据返回结果,提示用户下载成功与否
if(CURLE_OK == res)
{
printf("great! download %s as %s succesfully.",url,name);
}
else
{
printf("sorry:( cannot download %s.",url);
}
return ;
}
代码中的注释已经非常详尽了,这里就不再多加解释了。如果看完注释,还是有不明白的地方,或者想更加深入地了解这个程序,
可以参考《C程序设计伴侣》的第七章关于这个例子的介绍。
现在,我们可以用如下命令编译这个程序:
cl /TP get.c
编译后,得到get.exe,也就是我们为下载狂人写的下载程序。(这里的/TP让你觉得有点不舒服? 那么看看学了C语言,如何利用cURL写一个下载程序?——在MinGW环境下实现) 下载程序的开发简单,其 使用就更简单了,比如我们要下载cURL的源代码, 可以使用下面的命令:
get.exe http://curl.haxx.se/download/curl-7.28.1.zip
利用cURL,不到一百行代码,我们轻松地完成了一个下载程序,当然,如果你有兴趣,还可以进一步完善,比如加上进度提示等等。 这个事例也告诉我们一个道理:
学会站在巨人的肩膀上,可以收到事半功倍的效果

我们介绍了如何在Windows平台的Visual C++环境下利用cURL快速高效地实现一个下载程序。但是有朋友反馈说,“这是在用C++代码冒充C代码”。这位朋友说的很有道理,这是因为 Visual C++对C语言的支持并不十分完善,为了使用C语言中的一些新特性,我在编译最终代码的时候,加上了一个/TP选项,这实际上是将.c文件当作.cpp文 件来编译了,也就是把C语言代码视作了C++代码。这里需要说明的是,我们在代码中用到的全是C语言,只是在编译的时候采取了一些曲线救国的策略。

虽然用/TP的方式可以解决问题,但是看起来总有些旁门左道的感觉。幸运的是,在Windows平台上,不只有Visual C++这一款编译器,还有其他的C语言编译器,比如,MInGW就是其中应用比较广泛的一款。利用MinGW,我们同样可以完成整个过程,同时还更加简 单。

  1. 编译libcurl函数库     在Visual C++环境下,我们是使用其nmake程序进行编译,而在MinGW环境下,我们使用其make程序编译(这里的前提是MinGW安装目录下的bin目录在系统PATH路径中)。首先进入cURL的源代码目录,然后用如下命令编译:      make mingw32      因为我们在这里只是使用cURL的基本功能,所以没有使用其他附加选项。
  2. 编译结果     很快我们就可以得到我们需要的编译结果(位于lib目录下):
  • libcurl.a 静态链接库文件
  • libcurldll.a 动态链接库的导入库
  • libcurl.dll 动态链接库

安装     MinGW环境下的安装同Visual C++环境下的安装相似:      头文件:将include目录下的curl目录复制到MinGW的头文件目录,比如:E:\MinGW\include      库文件:将上面编译得到的libcurl.a和libcurldll.a复制到MinGW的库文件目录,比如:E:\MinGW\lib      dll文件:将上面编译得到的libcurl.dll复制到系统PATH目录,比如,C:\Windows\System32使用     仍然使用我们在学了C语言,如何利用cURL写一个下载程序?——用cURL提供的API实现下载中介绍到的get.c文件,用下面的命令进行编译:      动态链接:gcc –o get.exe get.c –lcurldll      静态链接:gcc –o get.exe get.c –lcurl      这样,我们就得到了下载程序get.exe。

整体来看,MinGW环境下libcurl的使用跟在Visual C++环境下的使用是相似的,只是MinGW对C语言的支持根据完善,看起来更加名门正派一些。总之,两种环境下都可以实现,而具体使用哪一种,就看你自己的喜好了。

转自:http://www.howzhi.com/course/3387/lesson/43112

学了C语言,如何利用CURL写一个下载程序?—用nmake编译CURL并安装的更多相关文章

  1. 利用Python写一个抽奖程序,解密游戏内抽奖的秘密

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: 极客挖掘机 PS:如有需要Python学习资料的小伙伴可以加点击下 ...

  2. 学了C语言,如何利用cURL写一个程序验证某个网址的有效性?

    在<C程序设计伴侣>以及这几篇关于cURL的文章中,我们介绍了如何利用cURL写一个下载程序,从网络下载文件.可是当我们在用这个程序下载文件时,又遇到了新问题:如果这个网址是无效的,那么我 ...

  3. linux常用终端指令+如何用vim写一个c程序并运行

    在装好ubuntu之后今天学习了一些linux的一些基础知识: windows里面打开命令窗口是win+r,在linux系统里面,ctrl+alt+t打开终端,今天的一些指令都是围绕终端来说的 首先s ...

  4. 用JAVA写一个多线程程序,写四个线程,其中二个对一个变量加1,另外二个对一个变量减1

    package com.ljn.base; /** * @author lijinnan * @date:2013-9-12 上午9:55:32 */ public class IncDecThrea ...

  5. 写一个ajax程序就是如此简单

    写一个ajax程序就是如此简单 ajax介绍: 1:AJAX全称为Asynchronous JavaScript and XML(异步JavaScript和XML),指一种创建交互式网页应用的网页开发 ...

  6. [Java] 将标准字符流写入到文件中(通过控制台写一个html程序,并保存)

    package test.stream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.Fi ...

  7. C语言学习书籍推荐《学通C语言的24堂课》下载

    下载地址:点我 编辑推荐 <学通C语言的24堂课>:用持续激励培养良好习惯以良好习惯铸就伟大梦想——致亲爱的读者朋友在开始学习<学通C语言的24堂课>的同时,强烈建议读者朋友同 ...

  8. Scheme语言实例入门--怎样写一个“新型冠状病毒感染风险检测程序”

    小学生都能用的编程语言 2020的春季中小学受疫情影响,一直还没有开学,孩子宅在家说想做一个学校要求的研究项目,我就说你做一个怎么样通过编程来学习数学的小项目吧,用最简单的计算机语言来解决小学数学问题 ...

  9. 利用 Python 写一个颜值测试小工具

    我们知道现在有一些利用照片来测试颜值的网站或软件,其实使用 Python 就可以实现这一功能,本文我们使用 Python 来写一个颜值测试小工具. 很多人学习python,不知道从何学起.很多人学习p ...

随机推荐

  1. A taste of urllib3

    import urllib3 import certifi http = urllib3.PoolManager( cert_reqs='CERT_REQUIRED', # Force certifi ...

  2. 转载:SQL索引一步到位

    原文: http://www.cnblogs.com/AK2012/archive/2013/01/04/2844283.html SQL索引一步到位(此文章为“数据库性能优化二:数据库表优化”附属文 ...

  3. Linux查看端口使用状态及启动

    LINUX网络性能之管理工具三剑客 本文是介绍管理Linux查看端口这些输出信息,该命令将显示从每个数据包传出的头和来自主机hostname对端口80的编址.Netstat -tln 命令是Linux ...

  4. 20145103 《Java程序设计》第2周学习总结

    20145103 <Java程序设计>第2周学习总结 教材学习内容总结 在第三章主要学习了Java语言中的类型及其变量主要类型为:整数(1字节的byte,2字节的short,4字节的int ...

  5. 响应式设计Responsinator工具推荐

    from:http://www.25xt.com/allcode/4066.html 原文推荐了5种,感觉有用的吧就这一种,所以收藏过来. Responsinator工具的好处Responsinato ...

  6. Leetcode#56 Merge Intervals

    原题地址 排序+合并,没啥好说的 第一次尝试C++的lambda表达式,有种写js的感觉,很神奇 c11就支持了lambda表达式,仔细想想,我学C++大概就是在09~10年,c11还没有发布,不得不 ...

  7. Brush Mode --- Nyoj 236 分类: Brush Mode 2014-04-02 06:56 116人阅读 评论(0) 收藏

    心急的C小加 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 C小加有一些木棒,它们的长度和质量都已经知道,需要一个机器处理这些木棒,机器开启的时候需要耗费一个单位的时间 ...

  8. 异步解压ZIP文件

    using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Tex ...

  9. smaa github iryoku

    dx10 demo 这东西我没法跑nsight ...这就坑大了 里面有个 RenderTargetCollection这个东西里面有很多 rendertargets 最让我苦恼的就是 sceneRT ...

  10. org.codehaus.xfire.XFireRuntimeException: Could not invoke service.. Server returned error code = 404 for URI.. Check server logs for details

    严重: Servlet.service() for servlet jsp threw exceptionorg.codehaus.xfire.XFireRuntimeException: Could ...