2012-05-04 17 views
0
  1. インターネットの障害により失敗したダウンロードを再開しようとしています。私はカールダウンロードの成功を確認するために使用しています機能は次のとおりです。Curl C APIを使用してダウンロードを再開しません。

    curl_multi_info_read 
    

    この機能は、それがインターネットが失われたのは今回が初めてと呼ばれ、適切なエラーコード(CURLE_COULDNT_CONNECT)を返します。もう一度呼び出そうとすると、NULLポインタが返され、メッセージがないことを意味します。実際には、私はインターネット接続が存在するかどうかを確認するために、戻りエラーコードを使用しています。インターネットがない場合、2回目の呼び出しでエラーコードを返さないので、これは私を困惑させています。このエラーコード(CURLE_COULDNT_CONNECT)は、インターネットの状態をチェックする際に非常に重要であり、したがって接続を取り戻したときにどこからダウンロードを再開するために、この関数を使用して戻りコードをチェックする方法を教えてください....ダウンロードを再開するために

  2. 私は、インターネット接続があるときにダウンロードが再開できるように、私はオプション私は失われたインターネット接続を取得するたびに設定するには、この関数を呼び出しています

    curl_easy_setopt (curl, CURLOPT_RESUME_FROM, InternalOffset); 
    

    を使用していますバック...

