簡體   English   中英

C 中的工作 curl_multi_perform() 示例

[英]Working curl_multi_perform() example in C

我花了幾個小時試圖弄清楚如何以一般方式實現 curl_multi_perform() 。 這個例子可以幫助其他人。

它基本上采用結構 object 並將所有 curl output 作為字符串放入其中。 然后,程序員可以獲取該字符串並進行他們喜歡的任何處理。 如果有人有任何改進等,我會很高興看到他們。

這是一個名為“multicurl.h”的 header 文件,其中包含一個結構和 function 原型。

#ifndef _MULTICURL_HEADER_H
#define _MULTICURL_HEADER_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>


// A data structure used to hold the result of the cURL request.
typedef struct{ 
    size_t size;
    char *memory;
} MemType;

// Function Prototypes
void *SetUpCurlHandle(char*,MemType*);
void *SetUpMultiCurlHandle();
void *PerformMultiCurl();

#endif

這是名為 multicurl.c 的源代碼文件,其中包含 function 定義。


#include "multicurl.h"

#define MAX_WAIT_MSECS 5*1000 /* Wait max. 5 seconds */

CURLM *mult_hnd = NULL;
int still_running = 0;

size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata){// cURL callback function [read in datastream to memory]
    // This prototype is defined by cURL, with an argument at the end for our data structure.
    // This function is repeatedly called by cURL until there is no more data in the data stream; *ptr.
    size_t realsize = size * nmemb;// The number of bytes in the datastream [there is no NULL char]

    MemType *mem = (MemType *)userdata;
    char *tmp = realloc(mem->memory, mem->size + realsize + 1);// We add 1 for the NULL char.

    if (tmp == NULL){
        printf("Not Enough Memory, realloc returned NULL.\n");
        exit(EXIT_FAILURE);
    }

    mem->memory = tmp;
    memcpy(&(mem->memory[mem->size]), ptr, realsize);// Starting at the last element copy in datastream
    mem->size += realsize;// The actual size is realsize + 1, however realsize gives us the location of the last element.
    mem->memory[mem->size] = 0;// The datastream doesn't include a NULL char, so we zeroize the last element.
    // We overwrite the NULL char {the zeroized element} on the next callback iteration, if any.

    return realsize;// cURL crosschecks the datastream with this return value.
}

void *SetUpCurlHandle(char *url, MemType *output){// Take in a URL and a struct pointer address, set up curl easy handle.
    CURL *hnd = NULL;
    output->memory = malloc(1);              // Initialize the memory component of the structure.
    output->size = 0;                        // Initialize the size component of the structure.

    // Initialize the cURL handle.
    hnd = curl_easy_init();

    if(hnd){

        // Setup the cURL options.
        curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
        curl_easy_setopt(hnd, CURLOPT_URL, url);// Set the request URL
        curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L);
        curl_easy_setopt(hnd, CURLOPT_USERAGENT, "curl/7.76.0");
        curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
        curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2TLS);
        curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
        curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
        curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, write_callback);// The callback function to write data to.
        curl_easy_setopt(hnd, CURLOPT_WRITEDATA, (void *)output);// Send the address of the data struct to callback func.
        //curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1);

        curl_multi_add_handle(mult_hnd, hnd);
    }else{
        output->memory[0] = '\0';
    }    
    return NULL;// The output struct was passed by reference no need to return anything.
}

void *SetUpMultiCurlHandle(){// set up curl multi handle
    curl_global_init(CURL_GLOBAL_ALL);

    mult_hnd = curl_multi_init();
    return NULL;
}

void *PerformMultiCurl(){// Request data from remote server asynchronously
    CURLMsg *msg=NULL;
    CURL *hnd = NULL;
    CURLcode return_code = 0;
    int msgs_left = 0;

    curl_multi_perform(mult_hnd, &still_running);
    do {
        int numfds=0;
        int res = curl_multi_wait(mult_hnd, NULL, 0, MAX_WAIT_MSECS, &numfds);
        if(res != CURLM_OK) {
            fprintf(stderr, "error: curl_multi_wait() returned %d\n", res);
            return NULL;
        }
        curl_multi_perform(mult_hnd, &still_running);
        /* if there are still transfers, loop! */
    } while(still_running);

    while ((msg = curl_multi_info_read(mult_hnd, &msgs_left))) {
        if (msg->msg == CURLMSG_DONE) {
            hnd = msg->easy_handle;

            return_code = msg->data.result;
            if(return_code!=CURLE_OK) {
                fprintf(stderr, "CURL error code: %d\n", msg->data.result);
                continue;
            }

            curl_multi_remove_handle(mult_hnd, hnd);
            curl_easy_cleanup(hnd);
            hnd = NULL;
        }
        else {
            fprintf(stderr, "error: after curl_multi_info_read(), CURLMsg=%d\n", msg->msg);
        }
    }

    curl_multi_cleanup(mult_hnd);
    curl_global_cleanup();
    return NULL;
}

