一、实验准备
实验目的:
- 基本的http GET/POST操作
- 取html网页
- 网页下载保存
- 文件的断点续传
实验环境:
环境:Ubuntu 18.04
语言:C语言
Ubuntu下载安装Libcurl库,命令如下:
sudo apt-get update
sudo apt-get install libcurl4-openssl-dev
安装完成
二、基本的http GET/POST操作
使用命令gedit http1.c
创建一个.c文件,写入以下代码:
#include <stdio.h>
#include <curl/curl.h>
void getUrl(char *filename)
{
CURL *curl;
CURLcode res;
FILE *fp;
/*
以可写的形式打开文件,若没有则创建一个
返回结果用文件存储
*/
if ((fp = fopen(filename, "w")) == NULL)
{
return;
}
//定义一个curl列表指针
struct curl_slist *headers = NULL;
//申请一个curl列表并向列表中添加:Accept:Agent-007
headers = curl_slist_append(headers, "Accept: Agent-007");
//开始一个curl会话
curl = curl_easy_init();
//传递自定义标头列表
if (curl)
{
//代理
//curl_easy_setopt(curl, CURLOPT_PROXY, "10.99.60.201:8080");
//更改协议头
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
//设置访问的URL(百度)
curl_easy_setopt(curl, CURLOPT_URL,"http://www.baidu.com");
//将返回的html主体数据输出到fp指向的文件
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
//将返回的http头输出到fp指向的文件
curl_easy_setopt(curl, CURLOPT_HEADERDATA, fp);
//执行curl,返回0则一切ok,否则有错
res = curl_easy_perform(curl);
//释放资源
curl_slist_free_all(headers);
//结束curl会话
curl_easy_cleanup(curl);
//关闭fp指向的文件
fclose(fp);
}
}
void postUrl(char *filename)
{
CURL *curl;
CURLcode res;
FILE *fp;
if ((fp = fopen(filename, "w")) == NULL)
{
return;
}
curl = curl_easy_init();
if (curl)
{
//指定cookie文件去访问其它页面
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "/home/zcj/code/cookie.txt");
//指定post内容(传递一个作为HTTP “POST”操作的所有数据的字符串)
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "&logintype=uid&u=xieyan&psw=xxx86");
//curl_easy_setopt(curl, CURLOPT_PROXY, "10.99.60.201:8080");
//指定url
curl_easy_setopt(curl, CURLOPT_URL, "http://mail.sina.com.cn/cgi-bin/login.cgi");
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
fclose(fp);
}
int main(void)
{
//传参:文件路径
getUrl("/home/zcj/code/get.html");
postUrl("/home/zcj/code/post.html");
}
编译运行
gcc http1.c -o http1 –lcurl
./http1
然后get.html 文件内有了百度返回的网页内容
三、获取html网页
新建一个.c文件
gedit http2.c
文件中写入以下代码
#include <stdio.h>
#include <curl/curl.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
//定义CURL类型的指针
CURL *curl;
//定义CURLcode类型的变量,保存返回状态码
CURLcode res;
//如果命令行参数不等于 2 ,则执行
if(argc!=2)
{
printf("Usage : file <url>;\n");
exit(1);
}
//初始化一个CURL类型的指针
curl = curl_easy_init();
if(curl!=NULL)
{
//设置 curl 选项. 其中 CURLOPT_URL 是让用户指定 url. argv[1] 中存放的命令行传进来的网址
curl_easy_setopt(curl, CURLOPT_URL, argv[1]);
//调用 curl_easy_perform 执行我们的设置.并进行相关的操作. 在这里默认打印出来
res = curl_easy_perform(curl);
//清除curl操作.
curl_easy_cleanup(curl);
}
return 0;
}
编译运行
gcc http2.c -o http2 –lcurl
./http2 www.baidu.com
四、网页下载保存
新建一个.c文件
gedit http3.c
文件中写入以下代码
// 采用 CURLOPT_WRITEFUNCTION 实现网页下载保存功能
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <curl/curl.h>
#include <curl/easy.h>
//定义FILE类型指针
FILE *fp;
/*
这个函数是为了符合 CURLOPT_WRITEFUNCTION 而构造的
完成数据保存功能
*/
size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
{
int written = fwrite(ptr, size, nmemb, (FILE *)fp);
return written;
}
int main(int argc, char *argv[])
{
CURL *curl;
//初始化所有的可能的调用
curl_global_init(CURL_GLOBAL_ALL);
//初始化一个CURL类型的指针
curl = curl_easy_init();
//设置 curl 选项(这里通过参数二设置)
curl_easy_setopt(curl, CURLOPT_URL, argv[1]);
//打开文件(根据参数三)
if((fp=fopen(argv[2],"w"))==NULL)
{
curl_easy_cleanup(curl);
exit(1);
}
//CURLOPT_WRITEFUNCTION 将后继的动作交给 write_data 函数处理
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
//执行
curl_easy_perform(curl);
curl_easy_cleanup(curl);
exit(0);
}
这里使用的是额外的函数进行写入文件并保存。
五、文件的断点续传
新建一个.c文件
gedit http4.c
文件中写入以下代码:
//采用 CURLOPT_RESUME_FROM_LARGE 实现文件断点续传功能
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include <curl/curl.h>
//这个函数为 CURLOPT_HEADERFUNCTION 参数构造
/* 从 http 头部获取文件 size */
size_t getcontentlengthfunc(void *ptr, size_t size, size_t nmemb, void *stream)
{
int r;
long len = 0;
/* _snscanf() is Win32 specific */
// r = _snscanf(ptr, size * nmemb, "Content-Length: %ld\n", &len);
//字符串解析函数
r = sscanf(ptr, "Content-Length: %ld\n", &len);
if (r) /* Microsoft: we don't read the specs */
{
*((long *) stream) = len;
}
return size * nmemb;
}
/* 保存下载文件 */
size_t wirtefunc(void *ptr, size_t size, size_t nmemb, void *stream)
{
//写进文件中
return fwrite(ptr, size, nmemb, stream);
}
/* 读取上传文件 */
size_t readfunc(void *ptr, size_t size, size_t nmemb, void *stream)
{
FILE *f = stream;
size_t n;
//打开文件出错
if (ferror(f))
{
return CURL_READFUNC_ABORT;
}
//读文件
n = fread(ptr, size, nmemb, f) * size;
return n;
}
/* 下载或者上传文件函数 */
int download(CURL *curlhandle, const char * remotepath, const char * localpath, long timeout, long tries)
{
FILE *f;
curl_off_t local_file_len = -1;
long filesize = 0;
CURLcode r = CURLE_GOT_NOTHING;
int c;
struct stat file_info;
int use_resume = 0;
/* 得到本地文件大小 */
//if(access(localpath,F_OK) == 0)
if(stat(localpath, &file_info) == 0)
{
local_file_len = file_info.st_size;
use_resume = 1;
}
//采用追加方式打开文件,便于实现文件断点续传工作
f = fopen(localpath, "ab+");
if (f == NULL) {
perror(NULL);
return 0;
}
//curl_easy_setopt(curlhandle, CURLOPT_UPLOAD, 1L);
//设置 URL 值
curl_easy_setopt(curlhandle, CURLOPT_URL, remotepath);
//设置连接超时,单位秒
curl_easy_setopt(curlhandle, CURLOPT_CONNECTTIMEOUT, timeout);
//设置 http 头部处理函数
curl_easy_setopt(curlhandle, CURLOPT_HEADERFUNCTION, getcontentlengthfunc);
//设置 http 头部的文件大小数据
curl_easy_setopt(curlhandle, CURLOPT_HEADERDATA, &filesize);
//设置文件续传的位置给 libcurl
curl_easy_setopt(curlhandle, CURLOPT_RESUME_FROM_LARGE, use_resume?local_file_len:0);
//将主体数据写入到文件中
curl_easy_setopt(curlhandle, CURLOPT_WRITEDATA, f);
//调用写数据函数
curl_easy_setopt(curlhandle, CURLOPT_WRITEFUNCTION, wirtefunc);
//curl_easy_setopt(curlhandle, CURLOPT_READFUNCTION, readfunc);
//curl_easy_setopt(curlhandle, CURLOPT_READDATA, f);
//不会 PHP 为 CURL 传输显示一个进程条,设置这个选项为一个非零值
curl_easy_setopt(curlhandle, CURLOPT_NOPROGRESS, 1L);
//想 CURL 报告每一件意外的事情,设置这个选项为一个非零值
curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, 1L);
//执行
r = curl_easy_perform(curlhandle);
//关闭文件
fclose(f);
//执行成功,返回 1
if (r == CURLE_OK)
return 1;
//执行失败,返回 0
else
{
fprintf(stderr, "%s\n", curl_easy_strerror(r));
return 0;
}
}
int main(int c, char **argv) {
CURL *curlhandle = NULL;
//初始化所有的可能的调用
curl_global_init(CURL_GLOBAL_ALL);
//初始化 CURL
curlhandle = curl_easy_init();
//download(curlhandle, "ftp://user:pass@host/path/file", "C:\\file", 0, 3);
download(curlhandle , "http://software.sky-union.cn/index.asp", "/home/zcj/code/index.asp", 1, 3);
//清除缓存
curl_easy_cleanup(curlhandle);
curl_global_cleanup();
return 0;
}
编译运行
gcc http4.c -o http4 –lcurl
./http4