libcurlの7.21.6
  • プラットフォーム - - のLinux(Ubuntuの)
    • カールバージョン:Daniel Stenbergへの

      注:ここでは

      は、プラットフォームとlibcurlのバージョンに関するいくつかの詳細です

      コメント:

      1. はい。あなたの意見は正しい。私はスタックから簡単なハンドルを削除し、新しいオプション(curl_easy_setopt(curl, CURLOPT_RESUME_FROM, InternalOffset))を設定してマルチハンドルに再度追加し、最後に複数の機能を実行しました。彼らはインターネット接続がない場合、それは適切なエラーを返しました。私の質問です:私は適切なエラーを得るためにインターネット接続を失ったときに上記の手順を繰り返す必要がありますか?これらの手順を実行しないと、curl_multi_info_read関数は常にNULLを返します。

      2. 私が作ったもう一つの観察は、インターネット接続が復帰したときと同じようにダウンロードの再開です。以前に停止した場所からダウンロードが開始されます。これは私にとって驚くべきことです。カールは、インターネットに戻ったときにダウンロードを再開することを内部的に担当しています。もしこれが正しい?本当にダウンロードを再開したり、適切に処理するようにカールしておく必要がありますか?

    +0

    1.あなたは、接続の損失を被るした後、新しいネットワークアドレスを取得する場合、あなたのカールハンドルは無用になります。それを削除する必要があります。しかし、私はあなたがそれを再利用できるはずだと思います。 – violet313

    +0

    2.はい。これは正しい動作です。そのため、あなたは 'InternalOffset'を提供しています〜部分的なGET要求には、サーバーにどこから再開するかを示すRangeヘッダーフィールドが含まれています。 *私の例のように*あなたはそれをカールに残すことができます。 – violet313

    +0

    btw、明白なことを言う危険があるので、あなたが再接続するたびにcurl_easy_setopt(curl、CURLOPT_RESUME_FROM、InternalOffset);を呼び出す必要があります。そうしないと毎回同じInternalOffsetからd/lが再開されます。 – violet313

    答えて

    3

    もっと情報を提供する必要があります。

    例:あなたは明示的にあなたがなどを使用しているものlibcurl &に取り組んでいるものプラットフォーム言及多分& ..あなたがmulti interfaceeasy interfaceを使用しているかどうかを言うことはありません。以下は

    libcurl/7.21.6に対する最小限カールeasymultiテストです。
    私は喜んでネットワークケーブルを外して、httpサーバ&を停止しました〜それは大丈夫に対処するようです。

    これらはあなたを助けるかもしれない:

    curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, dl_lowspeed_bytes); //bytes/sec 
    curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, dl_lowspeed_time); //seconds 
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); 
    


    NB:あなたがに非常に努力する必要があり、接続がドロップアウト時にオーバーcurl秋を作ります。これは設計によるものです。いくつかの人にとっては驚きです。


    私はあなたがCURLOPT_TIMEOUTを使用したいと思わないと思います。これにより転送がタイムアウトになります。あなたのd/lが大きければ、あなたのネットワーク接続に何かがあるかどうかを知るために待つ準備ができているよりも、時間がかかります。対照的に、CURLOPT_LOW_SPEED_TIMEのタイムアウトは、経過した転送時間のさらに多くの時間であっても、決してヒットしないことがあります。


    curltest_easy.c:

    /*---------------------------------------------------- 
    curltest_easy.c 
    WARNING: for test purposes only ~ 
    */ 
    #include <stdio.h> 
    #include <unistd.h> 
    #include <curl/curl.h> 
    #include <curl/types.h> 
    #include <curl/easy.h> 
    #include <sys/stat.h> 
    
    
    
    static int dl_progress(void *clientp,double dltotal,double dlnow,double ultotal,double ulnow) 
    { 
        if (dlnow && dltotal) 
         printf("dl:%3.0f%%\r",100*dlnow/dltotal); //shenzi prog-mon 
        fflush(stdout);  
        return 0; 
    } 
    
    static size_t dl_write(void *buffer, size_t size, size_t nmemb, void *stream) 
    {  
        return fwrite(buffer, size, nmemb, (FILE*)stream); 
    } 
    
    
    int do_dl(void) 
    { 
        CURL *curl; 
        FILE *fp; 
        CURLcode curl_retval; 
        long http_response; 
        double dl_size; 
        int retval=0; 
        long dl_lowspeed_bytes=1000; //1K 
        long dl_lowspeed_time=10; //sec   
        /*put something biG here, preferably on a server that you can switch off at will ;) */ 
        char url[] = {"http://fc00.deviantart.net/fs26/f/2008/134/1/a/Dragon_VII_by_NegativeFeedback.swf"}; 
        char filename[]={"blah.dl"}; 
    
        struct stat st={0};  
        if (!stat(filename, &st));  
        printf("st.st_size:[%ld]\n", st.st_size); 
    
    
        if(!(fp=fopen(filename, "ab"))) /*append binary*/ 
         return 1; 
    
    
        curl_global_init(CURL_GLOBAL_DEFAULT); 
        curl = curl_easy_init(); 
    
        if (curl) 
        { 
         //http://linux.die.net/man/3/curl_easy_setopt 
         curl_easy_setopt(curl, CURLOPT_URL, url); 
    
         /*callbacks*/ 
         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, dl_write); 
         curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, dl_progress); 
         curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0); 
    
         /*curl will keep running -so you have the freedom to recover 
         from network disconnects etc in your own way without 
         distrubing the curl task in hand. ** this is by design :p ** */ 
         //curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60);   
         //curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30); 
         /*set up min download speed threshold & time endured before aborting*/ 
         curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, dl_lowspeed_bytes); //bytes/sec 
         curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, dl_lowspeed_time); //seconds while below low spped limit before aborting 
    
    
         curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); 
         curl_easy_setopt(curl, CURLOPT_RESUME_FROM,st.st_size); 
    
         /*uncomment this to get curl to tell you what its up to*/ 
         //curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); 
    
    
         if(CURLE_OK != (curl_retval=curl_easy_perform(curl))) 
         {      
          printf("curl_retval:[%d]\n", curl_retval); 
          switch(curl_retval) 
          { 
           //Transferred a partial file 
           case CURLE_WRITE_ERROR: //can be due to a dropped connection 
           break; 
    
           //all defined in curl/curl.h 
    
           default: //suggest quitting on unhandled error 
           retval=0; 
          };  
    
    
          curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &dl_size); 
          printf("CURLINFO_CONTENT_LENGTH_DOWNLOAD:%f\n", dl_size); 
    
    
          curl_retval=curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_response); 
    
          //see: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 
          printf("CURLINFO_RESPONSE_CODE:%ld\n", http_response); 
    
          switch(http_response) 
          { 
          case 0: //eg connection down from kick-off ~suggest retrying till some max limit 
          break; 
    
          case 200: //yay we at least got to our url 
          break; 
    
          case 206: 
          case 416: //http://www.checkupdown.com/status/E416.html 
          printf("ouch! you might want to handle this & others\n"); 
    
          default: //suggest quitting on an unhandled error 
          retval=0; 
          };    
         } 
         else 
         { 
          printf("our work here is done ;)\n"); 
          retval=2; 
         } 
    
    
         if (fp) 
          fclose(fp); 
    
         if (curl) 
          curl_easy_cleanup(curl); 
        } 
    
        printf("retval [%d]\n", retval); 
        return retval; 
    } 
    
    
    int main(void) 
    { 
        while (!do_dl()) 
        { 
         usleep(5000); 
        } 
    
        return 0; 
    } 
    
    /* notes ---- 
    
    $sudo apt-get install libcurl4-gnutls-dev 
    $ curl-config --libs 
    -L/usr/lib/i386-linux-gnu -lcurl -Wl,-Bsymbolic-functions 
    
    #oook. lets do it: 
    $ gcc -o curltest_easy curltest_easy.c -L/usr/lib/i386-linux-gnu -lcurl -Wl,-Bsymbolic-functions 
    $ ./curltest 
    */ 
    



    curltest_multi.c:

    /*---------------------------------------------------- 
    curltest_mult1.c 
    WARNING: for test purposes only ~ 
    */ 
    #include <stdio.h> 
    #include <unistd.h> 
    #include <curl/curl.h> 
    #include <curl/types.h> 
    #include <curl/easy.h> 
    #include <sys/stat.h> 
    
    typedef struct S_dl_byte_data 
    { 
        double new_bytes_received; //from the latest request 
        double existing_filesize; 
    } dl_byte_data, *pdl_byte_data; 
    
    static int dl_progress(pdl_byte_data pdata,double dltotal,double dlnow,double ultotal,double ulnow) 
    { 
        /*dltotal := hacky way of getting the Content-Length ~ less hacky would be to first 
        do a HEAD request & then curl_easy_getinfo with CURLINFO_CONTENT_LENGTH_DOWNLOAD*/ 
        if (dltotal && dlnow) 
        { 
         pdata->new_bytes_received=dlnow; 
         dltotal+=pdata->existing_filesize; 
         dlnow+=pdata->existing_filesize; 
         printf(" dl:%3.0f%% total:%.0f received:%.0f\r",100*dlnow/dltotal, dltotal, dlnow); //shenzi prog-mon 
         fflush(stdout); 
        } 
        return 0; 
    } 
    
    static size_t dl_write(void *buffer, size_t size, size_t nmemb, void *stream) 
    { 
        return fwrite(buffer, size, nmemb, (FILE*)stream); 
    } 
    
    //////////////////////// 
    int do_dl(void) 
    { 
        CURLM *multi_handle; 
        CURL *curl; 
        FILE *fp; 
        CURLcode curl_retval; 
        int retval=0; 
        int handle_count=0; 
        double dl_bytes_remaining, dl_bytes_received; 
        dl_byte_data st_dldata={0}; 
        char curl_error_buf[CURL_ERROR_SIZE]={"meh"}; 
        long dl_lowspeed_bytes=1000, dl_lowspeed_time=10; /* 1KBs for 10 secs*/ 
    
        /*put something biG here, preferably on a server that you can switch off at will ;) */ 
        char url[] = {"http://fc00.deviantart.net/fs26/f/2008/134/1/a/Dragon_VII_by_NegativeFeedback.swf"}; 
    
        char outfilename[]={"blah.swf"}, filename[]={"blah.dl"}; 
        struct stat st={0}; 
    
    
        if (!(fp=fopen(filename, "ab")) || -1==fstat(fileno(fp), &st)) //append binary 
         return -1; 
    
        if (curl_global_init(CURL_GLOBAL_DEFAULT)) 
         return -2; 
    
        if (!(multi_handle = curl_multi_init())) 
         return -3; 
    
        if (!(curl = curl_easy_init())) 
         return -4; 
    
    
        st_dldata.new_bytes_received=st_dldata.existing_filesize=st.st_size; 
    
        //http://curl.haxx.se/libcurl/c/curl_easy_setopt.html 
        curl_easy_setopt(curl, CURLOPT_URL, url); 
    
        /*callbacks*/ 
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, dl_write); 
        curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, dl_progress); 
        curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &st_dldata); 
        curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0); 
    
        /*curl will keep running -so you have the freedom to recover from network disconnects etc 
        in your own way without distrubing the curl task in hand. ** this is by design :p ** 
        The follwoing sets up min download speed threshold & time endured before aborting*/ 
        curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, dl_lowspeed_bytes); //bytes/sec 
        curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, dl_lowspeed_time); //seconds while below low spped limit before aborting 
        //alternatively these are available in libcurl 7.25 
        //curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE,1L); 
        //curl_easy_setopt(curl, CURLOPT_TCP_KEEPIDLE,10); 
        //curl_easy_setopt(curl, CURLOPT_TCP_KEEPINTVL,10); 
    
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); 
    
        /*uncomment this to get curl to tell you what its up to*/ 
        //curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); 
    
        curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_error_buf); 
    
    
        do 
        { 
         if (st_dldata.new_bytes_received) //set the new range for the partial transfer if we have previously received some bytes 
         { 
          printf("resuming d/l..\n"); 
          fflush(fp); 
          //get the new filesize & sanity check for file; on error quit outer do-loop & return to main 
          if (-1==(retval=fstat(fileno(fp), &st)) || !(st_dldata.existing_filesize=st.st_size)) break; 
          //see also: CURLOPT_RANGE for passing a string with our own X-Y range 
          curl_easy_setopt(curl, CURLOPT_RESUME_FROM, st.st_size); 
          st_dldata.new_bytes_received=0; 
         } 
         printf("\n\nbytes already received:[%.0f]\n", st_dldata.existing_filesize); 
    
         //re-use the curl handle again & again & again & again... lol 
         curl_multi_add_handle(multi_handle, curl); 
    
         do //curl_multi_perform event-loop 
         { 
          CURLMsg *pMsg; 
          int msgs_in_queue; 
    
          while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(multi_handle, &handle_count)); 
    
          //check for any mesages regardless of handle count 
          while(pMsg=curl_multi_info_read(multi_handle, &msgs_in_queue)) 
          { 
           long http_response; 
    
           printf("\nmsgs_in_queue:[%d]\n",msgs_in_queue); 
           if (CURLMSG_DONE != pMsg->msg) 
           { 
            fprintf(stderr,"CURLMSG_DONE != pMsg->msg:[%d]\n", pMsg->msg); 
           } 
           else 
           { 
            printf("pMsg->data.result:[%d] meaning:[%s]\n",pMsg->data.result,curl_easy_strerror(pMsg->data.result)); 
            if (CURLE_OK != pMsg->data.result) printf("curl_error_buf:[%s]\n", curl_error_buf); 
            switch(pMsg->data.result) 
            { 
            case CURLE_OK: /////////////////////////////////////////////////////////////////////////////////////// 
            printf("CURLE_OK: "); 
            curl_easy_getinfo(pMsg->easy_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &dl_bytes_remaining); 
            curl_easy_getinfo(pMsg->easy_handle, CURLINFO_SIZE_DOWNLOAD, &dl_bytes_received); 
            if (dl_bytes_remaining == dl_bytes_received) 
            { 
             printf("our work here is done ;)\n"); 
             rename(filename, outfilename); 
             retval=1; 
            } 
            else 
            { 
             printf("ouch! st_dldata.new_bytes_received[%f]\n",st_dldata.new_bytes_received); 
             printf("ouch! dl_bytes_received[%f] dl_bytes_remaining[%f]\n",dl_bytes_received,dl_bytes_remaining); 
             retval=dl_bytes_received < dl_bytes_remaining ? 0 : -5; 
            } 
            break; ///////////////////////////////////////////////////////////////////////////////////////////////// 
    
            case CURLE_COULDNT_CONNECT:  //no network connectivity ? 
            case CURLE_OPERATION_TIMEDOUT: //cos of CURLOPT_LOW_SPEED_TIME 
            case CURLE_COULDNT_RESOLVE_HOST: //host/DNS down ? 
            printf("CURMESSAGE switch handle_count:[%d]\n",handle_count); 
            break; //we'll keep trying 
    
            default://see: http://curl.haxx.se/libcurl/c/libcurl-errors.html 
            handle_count=0; 
            retval=-5; 
            }; 
    
    
            //see: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 
            curl_retval=curl_easy_getinfo(pMsg->easy_handle, CURLINFO_RESPONSE_CODE, &http_response); 
            printf("CURLINFO_RESPONSE_CODE HTTP:[%ld]\n", http_response); 
            switch(http_response) 
            { 
            case 0: //eg connection down from kick-off ~suggest retrying till some max limit 
            case 200: //yay we at least got to our url 
            case 206: //Partial Content 
            break; 
    
            case 416: 
            //cannot d/l range ~ either cos no server support 
            //or cos we're asking for an invalid range ~ie: we already d/ld the file 
            printf("HTTP416: either the d/l is already complete or the http server cannot d/l a range\n"); 
            retval=2; 
    
            default: //suggest quitting on an unhandled error 
            handle_count=0; 
            retval=-6; 
            }; 
           } 
          } 
    
          if (handle_count) //select on any active handles 
          { 
           fd_set fd_read={0}, fd_write={0}, fd_excep={0}; 
           struct timeval timeout={5,0}; 
           int select_retval; 
           int fd_max; 
    
           curl_multi_fdset(multi_handle, &fd_read, &fd_write, &fd_excep, &fd_max); 
           if (-1 == (select_retval=select(fd_max+1, &fd_read, &fd_write, &fd_excep, &timeout))) 
           { 
            //errno shall be set to indicate the error 
            fprintf(stderr, "yikes! select error :(\n"); 
            handle_count=0; 
            retval=-7; 
            break; 
           } 
           else{/*check whatever*/} 
          } 
    
         } while (handle_count); 
    
         curl_multi_remove_handle(multi_handle,curl); 
         printf("continue from here?"); 
         getchar();   
        } 
        while(retval==0); 
    
        curl_multi_cleanup(multi_handle); 
        curl_easy_cleanup(curl); 
        curl_global_cleanup(); 
        if (fp) fclose(fp); 
    
        return retval; 
    } 
    
    //////////////////////// 
    int main(void) 
    { 
        int retval; 
        printf("\n\ncurl_multi d/l test ~curl version:[%s]\n", curl_version()); 
        while (1!=(retval=do_dl())) 
        { 
         printf("retval [%d] continue?\n\n", retval); 
         printf("continue?"); 
         getchar(); 
        } 
        printf("\nend of test!\n\n", retval); 
        return retval; 
    } 
    
    /* notes ---- 
    
    $sudo apt-get install libcurl4-gnutls-dev 
    $curl-config --libs 
    -L/usr/lib/i386-linux-gnu -lcurl -Wl,-Bsymbolic-functions 
    
    #oook. lets do it: 
    $gcc -o curltest_multi curltest_multi.c -L/usr/lib/i386-linux-gnu -lcurl -Wl,-Bsymbolic-functions 
    $./curltest_multi 
    
    */ 
    

    のErm、あなたはブランドの新しいテストを開始する前に、blah.dlファイルを削除することを忘れないようにしたい場合があります。 progが故意にないので、あなたは、テストのために、事前に既存のファイルを切り捨てることができます。

    NB):あなたのコードはほとんど誤差(笑ハンドリングする必要があります〜あなたは多分*ちょうどCURLE_COULDNT_CONNECTに頼るべきではありません。このような何かのために。あなたのprogが厳密に個人的な使用のためであれば、おそらく少ない。


    [編集:]) 私はeasy_handle再利用を実証するcurtest_multi.cを更新しました。

    そしてthe documentaionからノート以下の引用文を実行します。シングル転送が完了すると

    を、簡単にハンドルがまだマルチスタックに追加 を残しています。 curl_multi_remove_handle(3)で簡単なハンドル を削除してから、 curl_easy_cleanup(3)で閉じるか、新しいオプションを設定してcurl_multi_add_handle(3)でもう一度 を追加して別の転送を開始する必要があります。このことができます

    希望;)

    +0

    親愛なる友人、これらの2つのオプション(CURLOPT_LOW_SPEED_LIMIT、CURLOPT_LOW_SPEED_TIME)は接続をチェックするのに適していますか?スピードに基づいて接続性を判断できないと感じています。 – vinay

    +1

    7.25.0で追加されました: 'CURLOPT_TCP_KEEPALIVE'' CURLOPT_TCP_KEEPIDLE'〜ですが、これを使用すると、ネットワークトラフィックのオーバーヘッドが発生します。あるいは、あなた自身の方法で 'ioctl'を使うことができます。 – violet313

    +0

    ' CURLOPT_LOW_SPEED_LIMIT、CURLOPT_LOW_SPEED_TIME'は完全に受け入れられます。 〜あなたが戻ってバイトを取得していない場合、それはあなたが問題があると仮定することは妥当です。あなたが何かを試す前にあなたがどれくらい長く待っているかを決めるのはあなた次第です。 keepalive ack要求を送信するように。あなたのデバイスをチェックするか、単に接続を落として、投票で再試行してください。 – violet313

    関連する問題