這是名為 multicurlexample.c 的主要源代碼文件

//gcc -o multicurl -lcurl multicurlexample.c multicurl.c

#include "multicurl.h"

int main(){
    char* MyUrl1 = "https://api.weather.gov/stations/KBOS/observations/latest"; //Boston Weather
    char* MyUrl2 = "https://api.weather.gov/stations/KLGA/observations/latest"; //NYC Weather
    MemType MyOutputStruct1;
    MemType MyOutputStruct2;

    SetUpMultiCurlHandle();

    SetUpCurlHandle(MyUrl1, &MyOutputStruct1);
    SetUpCurlHandle(MyUrl2, &MyOutputStruct2);

    PerformMultiCurl();

    printf("Output:\n%s\n", MyOutputStruct1.memory);
    printf("Output:\n%s\n", MyOutputStruct2.memory);

    free( MyOutputStruct1.memory );
    free( MyOutputStruct2.memory );
    
    return 0;
}

這是上述示例的改進變體,使用提供的建議應該對線程更加友好。

一個名為“multicurl.h”的 header 文件


#ifndef _MULTICURL_HEADER_H
#define _MULTICURL_HEADER_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>


// A data structure used to hold the result of the cURL request.
typedef struct{ 
    size_t size;
    char *memory;
} MemType;

// Function Prototypes
void *SetUpCurlHandle(CURLM *, char *, MemType *);
CURLM *SetUpMultiCurlHandle();
void *PerformMultiCurl(CURLM*);

#endif

一個 c 源代碼文件,其中 function 定義稱為“multicurl.c”

#include "multicurl.h"

#define MAX_WAIT_MSECS 5*1000 /* Wait max. 5 seconds */

size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata){// cURL callback function [read in datastream to memory]
    // This prototype is defined by cURL, with an argument at the end for our data structure.
    // This function is repeatedly called by cURL until there is no more data in the data stream; *ptr.
    size_t realsize = size * nmemb;// The number of bytes in the datastream [there is no NULL char]

    MemType *mem = (MemType *)userdata;
    char *tmp = realloc(mem->memory, mem->size + realsize + 1);// We add 1 for the NULL char.

    if (tmp == NULL){
        printf("Not Enough Memory, realloc returned NULL.\n");
        exit(EXIT_FAILURE);
    }

    mem->memory = tmp;
    memcpy(&(mem->memory[mem->size]), ptr, realsize);// Starting at the last element copy in datastream
    mem->size += realsize;// The actual size is realsize + 1, however realsize gives us the location of the last element.
    mem->memory[mem->size] = 0;// The datastream doesn't include a NULL char, so we zeroize the last element.
    // We overwrite the NULL char {the zeroized element} on the next callback iteration, if any.

    return realsize;// cURL crosschecks the datastream with this return value.
}

void *SetUpCurlHandle(CURLM * mh, char *url, MemType *output){// Take in a multi handle pointer, a URL and a struct pointer address, add an easy handle to the multi handle.
    CURL *hnd = NULL;
    output->memory = malloc(1);              // Initialize the memory component of the structure.
    output->size = 0;                        // Initialize the size component of the structure.

    // Initialize the cURL handle.
    hnd = curl_easy_init();

    if(hnd){

        // Setup the cURL options.
        curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
        curl_easy_setopt(hnd, CURLOPT_URL, url);// Set the request URL
        curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L);
        curl_easy_setopt(hnd, CURLOPT_USERAGENT, "curl/7.76.0");
        curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
        curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2TLS);
        curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
        curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
        curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, write_callback);// The callback function to write data to.
        curl_easy_setopt(hnd, CURLOPT_WRITEDATA, (void *)output);// Send the address of the data struct to callback func.
        //curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1);

        curl_multi_add_handle(mh, hnd);
    }else{
        output->memory[0] = '\0';
    }    
    return NULL;// The output struct was passed by reference no need to return anything.
}

