1. 提供代码 重点关注curl_escape API


#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include <curl/curl.h>

size_t getcontentlengthfunc(void *ptr, size_t size, size_t nmemb, void *stream)
{
    int r;
    long len = 0;

    r = sscanf(ptr, "Content-Length: %ld\n", &len);
    printf("len: %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(stat(localpath, &file_info) == 0) {
        local_file_len =  file_info.st_size;
        use_resume  = 1;
    }

    f = fopen(localpath, "wb+");
    if (f == NULL) {
        perror(NULL);
        return 0;
    }

    //curl_easy_setopt(curlhandle, CURLOPT_UPLOAD, 1L);
    curl_easy_setopt(curlhandle, CURLOPT_URL, remotepath);
    curl_easy_setopt(curlhandle, CURLOPT_CONNECTTIMEOUT, timeout);  // 设置连接超时,单位秒
    //设置http 头部处理函数
    //curl_easy_setopt(curlhandle, CURLOPT_HEADERFUNCTION, getcontentlengthfunc);
    //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);
    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)
        return 1;

    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);
    curlhandle = curl_easy_init();

    char *name = "我和我";
    char *encode = curl_escape(name, strlen(name));
    char str[1024] = {0};
    snprintf(str, sizeof(str), "http://129.24.20.99:42/file/download?fileName=voiceLibrary/%s.mp3", encode);
    printf("str: %s\n", str);
    download(curlhandle, str,"./我和我.mp3",1,3);
    curl_easy_cleanup(curlhandle);
    curl_global_cleanup();

    return 0;
}

原本经过一些列的curl的API,并且通过抓包发现

 

 mp3的名字是没通过编码处理的,此时服务器返回FIN借以终结tcp连接,开始怀疑是tcp连接的问题,对比wget是一样的tcp链路。

 

2. 下文可以继续深入研究curl_escape 的具体实现。