该学习笔记的目标是利用libcurl实现ftp文件上传和下载功能
一、Libcurlde的简介
Libcurl是一个免费的并且易于使用的利用url进行文件传输的库。, libcurl当前支持DICT, FILE, FTP, FTPS, Gopher, HTTP, HTTPS, IMAP, IMAPS, LDAP,LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, Telnet and TFTP协议。libcurl同样支持HTTPS证书授权,HTTP POST, HTTP PUT, FTP 上传, HTTP基本表单上传,代理,cookies,和用户认证。
Libcurl是一个轻量级的库,编译后能够运行到多种平台,包括:Solaris, NetBSD, FreeBSD, OpenBSD, Darwin, HPUX, IRIX, AIX, Tru64,Linux, UnixWare, HURD, Windows, Amiga, OS/2, BeOs, Mac OS X, Ultrix, QNX,OpenVMS, RISC OS, Novell NetWare, DOS 等
二、libcurl的接口
Libcurl分为简单和复杂的接口。简单的接口是一个同步的,高效的,快速的,这种借口主要用于文件传输。大量的应用程序都使用这种方式。而复杂的姐姐偶是一个异步的,在这里不做过多研究
三、libcurl简单的接口工作流程
1、使用libcurl中的curl_easy_init()来初始化一个简单的文件传输会话并且获取到一个handle
2、通过使用curl_easy_setopt()来设置所有的选项参数,在这些参数中最重要的就是URL,同时你也极有可能需要设置一些回调函数,这些回调函数将会在条件符合的情况下被调用。
3、当上面的工作都做完了的时候,就可以使用curl_easy_perform()通知libcurl进行文件传输了,该函数在整个传输过程完成或者失败的时候才会返回一个值。
4、当你执行了第3步之后,你可以使用curl_easy_getinfo()来获取传输的信息
5、最后,你同样可以使用curl_easy_cleanup()来结束本次文件会话
下面针对这五个步骤,编写一个实例进行测试
四、部分功能函数的介绍
1、CURL *curl_easy_init( );
该函数必须首先调用,将会返回一个CURL*类型的handle.并且该函数将会和curl_easy_cleanup()一起配合使用。加入初始化出错的话,该函数将会返回一个NULL;
2、void curl_easy_cleanup(CURL *handle)
该函数一定是最后被调用的,他的参数应该是curl_easy_init的返回值;
3、CURLcode curl_easy_setopt(CURL*handle, CURLoption option, parameter);
该函数从名字上看就知道是设置一些参数的,通过设置不同的参数,将会改变libcurl的功能作用,这个需要仔细阅读指导文档,一旦设置方式不恰当,导致的错误将是致命的。
具体参数的使用方式在这个网址上描述的很详细
http://curl.haxx.se/libcurl/c/curl_easy_setopt.html
4、CURLcode curl_easy_perform(CURL * easy_handle);
像我们刚才提到的那样,这个函数应该是在init和setopt之后使用的,这个函数一旦执行,将会通知libcurl执行我们之前设置的所有方法,值得注意的是,当一个handle被加入到一个multi handle中之后,该参数handle将不能被函数perform调用
五、实例演示
1、下面来看一个简单的实例:
#include<stdio.h> #include<curl/curl.h> int main(int argc,char** argv) { CURL *pCurlHandle = NULL; CURLcode errorCode = 0; /*1. 初始化一个pCurlHandle*/ pCurlHandle = curl_easy_init(); if( pCurlHandle ) { /*2. 设置pCurlHandle的URL*/ curl_easy_setopt( pCurlHandle,CURLOPT_URL, "http://blog.csdn.net/jxnu_xiaobing" ); /*3. 因为上述网址已被重定向了,所以设置为CURLOPT_FOLLOWLOCATION*/ curl_easy_setopt( pCurlHandle,CURLOPT_FOLLOWLOCATION, 1L ); /*4. 开始执行上述opt*/ errorCode = curl_easy_perform(pCurlHandle ); if( errorCode != CURLE_OK ) { printf("curl_easy_perform() failed \n "); } } else { printf(" curl_easy_init() failed \n "); } /*5. 最后关闭pCurlHandle*/ curl_easy_cleanup( pCurlHandle ); return 0; }
2、上述的例子比较简单就是一个访问网页的例子,下面继续学习一个ftp上传的例子
#include<stdio.h> #include<string.h> #include<curl/curl.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<errno.h> #include<unistd.h> #defineLOCAL_FILE "/tmp/xiaobing.txt" #defineREMOTE_URL "ftp://172.30.26.247:21/xiaobing.txt" static size_tread_callback(void *ptr, size_t size, size_t nmemb, void *stream) { curl_off_t nread; /* in real-world cases, this would probablyget this data differently as this fread() stuff is exactly what thelibrary already would do by default internally */ size_t retcode = fread(ptr, size, nmemb,(FILE*)stream); nread = (curl_off_t)retcode; fprintf(stderr, "*** We read %"CURL_FORMAT_CURL_OFF_T " bytes from file\n",nread); return retcode; } int main(int argc,char **argv) { CURL *pCurlhandle; CURLcode res; FILE *hd_src; struct stat file_info; curl_off_t fsize; /*1. 获取待上传文件的大小 */ if(stat(LOCAL_FILE, &file_info)) { printf("Couldnt open '%s': %s\n",LOCAL_FILE, strerror(errno)); return 1; } fsize = (curl_off_t)file_info.st_size; printf("Local file size: %"CURL_FORMAT_CURL_OFF_T " bytes.\n", fsize); /*2. 获取待上传文件的描述符 */ hd_src = fopen(LOCAL_FILE, "rb"); /*3. 初始化所有可能的调用*/ curl_global_init(CURL_GLOBAL_ALL); /*4. 创建一个curlhandle*/ pCurlhandle = curl_easy_init(); if(curl) { /*5.设置一个回调函数 */ curl_easy_setopt(pCurlhandle, CURLOPT_READFUNCTION, read_callback); /*6.使能上传标志位 */ curl_easy_setopt(pCurlhandle, CURLOPT_UPLOAD, 1L); /*7.指定ftp服务器的url */ curl_easy_setopt(pCurlhandle,CURLOPT_URL, REMOTE_URL); /*8.指定需要上传的文件 */ curl_easy_setopt(pCurlhandle, CURLOPT_READDATA, hd_src); /*9.设置待上传文件的大小,这个大小是上面获取到的注意:当参数 为CURLOPT_INFILESIZE_LARGE的时候,size类型应该是curl_off_t的, 当参数为CURLOPT_INFILESIZE的时候size应该是long类型的*/ curl_easy_setopt(pCurlhandle, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fsize); /*10. 开始执行我们上述设定的方法*/ res= curl_easy_perform(pCurlhandle); /*11. 检查是否执行成功 */ if(res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); /*12. 关闭pCurlhandle*/ curl_easy_cleanup(pCurlhandle); } fclose(hd_src); /* close the local file */ /*13. 清除所有可能的调用*/ curl_global_cleanup(); return 0; }
上述程序就能够实现ftp上传文件
3、最后来看一个tfp下载的实例:
/************************************************************************************* * * 文件名: TfpcurlDownload.c * * 功能: curl测试程序 * * 作者: http://blog.csdn.net/King_BingGe * * 创建时间: 2014年09月29号 * * 最后修改时间: 2014年09月29号 * * 详细: 无 * **************************************************************************************/ #include <stdio.h> #include <string.h> #include <curl/curl.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> #include <unistd.h> #define REMOTE_URL "ftp://172.30.26.247:21/xiao.txt" typedef struct Ftpfile { const char *filename; FILE *stream; }Cftpfile; static size_t write_callback(void *ptr, size_t size, size_t nmemb, void *stream) { Cftpfile *out = (Cftpfile*)stream; if( out && !out->stream ) { out->stream = fopen(out->filename, "wb"); if(!out->stream) { printf("write_callback failed \n "); return -1; } } return fwrite(ptr, size, nmemb, out->stream); } int main(int argc, char **argv) { CURL *pCurlhandle; CURLcode res; curl_off_t fsize; Cftpfile ftpfile = { "/tmp/xiaoxiao.txt" , NULL }; /*3. 初始化所有可能的调用*/ curl_global_init(CURL_GLOBAL_ALL); /*4. 创建一个curlhandle*/ pCurlhandle = curl_easy_init(); if(pCurlhandle) { /*5. 设置一个回调函数 */ curl_easy_setopt(pCurlhandle, CURLOPT_WRITEFUNCTION, write_callback ); /*7. 指定ftp服务器的url */ curl_easy_setopt(pCurlhandle,CURLOPT_URL, REMOTE_URL); /*8. 指定需要上传的文件 */ curl_easy_setopt(pCurlhandle, CURLOPT_USERPWD, "cdn_ftp:123456"); /*9. 指定需要上传的文件 */ curl_easy_setopt(pCurlhandle, CURLOPT_WRITEDATA, &ftpfile ); /*10. 设置待下载文件的大小,这个大小是上面获取到的注意:当参数 为CURLOPT_INFILESIZE_LARGE的时候,size类型应该是curl_off_t的, 当参数为CURLOPT_INFILESIZE的时候size应该是long类型的*/ curl_easy_setopt(pCurlhandle, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fsize); /*11. 开始执行我们上述设定的方法 */ res = curl_easy_perform(pCurlhandle); /*12. 检查是否执行成功 */ if(res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); /*13. 关闭pCurlhandle*/ curl_easy_cleanup(pCurlhandle); } else { printf("curl_easy_init failed \n "); } /*14. 清除所有可能的调用*/ curl_global_cleanup(); return 0; }