CURLM *SetUpMultiCurlHandle(){
    curl_global_init(CURL_GLOBAL_ALL);

    CURLM * mh = curl_multi_init();
    return mh;
}

void *PerformMultiCurl(CURLM * mh){// Take in a multi handle pointer and request data from remote server asynchronously
    CURLMsg *msg=NULL;
    CURL *hnd = NULL;
    CURLcode return_code = 0;
    int still_running = 0;
    int msgs_left = 0;

    curl_multi_perform(mh, &still_running);
    do {
        int numfds=0;
        int res = curl_multi_wait(mh, NULL, 0, MAX_WAIT_MSECS, &numfds);
        if(res != CURLM_OK) {
            fprintf(stderr, "error: curl_multi_wait() returned %d\n", res);
            return NULL;
        }
        curl_multi_perform(mh, &still_running);
        /* if there are still transfers, loop! */
    } while(still_running);
    
    /* This portion of the code will clean up and remove the handles from memory, you could change this to make them more persistent */
    while ((msg = curl_multi_info_read(mh, &msgs_left))) {
        if (msg->msg == CURLMSG_DONE) {
            hnd = msg->easy_handle;

            return_code = msg->data.result;
            if(return_code!=CURLE_OK) {
                fprintf(stderr, "CURL error code: %d\n", msg->data.result);
                continue;
            }

            curl_multi_remove_handle(mh, hnd);
            curl_easy_cleanup(hnd);
            hnd = NULL;
        }
        else {
            fprintf(stderr, "error: after curl_multi_info_read(), CURLMsg=%d\n", msg->msg);
        }
    }

    curl_multi_cleanup(mh);
    curl_global_cleanup();
    return NULL;
}

一個名為“multicurlexample.c”的主要 c 源代碼文件

//gcc -o multicurl -lcurl multicurlexample.c multicurl.c
#include "multicurl.h"

int main(){
    CURLM *mult_hnd = SetUpMultiCurlHandle();
    char* MyUrl1 = "https://api.weather.gov/stations/KBOS/observations/latest"; //Boston Weather
    char* MyUrl2 = "https://api.weather.gov/stations/KLGA/observations/latest"; //NYC Weather
    MemType MyOutputStruct1;
    MemType MyOutputStruct2;
    

    SetUpCurlHandle( mult_hnd, MyUrl1, &MyOutputStruct1 );
    SetUpCurlHandle( mult_hnd, MyUrl2, &MyOutputStruct2 );

    PerformMultiCurl( mult_hnd );

    printf("Output:\n%s\n", MyOutputStruct1.memory);
    printf("Output:\n%s\n", MyOutputStruct2.memory);

    free( MyOutputStruct1.memory );
    free( MyOutputStruct2.memory );
    
    return 0;
}

這是同一程序的實驗變體,它使用寬字符顯示 UTF-8。 到目前為止它似乎有效,但我不確定回調 function 是否總是適用於所有 UTF-8 數據流[數據流是否總是可以被 wchar_t 的大小整除?]。

//gcc -o multicurl -lcurl multicurlexample.c multicurl.c

#include "multicurl.h"

int main(){
    setlocale(LC_ALL, "");

    CURLM *mult_hnd = SetUpMultiCurlHandle();

    wchar_t* MyUrl1 = L"https://api.weather.gov/stations/KBOS/observations/latest"; //Boston Weather
    wchar_t* MyUrl2 = L"https://api.weather.gov/stations/KLGA/observations/latest"; //NYC Weather
    MemType MyOutputStruct1;
    MemType MyOutputStruct2;
    
    SetUpCurlHandle( mult_hnd, MyUrl1, &MyOutputStruct1 );
    SetUpCurlHandle( mult_hnd, MyUrl2, &MyOutputStruct2 );

    PerformMultiCurl( mult_hnd );

    wprintf(L"Output:\n%s\n", MyOutputStruct1.memory);
    wprintf(L"Output:\n%s\n", MyOutputStruct2.memory);

    free( MyOutputStruct1.memory );
    free( MyOutputStruct2.memory );
    return 0;
}
#ifndef MULTICURL_HEADER_H
#define MULTICURL_HEADER_H

#include <stdio.h>
#include <stdlib.h>

#include <locale.h>
#include <wchar.h>

#include <string.h>
#include <curl/curl.h>


// A data structure to hold the result of the cURL request.
typedef struct{ 
    size_t size; // The size of the string in bytes [this is not the number of characters when using UTF-8].
    wchar_t *memory;
} MemType;

