有个业务需求需要通过curl代理的方式来访问外网
百度了一把,测试可以正常使用。记录下来方便后续查找
CURLOPT_FOLLOWLOCATION:设为0,则不会自动301,302跳转;
*CURLOPT_INFILESIZE:当你上传一个文件到远程站点,这个选项告诉PHP你上传文件的大小。*CURLOPT_VERBOSE:如果你想CURL报告每一件意外的事情,设置这个选项为一个非零值。*CURLOPT_HEADER:如果你想把一个头包含在输出中,设置这个选项为一个非零值。*CURLOPT_NOPROGRESS:如果你不会PHP为CURL传输显示一个进程条,设置这个选项为一个非零值。
注意:PHP自动设置这个选项为非零值,你应该仅仅为了调试的目的来改变这个选项。
下列选项的值将被作为字符串:
注意:在确认你的服务器支持命令先不要去这样做。
下列的选项要求一个文件描述(通过使用fopen()函数获得):
*CURLOPT_FILE:这个文件将是你放置传送的输出文件,默认是STDOUT.*CURLOPT_INFILE:这个文件是你传送过来的输入文件。*CURLOPT_WRITEHEADER:这个文件写有你输出的头部分。*CURLOPT_STDERR:这个文件写有错误而不是stderr。
Libcurl为一个免费开源的,客户端url传输库,支持FTP,FTPS,TFTP,HTTP,HTTPS,GOPHER,TELNET,DICT,FILE和LDAP,跨平台,支持Windows,Unix,Linux等,线程安全,支持Ipv6。并且易于使用。
下载下来的是源码包,需要编译。
解压zip文件,进入curl-7.14.0/lib目录(我下载的是7.14.0)。
编译Debug版本。新建一个批处理bat文件,如buildDebug.bat,内容如下:
call"C:/ProgramFiles/MicrosoftVisualStudio/VC98/Bin/vcvars32.bat"
setCFG=debug-dll-ssl-dll-zlib-dll
setOPENSSL_PATH=E:/SSL/openssl-0.9.7e
setZLIB_PATH=E:/zip/zlib123
nmake-fMakefile.vc6
其输出:libcurld_imp.lib,libcurld.dll
编译Release版本。新建一个批处理文件BuildRelease.bat,内容如下:
setCFG=release-dll-ssl-dll-zlib-dll
其输出:libcurl_imp.lib,libcurl.dll
如果需要编译其他版本,可查看Makefile.vc6,设定相应的CFG参数即可。
2.1LibCurl编程流程
在基于LibCurl的程序里,主要采用callbackfunction(回调函数)的形式完成传输任务,用户在启动传输前设置好各类参数和回调函数,当满足条件时libcurl将调用用户的回调函数实现特定功能。下面是利用libcurl完成传输任务的流程:
1.调用curl_global_init()初始化libcurl
2.调用curl_easy_init()函数得到easyinterface型指针
3.调用curl_easy_setopt设置传输选项
4.根据curl_easy_setopt设置的传输选项,实现回调函数以完成用户特定任务
5.调用curl_easy_perform()函数完成传输任务
6.调用curl_easy_cleanup()释放内存
在整过过程中设置curl_easy_setopt()参数是最关键的,几乎所有的libcurl程序都要使用它。
2.2重要函数
1.CURLcodecurl_global_init(longflags);
描述:这个函数只能用一次。(其实在调用curl_global_cleanup函数后仍然可再用)如果这个函数在curl_easy_init函数调用时还没调用,它讲由libcurl库自动完成。参数:flagsCURL_GLOBAL_ALL//初始化所有的可能的调用。CURL_GLOBAL_SSL//初始化支持安全套接字层。CURL_GLOBAL_WIN32//初始化win32套接字库。CURL_GLOBAL_NOTHING//没有额外的初始化。
3.3curl_easy_setopt函数介绍
1.CURLOPT_URL设置访问URL
7.CURLOPT_FOLLOWLOCATION设置重定位URL
同时指定几个范围:bytes=500-600,601-999CURLOPT_RESUME_FROM传递一个long参数给libcurl,指定你希望开始传递的
偏移量。
3.4curl_easy_perform函数说明(error状态码)
该函数完成curl_easy_setopt指定的所有选项,本节重点介绍curl_easy_perform的返回值。返回0意味一切ok,非0代表错误发生。主要错误码说明:1.CURLE_OK任务完成一切都好
2CURLE_UNSUPPORTED_PROTOCOL
不支持的协议,由URL的头部指定
3CURLE_COULDNT_CONNECT
不能连接到remote主机或者代理
4CURLE_REMOTE_ACCESS_DENIED
访问被拒绝
5CURLE_HTTP_RETURNED_ERROR
Http返回错误
6CURLE_READ_ERROR读本地文件错误
3.1获取html网页
#include
#include
#include
intmain(intargc,char*argv[])
{
CURL*curl;//定义CURL类型的指针
CURLcoderes;//定义CURLcode类型的变量,保存返回状态码
if(argc!=2)
printf("Usage:file
exit(1);
}
curl=curl_easy_init();//初始化一个CURL类型的指针
if(curl!=NULL)
//设置curl选项.其中CURLOPT_URL是让用户指定url.argv[1]中存放的命令行传进来的网址
curl_easy_setopt(curl,CURLOPT_URL,argv[1]);
res=curl_easy_perform(curl);
//清除curl操作.
curl_easy_cleanup(curl);
return0;
}
3.2网页下载保存实例
//采用CURLOPT_WRITEFUNCTION实现网页下载保存功能
#include
#include
#include
#include
#include
#include
FILE*fp;//定义FILE类型指针
//这个函数是为了符合CURLOPT_WRITEFUNCTION而构造的
//完成数据保存功能
size_twrite_data(void*ptr,size_tsize,size_tnmemb,void*stream)
intwritten=fwrite(ptr,size,nmemb,(FILE*)fp);
returnwritten;
intmain(intargc,char*argv[])
CURL*curl;
curl_global_init(CURL_GLOBAL_ALL);
curl=curl_easy_init();
if((fp=fopen(argv[2],"w"))==NULL)
////CURLOPT_WRITEFUNCTION将后继的动作交给write_data函数处理
curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,write_data);
curl_easy_perform(curl);
exit(0);
3.3进度条实例显示文件下载进度
//采用CURLOPT_NOPROGRESS,CURLOPT_PROGRESSFUNCTIONCURLOPT_PROGRESSDATA实现文件传输进度提示功能
//函数采用了gtk库,故编译时需指定gtk库
//函数启动专门的线程用于显示gtk进度条bar
#include
#include
#include
GtkWidget*Bar;
////这个函数是为了符合CURLOPT_WRITEFUNCTION而构造的
size_tmy_write_func(void*ptr,size_tsize,size_tnmemb,FILE*stream)
returnfwrite(ptr,size,nmemb,stream);
//这个函数是为了符合CURLOPT_READFUNCTION而构造的
//数据上传时使用
size_tmy_read_func(void*ptr,size_tsize,size_tnmemb,FILE*stream)
returnfread(ptr,size,nmemb,stream);
//这个函数是为了符合CURLOPT_PROGRESSFUNCTION而构造的
//显示文件传输进度,t代表文件大小,d代表传输已经完成部分
intmy_progress_func(GtkWidget*bar,
doublet,/*dltotal*/
doubled,/*dlnow*/
doubleultotal,
doubleulnow)
/*printf("%d/%d(%g%%)/n",d,t,d*100.0/t);*/
gdk_threads_enter();
gtk_progress_set_value(GTK_PROGRESS(bar),d*100.0/t);
gdk_threads_leave();
void*my_thread(void*ptr)
CURLcoderes;
FILE*outfile;
gchar*url=ptr;
curl=curl_easy_init();
if(curl)
outfile=fopen("test.curl","w");
curl_easy_setopt(curl,CURLOPT_URL,url);
curl_easy_setopt(curl,CURLOPT_WRITEDATA,outfile);
curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,my_write_func);
curl_easy_setopt(curl,CURLOPT_READFUNCTION,my_read_func);
curl_easy_setopt(curl,CURLOPT_NOPROGRESS,0L);
curl_easy_setopt(curl,CURLOPT_PROGRESSFUNCTION,my_progress_func);
curl_easy_setopt(curl,CURLOPT_PROGRESSDATA,Bar);
res=curl_easy_perform(curl);
fclose(outfile);
/*alwayscleanup*/
returnNULL;
intmain(intargc,char**argv)
GtkWidget*Window,*Frame,*Frame2;
GtkAdjustment*adj;
/*Mustinitializelibcurlbeforeanythreadsarestarted*/
curl_global_init(CURL_GLOBAL_ALL);
/*Initthread*/
g_thread_init(NULL);
gtk_init(&argc,&argv);
Window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
Frame=gtk_frame_new(NULL);
gtk_frame_set_shadow_type(GTK_FRAME(Frame),GTK_SHADOW_OUT);
gtk_container_add(GTK_CONTAINER(Window),Frame);
Frame2=gtk_frame_new(NULL);
gtk_frame_set_shadow_type(GTK_FRAME(Frame2),GTK_SHADOW_IN);
gtk_container_add(GTK_CONTAINER(Frame),Frame2);
gtk_container_set_border_width(GTK_CONTAINER(Frame2),5);
adj=(GtkAdjustment*)gtk_adjustment_new(0,0,100,0,0,0);
Bar=gtk_progress_bar_new_with_adjustment(adj);
gtk_container_add(GTK_CONTAINER(Frame2),Bar);
gtk_widget_show_all(Window);
if(!g_thread_create(&my_thread,argv[1],FALSE,NULL)!=0)
g_warning("can'tcreatethethread");
gdk_threads_enter();
gtk_main();
编译exportPKG_CONFIG_PATH=/usr/lib/pkgconfig/gccprogress.c–oprogress`pkg-config--libs–cflagsgtk+-2..0`-lcurl–lgthread-2.0
3.4断点续传实例
//采用CURLOPT_RESUME_FROM_LARGE实现文件断点续传功能
#include
#include
//这个函数为CURLOPT_HEADERFUNCTION参数构造
size_tgetcontentlengthfunc(void*ptr,size_tsize,size_tnmemb,void*stream){
intr;
longlen=0;
/*_snscanf()isWin32specific*/
//r=_snscanf(ptr,size*nmemb,"Content-Length:%ld/n",&len);
r=sscanf(ptr,"Content-Length:%ld/n",&len);
if(r)/*Microsoft:wedon'treadthespecs*/
*((long*)stream)=len;
returnsize*nmemb;
/*保存下载文件*/
size_twirtefunc(void*ptr,size_tsize,size_tnmemb,void*stream)
/*读取上传文件*/
size_treadfunc(void*ptr,size_tsize,size_tnmemb,void*stream)
FILE*f=stream;
size_tn;
if(ferror(f))
returnCURL_READFUNC_ABORT;
n=fread(ptr,size,nmemb,f)*size;
returnn;
//下载或者上传文件函数
intdownload(CURL*curlhandle,constchar*remotepath,constchar*localpath,
longtimeout,longtries)
FILE*f;
curl_off_tlocal_file_len=-1;
longfilesize=0;
CURLcoder=CURLE_GOT_NOTHING;
intc;
structstatfile_info;
intuse_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);
//curl_easy_setopt(curlhandle,CURLOPT_UPLOAD,1L);
curl_easy_setopt(curlhandle,CURLOPT_URL,remotepath);
curl_easy_setopt(curlhandle,CURLOPT_CONNECTTIMEOUT,timeout);//设置连接超时,单位秒
curl_easy_setopt(curlhandle,CURLOPT_HEADERFUNCTION,getcontentlengthfunc);
curl_easy_setopt(curlhandle,CURLOPT_HEADERDATA,&filesize);
//设置文件续传的位置给libcurl
curl_easy_setopt(curlhandle,CURLOPT_RESUME_FROM_LARGE,use_resumelocal_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);
curl_easy_setopt(curlhandle,CURLOPT_NOPROGRESS,1L);
curl_easy_setopt(curlhandle,CURLOPT_VERBOSE,1L);
r=curl_easy_perform(curlhandle);
fclose(f);
if(r==CURLE_OK)
return1;
else{
fprintf(stderr,"%s/n",curl_easy_strerror(r));
intmain(intc,char**argv){
CURL*curlhandle=NULL;
curlhandle=curl_easy_init();
curl_easy_cleanup(curlhandle);
curl_global_cleanup();
return0;
编译gccresume.c-oresume–lcurl
./resume
3.5LibCurl调试实例
//采用CURLOPT_DEBUGFUNCTION参数实现libcurl调试功能
structdata{
chartrace_ascii;/*1or0*/
};
static
voiddump(constchar*text,
FILE*stream,unsignedchar*ptr,size_tsize,
charnohex)
size_ti;
size_tc;
unsignedintwidth=0x10;
if(nohex)
/*withoutthehexoutput,wecanfitmoreonscreen*/
width=0x40;
fprintf(stream,"%s,%zdbytes(0x%zx)/n",text,size,size);
for(i=0;i fprintf(stream,"%04zx:",i); if(!nohex){ /*hexnotdisabled,showit*/ for(c=0;c if(i+c fprintf(stream,"%02x",ptr[i+c]); else fputs("",stream); for(c=0;(c /*checkfor0D0A;iffound,skippastandstartanewlineofoutput*/ if(nohex&&(i+c+1 i+=(c+2-width); break; fprintf(stream,"%c", (ptr[i+c]>=0x20)&&(ptr[i+c]<0x80)ptr[i+c]:'.'); /*checkagainfor0D0A,toavoidanextra/nifit'satwidth*/ if(nohex&&(i+c+2 i+=(c+3-width); fputc('/n',stream);/*newline*/ fflush(stream); intmy_trace(CURL*handle,curl_infotypetype, char*data,size_tsize, void*userp) structdata*config=(structdata*)userp; constchar*text; (void)handle;/*preventcompilerwarning*/ switch(type){ caseCURLINFO_TEXT: fprintf(stderr,"==Info:%s",data); default:/*incaseanewoneisintroducedtoshockus*/ caseCURLINFO_HEADER_OUT: text="=>Sendheader"; caseCURLINFO_DATA_OUT: text="=>Senddata"; caseCURLINFO_SSL_DATA_OUT: text="=>SendSSLdata"; caseCURLINFO_HEADER_IN: text="<=Recvheader"; caseCURLINFO_DATA_IN: text="<=Recvdata"; caseCURLINFO_SSL_DATA_IN: text="<=RecvSSLdata"; dump(text,stderr,(unsignedchar*)data,size,config->trace_ascii); intmain(void) structdataconfig; config.trace_ascii=1;/*enableasciitracing*/======================================================================= 最近我需要写点页面分析的东西,这些东西某些程度上类似搜索引擎的“爬虫->parser->存储”的过程。 一整天之后,我终于能用这东西抓下来页面,并且从html页面中分析出来一些信息了,但是想更进一步就变的异常困难。因为这个库功能太复杂了。这东西文档不详细,被人提及的也少。Libwww最近的Release5.3.2,发布于2000年12月20日。一个有这么多年历史的东西,竟然没多少开发者在讨论,非常不正常。 好吧,我也投降,libcurl没html解析功能,这没关系,我找别的办法好了...这么复杂的库,再好我也实在没办法忍受下去了,再说我需要的功能其实也真没Libwww那么复杂的。 写程序其实很容易迷失,你会看到一个似乎很完美,什么都能做的东西,一下子就喜欢上它,但是最后往往还是无福消受。往往是那些,不那么成熟,多少有点小毛病的库,组合在一起才是真正的解决方案。 libcurl的文档中有getinmemory.c这个例子,把下载的网页写入自己定义的一个memorystruct中,看了这个例子的做法,它需要自己照顾内存的开辟,特别是需要在curl_easy_perform的调用函数中释放已开辟的内存,很不利于函数的封装,而且应用于multihandle的时候,运行时会出莫名其妙的assert错误。因此改写了一下,将下载的内容放入stl的string中,这样根本不需要自己照顾内存的开辟和释放。源代码如下: #include usingnamespacestd;staticcharerrorBuffer[CURL_ERROR_SIZE];staticintwriter(char*,size_t,size_t,string*);staticboolinit(CURL*&,char*,string*); staticboolinit(CURL*&conn,char*url,string*p_buffer){CURLcodecode;conn=curl_easy_init();if(conn==NULL){fprintf(stderr,"FailedtocreateCURLconnection/n");exit(EXIT_FAILURE);}code=curl_easy_setopt(conn,CURLOPT_ERRORBUFFER,errorBuffer);if(code!=CURLE_OK){fprintf(stderr,"Failedtoseterrorbuffer[%d]/n",code);returnfalse;}code=curl_easy_setopt(conn,CURLOPT_URL,url);if(code!=CURLE_OK){fprintf(stderr,"FailedtosetURL[%s]/n",errorBuffer);returnfalse;}code=curl_easy_setopt(conn,CURLOPT_FOLLOWLOCATION,1);if(code!=CURLE_OK){fprintf(stderr,"Failedtosetredirectoption[%s]/n",errorBuffer);returnfalse;}code=curl_easy_setopt(conn,CURLOPT_WRITEFUNCTION,writer);if(code!=CURLE_OK){fprintf(stderr,"Failedtosetwriter[%s]/n",errorBuffer);returnfalse;}code=curl_easy_setopt(conn,CURLOPT_WRITEDATA,p_buffer);if(code!=CURLE_OK){fprintf(stderr,"Failedtosetwritedata[%s]/n",errorBuffer);returnfalse;}returntrue;} staticintwriter(char*data,size_tsize,size_tnmemb,string*writerData){unsignedlongsizes=size*nmemb;if(writerData==NULL)return0;writerData->append(data,sizes);returnsizes;} RFID,RFID仓储管理,RFID资产管理,RFID系统,RFID资产管理,RFID仓库管理,RFID珠宝,RFID生产线,RFID手持机,RFID读写器,RFID战备物资,UWB定位,RFID电子标签,RFID抗金属标签,RFID特种标签,广州睿丰德