// Function Prototypes
void *SetUpCurlHandle(CURLM *, wchar_t *, MemType *);
CURLM *SetUpMultiCurlHandle();
void *PerformMultiCurl(CURLM*);

#endif
#include "multicurl.h"

#define MAX_WAIT_MSECS 5*1000 /* Wait max. 5 seconds */

/*  The largest difference between the ASCII and UTF-8 variations of this program is that this callback function is now dealing with an array of wchar_t blocks rather than chars which are always 1 byte long, but it still works the same basic way. */
static size_t write_callback(wchar_t *ptr, size_t size, size_t nmemb, void *userdata){// cURL callback function [read in datastream to memory]
    // This prototype is provided by cURL, with an argument at the end for our data structure.
    // This function is repeatedly called by cURL until there is no more data in the data stream; *ptr [it is assumed cURL handles memory management for this pointer].
    
    size_t realsize = nmemb * size;// The number of bytes in the datastream [there is no NULL char]
    MemType *mem = (MemType *)userdata;
    wchar_t *tmp = realloc(mem->memory, mem->size  + realsize + sizeof(wchar_t) );// We add 1 wchar_t unit for the NULL character.

    if (tmp == NULL){
        printf("Not Enough Memory, realloc returned NULL.\n");
        exit(EXIT_FAILURE);
    }

    mem->memory = tmp;
    memcpy(&(mem->memory[ mem->size /  sizeof(wchar_t) ]), ptr, realsize );// Starting at the last element copy in datastream [it overwrites the last element]
    mem->size += realsize;// The actual size, in bytes, is realsize + ( 1 * sizeof(wchar_t) ), however realsize gives us the location of the last element.
    mem->memory[ mem->size / sizeof(wchar_t) ] = 0;// The datastream doesn't include a NULL character, so we zeroize the last element.
    // We overwrite the NULL character {the zeroized element} on the next callback iteration, if any.

    return (size * nmemb);// cURL crosschecks the datastream with this return value.
}

void *SetUpCurlHandle(CURLM * mh, wchar_t *utf8_url, MemType *output){
// Take in a multi handle pointer address, a URL and a struct pointer address, set up the curl easy handle and add it to the multi handle.

    /* Convert our UTF-8 URL string to a regular ASCII URL string. */
    char* url = (char*) malloc ( wcslen( utf8_url ) + 1 );
    wcstombs(url, utf8_url, wcslen( utf8_url ) * sizeof( wchar_t ) );

    CURL *hnd = NULL;
    output->memory = malloc( sizeof( wchar_t ) );              // Initialize the memory component of the structure.
    output->size = 0;                                           // Initialize the size component of the structure.

    // Initialize the cURL handle.
    hnd = curl_easy_init();

    if(hnd){

        // Setup the cURL options.
        curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
        curl_easy_setopt(hnd, CURLOPT_URL, url);// Set the request URL
        curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L);
        curl_easy_setopt(hnd, CURLOPT_USERAGENT, "curl/7.80.0");
        curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
        curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2TLS);
        curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
        curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
        curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, write_callback);// The callback function to write data to.
        curl_easy_setopt(hnd, CURLOPT_WRITEDATA, (void *)output);// Send the address of the data struct to callback func.
        //curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1);

        curl_multi_add_handle(mh, hnd);
    }else{
        output->memory[0] = '\0';
    }    
    return NULL;// The output struct was passed by reference no need to return anything.
}

CURLM *SetUpMultiCurlHandle(){
    curl_global_init(CURL_GLOBAL_ALL);

    CURLM * mh = curl_multi_init();
    return mh;
}

void *PerformMultiCurl(CURLM * mh) 
/*Take in a preset multi handle, request data from the remote server asynchronously {it's assumed cURL is using threads transparent to the calling program}.
   Remove the handles from memory.*/
{
    CURLMsg *msg=NULL;
    CURL *hnd = NULL;
    CURLcode return_code = 0;
    int still_running = 0;
    int msgs_left = 0;

    curl_multi_perform(mh, &still_running);// Perform the requests.
    do {
        int numfds=0;
        int res = curl_multi_wait(mh, NULL, 0, MAX_WAIT_MSECS, &numfds);
        if(res != CURLM_OK) {
            fprintf(stderr, "error: curl_multi_wait() returned %d\n", res);
            return NULL;
        }
        curl_multi_perform(mh, &still_running);
        
       /* Without this loop the program will proceed to the next statement, most likely before the messages are retrieved from the server.
           The easy handle requests are conducted asynchronously, but one multi handle request is obviously conducted sequentially (can use pthreads to make asynchronous multi requests).*/
    } while(still_running); 
    
    
    /* This portion of the code will clean up and remove the handles from memory, you could change this to make them more persistent */
    while ((msg = curl_multi_info_read(mh, &msgs_left))) {
        if (msg->msg == CURLMSG_DONE) {
            hnd = msg->easy_handle;

            return_code = msg->data.result;
            if(return_code!=CURLE_OK) {
                fprintf(stderr, "CURL error code: %d\n", msg->data.result);
                continue;
            }

            curl_multi_remove_handle(mh, hnd);
            curl_easy_cleanup(hnd);
            hnd = NULL;
        }
        else {
            fprintf(stderr, "error: after curl_multi_info_read(), CURLMsg=%d\n", msg->msg);
        }
    }

    curl_multi_cleanup(mh);
    curl_global_cleanup();
    return NULL;
}

這是相同的程序,用於處理 UTF-8。

//gcc -o multicurl -lcurl multicurlexample.c multicurl.c
#include "multicurl.h"

wchar_t* parse_UTF8_bitstream( size_t *len, const char *input_stream )
/* Parse a UTF-8 char bytestream into a 4-byte wide wchar_t bytestream [so we can address each UTF-8 character individually] 
    This parser does not do error checking.  If it receives invalid UTF-8 code, the result is undefined. */
{
    *len = 0; /* This will give us the number of wide-characters not counting NULL. */
    int i = 0; /* This iterates through the mb char stream. */
    size_t wc_size = sizeof( wchar_t ); /* The size of our destination datatype. */
    wchar_t *output = ( wchar_t* ) malloc ( sizeof( wchar_t ) );
    wchar_t *temp;
    while ( input_stream[ i ] ){
        temp = ( wchar_t* ) realloc(output, (*len + 1) * sizeof( wchar_t ) );
        output = temp;
        /* i skips this many chars to the next UTF-8 code.*/
        i += mbtowc( &output[ *len ], &input_stream[ i ], wc_size );
        *len = *len + 1;
    }
    
    /* Make sure the last wide-character is NULL */
    temp = ( wchar_t* ) realloc(output, (*len + 1) * sizeof( wchar_t ) );
    output = temp;
    output[ *len ] = 0;
    
    return output; /* This is our wide character string. */
}

int main(){
    /* Notice that we had to set the locale here. */
    setlocale(LC_ALL, "");
    
    CURLM *mult_hnd = SetUpMultiCurlHandle();

    char* MyUrl1 = "https://api.weather.gov/stations/KBOS/observations/latest"; //Boston Weather
    char* MyUrl2 = "https://api.weather.gov/stations/KLGA/observations/latest"; //NYC Weather
    MemType MyOutputStruct1;
    MemType MyOutputStruct2;
    

    SetUpCurlHandle( mult_hnd, MyUrl1, &MyOutputStruct1 );
    SetUpCurlHandle( mult_hnd, MyUrl2, &MyOutputStruct2 );

    PerformMultiCurl( mult_hnd );
    
    /* If you do not need to address individual characters in UTF-8 or if you are only using the ASCII 
        subset of UTF-8, parsing the result like this isn't necessary. */
        
    /* Parse the result into wide characters so we can address each UTF-8 character individually. */
    size_t len1;
    wchar_t* outputstream1 = parse_UTF8_bitstream( &len1, MyOutputStruct1.memory);
    
    size_t len2;
    wchar_t* outputstream2 = parse_UTF8_bitstream( &len2, MyOutputStruct2.memory);

    printf("Output:\n%ls\n", outputstream1);
    printf("Output:\n%ls\n", outputstream2);

    free( MyOutputStruct1.memory );
    free( MyOutputStruct2.memory );
    
    free( outputstream1 );
    free( outputstream2 );

    return 0;
}
#ifndef MULTICURL_HEADER_H
#define MULTICURL_HEADER_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>

#include <locale.h>


// A data structure to hold the result of the cURL request.
typedef struct{ 
    size_t size;
    char *memory;
} MemType;

// Function Prototypes
void *SetUpCurlHandle(CURLM *, char *, MemType *);
CURLM *SetUpMultiCurlHandle();
void *PerformMultiCurl(CURLM*);

#endif
#include "multicurl.h"

#define MAX_WAIT_MSECS 5*1000 /* Wait max. 5 seconds */

static size_t write_callback(void *ptr, size_t size, size_t nmemb, void *userdata){// cURL callback function [read in datastream to memory]
    // This prototype is provided by cURL, with an argument at the end for our data structure.
    // This function is repeatedly called by cURL until there is no more data in the data stream; *ptr [it is assumed cURL handles memory management for this pointer].
    size_t realsize = size * nmemb;// The number of bytes in the datastream [there is no NULL char]

    MemType *mem = (MemType *)userdata;
    char *tmp = realloc(mem->memory, mem->size + realsize + 1);// We add 1 for the NULL char.

    if (tmp == NULL){
        printf("Not Enough Memory, realloc returned NULL.\n");
        exit(EXIT_FAILURE);
    }

    mem->memory = tmp;
    memcpy(&(mem->memory[mem->size]), ptr, realsize);// Starting at the last element copy in datastream [it overwrites the last element]
    mem->size += realsize;// The actual size is realsize + 1, however realsize gives us the location of the last element.
    mem->memory[mem->size] = 0;// The datastream doesn't include a NULL char, so we zeroize the last element.
    // We overwrite the NULL char {the zeroized element} on the next callback iteration, if any.

    return realsize;// cURL crosschecks the datastream with this return value.
}

void *SetUpCurlHandle(CURLM * mh, char *url, MemType *output){
// Take in a multi handle pointer address, a URL and a struct pointer address, set up the curl easy handle and add it to the multi handle.
    CURL *hnd = NULL;
    output->memory = malloc(1);              // Initialize the memory component of the structure.
    output->size = 0;                        // Initialize the size component of the structure.

    // Initialize the cURL handle.
    hnd = curl_easy_init();

    if(hnd){

        // Setup the cURL options.
        curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
        curl_easy_setopt(hnd, CURLOPT_URL, url);// Set the request URL
        curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L);
        curl_easy_setopt(hnd, CURLOPT_USERAGENT, "curl/7.80.0");
        curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
        curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2TLS);
        curl_easy_setopt(hnd, CURLOPT_FTP_SKIP_PASV_IP, 1L);
        curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
        curl_easy_setopt(hnd, CURLOPT_WRITEFUNCTION, write_callback);// The callback function to write data to.
        curl_easy_setopt(hnd, CURLOPT_WRITEDATA, (void *)output);// Send the address of the data struct to callback func.
        //curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1);

        curl_multi_add_handle(mh, hnd);
    }else{
        output->memory[0] = '\0';
    }    
    return NULL;// The output struct was passed by reference no need to return anything.
}

CURLM *SetUpMultiCurlHandle(){
    curl_global_init(CURL_GLOBAL_ALL);

    CURLM * mh = curl_multi_init();
    return mh;
}

void *PerformMultiCurl(CURLM * mh) 
/*Take in a preset multi handle, request data from the remote server asynchronously {it's assumed cURL is using threads transparent to the calling program}.
   Remove the handles from memory.*/
{
    CURLMsg *msg=NULL;
    CURL *hnd = NULL;
    CURLcode return_code = 0;
    int still_running = 0;
    int msgs_left = 0;

    curl_multi_perform(mh, &still_running);// Perform the requests.
    do {
        int numfds=0;
        int res = curl_multi_wait(mh, NULL, 0, MAX_WAIT_MSECS, &numfds);
        if(res != CURLM_OK) {
            fprintf(stderr, "error: curl_multi_wait() returned %d\n", res);
            return NULL;
        }
        curl_multi_perform(mh, &still_running);
        
       /* Without this loop the program will proceed to the next statement, most likely before the messages are retrieved from the server.
           The easy handle requests are conducted asynchronously, but one multi handle request is obviously conducted sequentially (can use pthreads to make asynchronous multi requests).*/
    } while(still_running); 
    
    
    /* This portion of the code will clean up and remove the handles from memory, you could change this to make them more persistent */
    while ((msg = curl_multi_info_read(mh, &msgs_left))) {
        if (msg->msg == CURLMSG_DONE) {
            hnd = msg->easy_handle;

            return_code = msg->data.result;
            if(return_code!=CURLE_OK) {
                fprintf(stderr, "CURL error code: %d\n", msg->data.result);
                continue;
            }

            curl_multi_remove_handle(mh, hnd);
            curl_easy_cleanup(hnd);
            hnd = NULL;
        }
        else {
            fprintf(stderr, "error: after curl_multi_info_read(), CURLMsg=%d\n", msg->msg);
        }
    }

    curl_multi_cleanup(mh);
    curl_global_cleanup();
    return NULL;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM